diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..9bea2c99e --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +--- +BasedOnStyle: Google +# Google style has a default of 80 lines, but clang-format 7 disregards it in +# a weird case in modtrezorio-fatfs.h. Setting it explicitly helps. +ColumnLimit: 80 +# This setting differs between clang-format 7 and 9. +# Let's set it explicitly to v7 value +IncludeBlocks: Preserve +SortIncludes: false \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 3bdf70d95..869f7a53d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,7 @@ [submodule "deps/device-protocol"] path = deps/device-protocol url = https://github.com/keepkey/device-protocol.git + branch = master [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware url = https://github.com/keepkey/trezor-firmware.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 89d091329..81a321478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,12 +2,12 @@ cmake_minimum_required(VERSION 3.7.2) project(KeepKeyFirmware - VERSION 6.4.0 + VERSION 6.5.1 LANGUAGES C CXX ASM) set(BOOTLOADER_MAJOR_VERSION 2) -set(BOOTLOADER_MINOR_VERSION 0) +set(BOOTLOADER_MINOR_VERSION 1) set(BOOTLOADER_PATCH_VERSION 0) option(KK_EMULATOR "Build the emulator" OFF) diff --git a/deps/device-protocol b/deps/device-protocol index 552a527cd..5ce49feff 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 552a527cdb7b2ead07ba9d2024112a794ee55b32 +Subproject commit 5ce49feffa5b53401a2db3f3b232d988f018974d diff --git a/deps/python-keepkey b/deps/python-keepkey index 28ef3fbe8..20d25ec76 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit 28ef3fbe890b8feb6c94d9094b4532c9bcb363a2 +Subproject commit 20d25ec76571a8e99618ccdd3619e2aedb25067e diff --git a/docs/Storage.md b/docs/Storage.md index f35cb5e24..3cb2f7aff 100644 --- a/docs/Storage.md +++ b/docs/Storage.md @@ -105,7 +105,7 @@ it easier to extend for new features later on. | language | char[16] | 16 | 16 | | label | char[48] | 48 | 32 | | wrapped_storage_key | char[64] | 64 | 80 | -| storage_key_fingerprint | char[64] | 8 | 144 | +| storage_key_fingerprint | char[64] | 32 | 144 | | u2froot | StorageHDNode | 129 | 176 | | u2f_counter | u32 | 4 | 305 | | sec_fingerprint | char[32] | 32 | 309 | @@ -125,3 +125,60 @@ it easier to extend for new features later on. | root_seed_cache | char[64] | 64 | 371 | | root_ecdsa_curve_type | char[10] | 10 | 435 | | reserved | char[63] | 63 | 445 | + + +STORAGE_VERSION 16 layout +------------------------- + +#### Public(ish) Storage + +| Field | Type | Size (bytes) | Offset (bytes) | +| ------------------------- | -------------- | ------------ | -------------- | +| version | u32 | 4 | 0 | +| flags | u32 | 4 | 4 | +| has_pin | bit 0 | | | +| has_language | bit 1 | | | +| has_label | bit 2 | | | +| has_auto_lock_delay_ms | bit 3 | | | +| imported | bit 4 | | | +| passphrase_protection | bit 5 | | | +| ShapeShift policy | bit 6 | | | +| formerly: Pin Caching | bit 7 | | | +| has_node | bit 8 | | | +| has_mnemonic | bit 9 | | | +| has_u2froot | bit 10 | | | +| Experinemtal policy | bit 11 | | | +| AdvancedMode policy | bit 12 | | | +| no backup (seedless) | bit 13 | | | +| has_sec_fingerprint | bit 14 | | | +| sca_hardened | bit 15 | | | +| has_wipe_code | bit 16 | | | +| v15_16_trans | bit 17 | | | +| reserved | bits 18 - 31 | | | +| pin_failed_attempts | u32 | 4 | 8 | +| auto_lock_delay_ms | u32 | 4 | 12 | +| language | char[16] | 16 | 16 | +| label | char[48] | 48 | 32 | +| wrapped_storage_key | char[64] | 64 | 80 | +| storage_key_fingerprint | char[64] | 32 | 144 | +| wrapped_wipe_code_key | char[64] | 64 | 176 | +| wipe_code_key_fingerprint | char[64] | 32 | 240 | +| u2froot | StorageHDNode | 129 | 272 | +| u2f_counter | u32 | 4 | 401 | +| sec_fingerprint | char[32] | 32 | 405 | +| random_salt | char[32] | 32 | 437 | +| reserved | char[1028] | 1028 | 469 | +| encrypted_secrets_version | u32 | 4 | 1497 | +| encrypted_secrets | char[512] | 512 | 1501 | + + +#### Secret Storage + +| Field | Type | Size (bytes) | Offset (bytes) | +| ------------------------- | -------------- | ------------ | -------------- | +| node | StorageHDNode | 129 | 0 | +| mnemonic | char[241] | 241 | 129 | +| root_seed_cache_status | u8 | 1 | 370 | +| root_seed_cache | char[64] | 64 | 371 | +| root_ecdsa_curve_type | char[10] | 10 | 435 | +| reserved | char[63] | 63 | 445 | \ No newline at end of file diff --git a/fuzzer/firmware/eos_formatAsset.cpp b/fuzzer/firmware/eos_formatAsset.cpp index e4956a540..43667c6ca 100644 --- a/fuzzer/firmware/eos_formatAsset.cpp +++ b/fuzzer/firmware/eos_formatAsset.cpp @@ -6,18 +6,17 @@ extern "C" { #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size != 16) - return 0; + if (size != 16) return 0; - EosAsset asset; - asset.has_amount = true; - asset.amount = *(const uint64_t*)&data[0]; - asset.has_symbol = true; - asset.symbol = *(const uint64_t*)&data[8]; + EosAsset asset; + asset.has_amount = true; + asset.amount = *(const uint64_t *)&data[0]; + asset.has_symbol = true; + asset.symbol = *(const uint64_t *)&data[8]; - char str[EOS_ASSET_STR_SIZE]; - eos_formatAsset(&asset, str); - asm volatile("" : : "g"(str) : "memory"); + char str[EOS_ASSET_STR_SIZE]; + eos_formatAsset(&asset, str); + asm volatile("" : : "g"(str) : "memory"); - return 0; + return 0; } diff --git a/fuzzer/firmware/eos_formatName.cpp b/fuzzer/firmware/eos_formatName.cpp index b3d6d0d77..721ffaafb 100644 --- a/fuzzer/firmware/eos_formatName.cpp +++ b/fuzzer/firmware/eos_formatName.cpp @@ -5,12 +5,11 @@ extern "C" { #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size != 4) - return 0; + if (size != 4) return 0; - char str[EOS_NAME_STR_SIZE]; - eos_formatName(*(const uint32_t*)data, str); - asm volatile("" : : "g"(str) : "memory"); + char str[EOS_NAME_STR_SIZE]; + eos_formatName(*(const uint32_t *)data, str); + asm volatile("" : : "g"(str) : "memory"); - return 0; + return 0; } diff --git a/fuzzer/firmware/ripple_decode.cpp b/fuzzer/firmware/ripple_decode.cpp index d673c2b02..93664a2fa 100644 --- a/fuzzer/firmware/ripple_decode.cpp +++ b/fuzzer/firmware/ripple_decode.cpp @@ -6,31 +6,27 @@ extern "C" { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size != 33) - return 0; + if (size != 33) return 0; - uint8_t buff[64]; - memset(buff, 0, sizeof(buff)); + uint8_t buff[64]; + memset(buff, 0, sizeof(buff)); - Hasher hasher; - hasher_Init(&hasher, HASHER_SHA2_RIPEMD); - hasher_Update(&hasher, data, 33); - hasher_Final(&hasher, buff + 1); + Hasher hasher; + hasher_Init(&hasher, HASHER_SHA2_RIPEMD); + hasher_Update(&hasher, data, 33); + hasher_Final(&hasher, buff + 1); - char address[56]; - if (!ripple_encode_check(buff, 21, HASHER_SHA2D, - address, MAX_ADDR_SIZE)) - return 1; + char address[56]; + if (!ripple_encode_check(buff, 21, HASHER_SHA2D, address, MAX_ADDR_SIZE)) + return 1; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - memset(addr_raw, 0, sizeof(addr_raw)); - uint32_t addr_raw_len = ripple_decode_check(address, HASHER_SHA2D, - addr_raw, MAX_ADDR_RAW_SIZE); - if (addr_raw_len != 21) - return 2; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + memset(addr_raw, 0, sizeof(addr_raw)); + uint32_t addr_raw_len = + ripple_decode_check(address, HASHER_SHA2D, addr_raw, MAX_ADDR_RAW_SIZE); + if (addr_raw_len != 21) return 2; - if (memcmp(buff, addr_raw, 21) != 0) - return 3; + if (memcmp(buff, addr_raw, 21) != 0) return 3; - return 0; + return 0; } diff --git a/include/keepkey/board/canvas.h b/include/keepkey/board/canvas.h index bc84220d7..2065c4c79 100644 --- a/include/keepkey/board/canvas.h +++ b/include/keepkey/board/canvas.h @@ -20,18 +20,14 @@ #ifndef CANVAS_H #define CANVAS_H - #include #include - -typedef struct -{ - uint8_t* buffer; - uint16_t height; - uint16_t width; - bool dirty; +typedef struct { + uint8_t* buffer; + uint16_t height; + uint16_t width; + bool dirty; } Canvas; #endif - diff --git a/include/keepkey/board/check_bootloader.h b/include/keepkey/board/check_bootloader.h index 568c3cd1d..28e9cc504 100644 --- a/include/keepkey/board/check_bootloader.h +++ b/include/keepkey/board/check_bootloader.h @@ -38,22 +38,22 @@ extern char bl_hash_v1_0_4_unpatched[32]; extern char bl_hash_v1_1_0[32]; extern char bl_hash_v2_0_0[32]; - +extern char bl_hash_v2_1_0[32]; typedef enum _BootloaderKind { - BLK_UNKNOWN, - BLK_v1_0_0, - BLK_v1_0_1, - BLK_v1_0_2, - BLK_v1_0_3, - BLK_v1_0_3_sig, - BLK_v1_0_3_elf, - BLK_v1_0_4, - BLK_v1_1_0, - BLK_v2_0_0 + BLK_UNKNOWN, + BLK_v1_0_0, + BLK_v1_0_1, + BLK_v1_0_2, + BLK_v1_0_3, + BLK_v1_0_3_sig, + BLK_v1_0_3_elf, + BLK_v1_0_4, + BLK_v1_1_0, + BLK_v2_0_0, + BLK_v2_1_0 } BootloaderKind; BootloaderKind get_bootloaderKind(void); #endif - diff --git a/include/keepkey/board/confirm_sm.h b/include/keepkey/board/confirm_sm.h index 544dbc3ac..b370be46d 100644 --- a/include/keepkey/board/confirm_sm.h +++ b/include/keepkey/board/confirm_sm.h @@ -28,40 +28,31 @@ /* The number of milliseconds to wait for a confirmation */ #define CONFIRM_TIMEOUT_MS 1200 -typedef enum -{ - HOME, - CONFIRM_WAIT, - CONFIRMED, - FINISHED -} DisplayState; - -typedef enum -{ - LAYOUT_REQUEST, - LAYOUT_REQUEST_NO_ANIMATION, - LAYOUT_CONFIRM_ANIMATION, - LAYOUT_CONFIRMED, - LAYOUT_FINISHED, - LAYOUT_NUM_LAYOUTS, - LAYOUT_INVALID +typedef enum { HOME, CONFIRM_WAIT, CONFIRMED, FINISHED } DisplayState; + +typedef enum { + LAYOUT_REQUEST, + LAYOUT_REQUEST_NO_ANIMATION, + LAYOUT_CONFIRM_ANIMATION, + LAYOUT_CONFIRMED, + LAYOUT_FINISHED, + LAYOUT_NUM_LAYOUTS, + LAYOUT_INVALID } ActiveLayout; /* Define the given layout dialog texts for each screen */ -typedef struct -{ - const char *request_title; - const char *request_body; +typedef struct { + const char *request_title; + const char *request_body; } ScreenLine; typedef ScreenLine ScreenLines; typedef ScreenLines DialogLines[LAYOUT_NUM_LAYOUTS]; -typedef struct -{ - DialogLines lines; - DisplayState display_state; - ActiveLayout active_layout; +typedef struct { + DialogLines lines; + DisplayState display_state; + ActiveLayout active_layout; } StateInfo; typedef void (*layout_notification_t)(const char *str1, const char *str2, @@ -72,7 +63,11 @@ typedef void (*layout_notification_t)(const char *str1, const char *str2, /// \param request_title Title of confirm message. /// \param request_body Body of confirm message. /// \returns true iff the device confirmed. -bool confirm(ButtonRequestType type, const char *request_title, const char *request_body, +bool confirm(ButtonRequestType type, const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 3, 4))); + +bool confirm_constant_power(ButtonRequestType type, const char *request_title, const char *request_body, ...) __attribute__((format(printf, 3, 4))); /// User confirmation. @@ -81,8 +76,9 @@ bool confirm(ButtonRequestType type, const char *request_title, const char *requ /// \param request_body Body of confirm message. /// \returns true iff the device confirmed. bool confirm_with_custom_button_request(ButtonRequest *button_request, - const char *request_title, const char *request_body, - ...) __attribute__((format(printf, 3, 4))); + const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 3, 4))); /// User confirmation, custom layout. /// \param layout_notification_func Layout callback. @@ -92,8 +88,9 @@ bool confirm_with_custom_button_request(ButtonRequest *button_request, /// \returns true iff the device confirmed. bool confirm_with_custom_layout(layout_notification_t layout_notification_func, ButtonRequestType type, - const char *request_title, const char *request_body, - ...) __attribute__((format(printf, 4, 5))); + const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 4, 5))); /// User confirmation. /// @@ -101,19 +98,22 @@ bool confirm_with_custom_layout(layout_notification_t layout_notification_func, /// \param request_title Title of confirm message. /// \param request_body Body of confirm message. /// \returns true iff the device confirmed. -bool confirm_without_button_request(const char *request_title, const char *request_body, - ...) __attribute__((format(printf, 2, 3))); +bool confirm_without_button_request(const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 2, 3))); /// Like confirm, but always \returns true. /// \param request_title Title of confirm message. /// \param request_body Body of confirm message. -bool review(ButtonRequestType type, const char *request_title, const char *request_body, - ...) __attribute__((format(printf, 3, 4))); - -/// Like confirm, but always \returns true. Does not message the host for ButtonAcks. -/// \param request_title Title of confirm message. -/// \param request_body Body of confirm message. -bool review_without_button_request(const char *request_title, const char *request_body, - ...) __attribute__((format(printf, 2, 3))); +bool review(ButtonRequestType type, const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 3, 4))); + +/// Like confirm, but always \returns true. Does not message the host for +/// ButtonAcks. \param request_title Title of confirm message. \param +/// request_body Body of confirm message. +bool review_without_button_request(const char *request_title, + const char *request_body, ...) + __attribute__((format(printf, 2, 3))); #endif diff --git a/include/keepkey/board/draw.h b/include/keepkey/board/draw.h index b7e2d1eb3..2e9ccfa02 100644 --- a/include/keepkey/board/draw.h +++ b/include/keepkey/board/draw.h @@ -20,7 +20,6 @@ #ifndef DRAW_H #define DRAW_H - #include #include @@ -29,34 +28,30 @@ #include "resources.h" #include "keepkey/board/variant.h" - -typedef struct -{ - uint8_t color; - uint16_t x; - uint16_t y; +typedef struct { + uint8_t color; + uint16_t x; + uint16_t y; } DrawableParams; -typedef struct -{ - DrawableParams base; - uint16_t height; - uint16_t width; +typedef struct { + DrawableParams base; + uint16_t height; + uint16_t width; } BoxDrawableParams; - -bool draw_char_with_shift(Canvas *canvas, DrawableParams *p, - uint16_t *x_shift, uint16_t *y_shift, const CharacterImage *img); -void draw_string(Canvas *canvas, const Font *font, const char *c, DrawableParams *p, - uint16_t width, - uint16_t line_height); +bool draw_char_with_shift(Canvas *canvas, DrawableParams *p, uint16_t *x_shift, + uint16_t *y_shift, const CharacterImage *img); +void draw_string(Canvas *canvas, const Font *font, const char *c, + DrawableParams *p, uint16_t width, uint16_t line_height); void draw_char(Canvas *canvas, const Font *font, char c, DrawableParams *p); -void draw_char_simple(Canvas *canvas, const Font *font, char c, uint8_t color, uint16_t x, - uint16_t y); -void draw_box(Canvas *canvas, BoxDrawableParams *params); -void draw_box_simple(Canvas *canvas, uint8_t color, uint16_t x, uint16_t y, uint16_t width, uint16_t height); -bool draw_bitmap_mono_rle(Canvas *canvas, const AnimationFrame *frame, bool erase); +void draw_char_simple(Canvas *canvas, const Font *font, char c, uint8_t color, + uint16_t x, uint16_t y); +void draw_box(Canvas *canvas, BoxDrawableParams *params); +void draw_box_simple(Canvas *canvas, uint8_t color, uint16_t x, uint16_t y, + uint16_t width, uint16_t height); +bool draw_bitmap_mono_rle(Canvas *canvas, const AnimationFrame *frame, + bool erase); #endif - diff --git a/include/keepkey/board/font.h b/include/keepkey/board/font.h index 9df8b2b55..8ab656dc1 100644 --- a/include/keepkey/board/font.h +++ b/include/keepkey/board/font.h @@ -20,36 +20,28 @@ #ifndef FONT_H #define FONT_H - #include - /* Data pertaining to the image of a character */ -typedef struct -{ - const uint8_t *data; - uint16_t width; - uint16_t height; +typedef struct { + const uint8_t *data; + uint16_t width; + uint16_t height; } CharacterImage; - /* Character information. */ -typedef struct -{ - long int code; - const CharacterImage *image; +typedef struct { + long int code; + const CharacterImage *image; } Character; - /* A complete font package. */ -typedef struct -{ - int length; - int size; - const Character *characters; +typedef struct { + int length; + int size; + const Character *characters; } Font; - const Font *get_pin_font(void); const Font *get_title_font(void); const Font *get_body_font(void); diff --git a/include/keepkey/board/keepkey_board.h b/include/keepkey/board/keepkey_board.h index cdc780f20..eaa2b730a 100644 --- a/include/keepkey/board/keepkey_board.h +++ b/include/keepkey/board/keepkey_board.h @@ -41,42 +41,40 @@ 0x0029 | ? | Storage structure */ -#define STORAGE_SECTOR_LEN 0x00004000 +#define STORAGE_SECTOR_LEN 0x00004000 -#define STORAGE_MAGIC_STR "stor" -#define STORAGE_MAGIC_LEN 4 +#define STORAGE_MAGIC_STR "stor" +#define STORAGE_MAGIC_LEN 4 -#define CACHE_EXISTS 0xCA +#define CACHE_EXISTS 0xCA /* Specify the length of the uuid binary string */ -#define STORAGE_UUID_LEN 12 +#define STORAGE_UUID_LEN 12 /* Length of the uuid binary converted to readable ASCII. */ #define STORAGE_UUID_STR_LEN ((STORAGE_UUID_LEN * 2) + 1) -#define SMALL_STR_BUF 32 -#define MEDIUM_STR_BUF 64 -#define LARGE_STR_BUF 128 +#define SMALL_STR_BUF 32 +#define MEDIUM_STR_BUF 64 +#define LARGE_STR_BUF 128 #define VERSION_NUM(x) #x #define VERSION_STR(x) VERSION_NUM(x) /* Flash metadata structure which will contains unique identifier information that spans device resets. */ -typedef struct _Metadata -{ - char magic[STORAGE_MAGIC_LEN]; - uint8_t uuid[STORAGE_UUID_LEN]; - char uuid_str[STORAGE_UUID_STR_LEN]; +typedef struct _Metadata { + char magic[STORAGE_MAGIC_LEN]; + uint8_t uuid[STORAGE_UUID_LEN]; + char uuid_str[STORAGE_UUID_STR_LEN]; } Metadata; /* Cache structure */ -typedef struct _Cache -{ - /* Root node cache */ - uint8_t root_seed_cache_status; - uint8_t root_seed_cache[64]; - char root_ecdsa_curve_type[10]; +typedef struct _Cache { + /* Root node cache */ + uint8_t root_seed_cache_status; + uint8_t root_seed_cache[64]; + char root_ecdsa_curve_type[10]; } Cache; extern uintptr_t __stack_chk_guard; diff --git a/include/keepkey/board/keepkey_button.h b/include/keepkey/board/keepkey_button.h index 2f365996f..f32e7bbf1 100644 --- a/include/keepkey/board/keepkey_button.h +++ b/include/keepkey/board/keepkey_button.h @@ -20,16 +20,12 @@ #ifndef KEEPKEY_BUTTON_H #define KEEPKEY_BUTTON_H - #include #include "canvas.h" - typedef void (*Handler)(void* context); - - /** kk_keepkey_button_init() - Initialize push botton interrupt registers * and variables * @@ -41,13 +37,14 @@ typedef void (*Handler)(void* context); void kk_keepkey_button_init(void); void keepkey_button_init(void); -void keepkey_button_set_on_press_handler( Handler handler, void* context); -void keepkey_button_set_on_release_handler( Handler handler, void* context); +void keepkey_button_set_on_press_handler(Handler handler, void* context); +void keepkey_button_set_on_release_handler(Handler handler, void* context); bool keepkey_button_down(void); bool keepkey_button_up(void); /** - * buttonisr_usr() - user interrupt service routine for push button external interrupt + * buttonisr_usr() - user interrupt service routine for push button external + *interrupt * * INPUT * none diff --git a/include/keepkey/board/keepkey_display.h b/include/keepkey/board/keepkey_display.h index 142078288..71fb78e92 100644 --- a/include/keepkey/board/keepkey_display.h +++ b/include/keepkey/board/keepkey_display.h @@ -20,18 +20,15 @@ #ifndef KEEPKEY_DISPLAY_H #define KEEPKEY_DISPLAY_H - #include "canvas.h" - #define START_COL ((uint8_t)0x1C) #define START_ROW ((uint8_t)0x00) -#define KEEPKEY_DISPLAY_HEIGHT 64 -#define KEEPKEY_DISPLAY_WIDTH 256 - -#define DEFAULT_DISPLAY_BRIGHTNESS 100 /* Percent */ +#define KEEPKEY_DISPLAY_HEIGHT 64 +#define KEEPKEY_DISPLAY_WIDTH 256 +#define DEFAULT_DISPLAY_BRIGHTNESS 100 /* Percent */ void display_hw_init(void); Canvas *display_canvas_init(void); @@ -41,6 +38,8 @@ void display_set_brightness(int percentage); void display_turn_on(void); void display_turn_off(void); +void display_constant_power(bool enabled); + typedef void (*DumpDisplayCallback)(const uint8_t*); void display_set_dump_callback(DumpDisplayCallback d); diff --git a/include/keepkey/board/keepkey_flash.h b/include/keepkey/board/keepkey_flash.h index c504f1abe..2074e601a 100644 --- a/include/keepkey/board/keepkey_flash.h +++ b/include/keepkey/board/keepkey_flash.h @@ -20,20 +20,30 @@ #ifndef KEEPKEY_FLASH_H #define KEEPKEY_FLASH_H - -#define MODEL_STR_SIZE 32 - +#define MODEL_STR_SIZE 32 #include #include "memory.h" +#ifndef EMULATOR +#include +// This sequence ensures that the flash unlock sequence is reset before +// attempting an unlock. If an unlock is called when the flash is unlocked, a +// hard fault exception is thrown +#define flash_unlock(void) \ + ; \ + flash_lock(void); \ + flash_unlock(void); +#endif intptr_t flash_write_helper(Allocation group); void flash_erase(Allocation group); void flash_erase_word(Allocation group); -bool flash_write(Allocation group, uint32_t offset, uint32_t len, const uint8_t *data); -bool flash_write_word(Allocation group, uint32_t offset, uint32_t len, const uint8_t *data); +bool flash_write(Allocation group, uint32_t offset, uint32_t len, + const uint8_t *data); +bool flash_write_word(Allocation group, uint32_t offset, uint32_t len, + const uint8_t *data); bool flash_chk_status(void); bool is_mfg_mode(void); bool set_mfg_mode_off(void); diff --git a/include/keepkey/board/keepkey_leds.h b/include/keepkey/board/keepkey_leds.h index 65f9252ee..5f4e1826c 100644 --- a/include/keepkey/board/keepkey_leds.h +++ b/include/keepkey/board/keepkey_leds.h @@ -20,24 +20,20 @@ #ifndef KEEPKEY_LEDS_H #define KEEPKEY_LEDS_H - #include #include "canvas.h" - typedef enum { - CLR_GREEN_LED, - SET_GREEN_LED, - TGL_GREEN_LED, - CLR_RED_LED, - SET_RED_LED, - TGL_RED_LED + CLR_GREEN_LED, + SET_GREEN_LED, + TGL_GREEN_LED, + CLR_RED_LED, + SET_RED_LED, + TGL_RED_LED } LedAction; - -void keepkey_leds_init( void); +void keepkey_leds_init(void); void led_func(LedAction act); #endif - diff --git a/include/keepkey/board/keepkey_usart.h b/include/keepkey/board/keepkey_usart.h index 487252f4b..308433a3e 100644 --- a/include/keepkey/board/keepkey_usart.h +++ b/include/keepkey/board/keepkey_usart.h @@ -20,7 +20,6 @@ #ifndef KEEPKEY_USART_H #define KEEPKEY_USART_H - #include #include "keepkey_leds.h" @@ -29,16 +28,17 @@ #include "timer.h" - -#define SMALL_DEBUG_BUF 32 -#define MEDIUM_DEBUG_BUF 64 -#define LARGE_DEBUG_BUF 128 - +#define SMALL_DEBUG_BUF 32 +#define MEDIUM_DEBUG_BUF 64 +#define LARGE_DEBUG_BUF 128 #ifndef EMULATOR -void dbg_print(const char *pStr, ...) __attribute__((format(printf,1,2))); +void dbg_print(const char *pStr, ...) __attribute__((format(printf, 1, 2))); #else -# define dbg_print(FMT, ...) do { printf(FMT, ## __VA_ARGS__); } while(0) +#define dbg_print(FMT, ...) \ + do { \ + printf(FMT, ##__VA_ARGS__); \ + } while (0) #endif void usart_init(void); diff --git a/include/keepkey/board/layout.h b/include/keepkey/board/layout.h index 0d0e354c4..3e03e190c 100644 --- a/include/keepkey/board/layout.h +++ b/include/keepkey/board/layout.h @@ -20,14 +20,12 @@ #ifndef LAYOUT_H #define LAYOUT_H - #include "keepkey/board/canvas.h" #include "keepkey/board/resources.h" #include "keepkey/board/draw.h" #include - #define MAX_ANIMATIONS 5 #define ANIMATION_PERIOD 20 @@ -39,71 +37,68 @@ #define TOP_MARGIN_FOR_THREE_LINES 0 /* Margin */ -#define TOP_MARGIN 7 +#define TOP_MARGIN 7 #define LEFT_MARGIN 4 /* Title */ -#define TITLE_COLOR 0xFF -#define TITLE_WIDTH 206 -#define TITLE_ROWS 1 +#define TITLE_COLOR 0xFF +#define TITLE_WIDTH 206 +#define TITLE_ROWS 1 #define TITLE_FONT_LINE_PADDING 0 -#define TITLE_CHAR_MAX 128 +#define TITLE_CHAR_MAX 128 /* Body */ -#define BODY_TOP_MARGIN 7 -#define BODY_COLOR 0xFF -#define BODY_WIDTH 225 -#define BODY_ROWS 3 -#define BODY_FONT_LINE_PADDING 4 -#define BODY_CHAR_MAX 352 +#define BODY_TOP_MARGIN 7 +#define BODY_COLOR 0xFF +#define BODY_WIDTH 225 +#define BODY_ROWS 3 +#define BODY_FONT_LINE_PADDING 4 +#define BODY_CHAR_MAX 352 /* Warning */ -#define WARNING_COLOR 0xFF -#define WARNING_ROWS 1 -#define WARNING_FONT_LINE_PADDING 0 +#define WARNING_COLOR 0xFF +#define WARNING_ROWS 1 +#define WARNING_FONT_LINE_PADDING 0 /* Default Layout */ #define NO_WIDTH 0; - -typedef enum -{ - NOTIFICATION_INFO, - NOTIFICATION_REQUEST, - NOTIFICATION_REQUEST_NO_ANIMATION, - NOTIFICATION_UNPLUG, - NOTIFICATION_CONFIRM_ANIMATION, - NOTIFICATION_CONFIRMED, - NOTIFICATION_LOGO, +typedef enum { + NOTIFICATION_INFO, + NOTIFICATION_REQUEST, + NOTIFICATION_REQUEST_NO_ANIMATION, + NOTIFICATION_UNPLUG, + NOTIFICATION_CONFIRM_ANIMATION, + NOTIFICATION_CONFIRMED, + NOTIFICATION_LOGO, } NotificationType; -typedef void (*AnimateCallback)(void *data, uint32_t duration, uint32_t elapsed); +typedef void (*AnimateCallback)(void *data, uint32_t duration, + uint32_t elapsed); typedef struct Animation Animation; typedef void (*leaving_handler_t)(void); -struct Animation -{ - uint32_t duration; - uint32_t elapsed; - void *data; - AnimateCallback animate_callback; - Animation *next; +struct Animation { + uint32_t duration; + uint32_t elapsed; + void *data; + AnimateCallback animate_callback; + Animation *next; }; -typedef struct -{ - Animation *head; - int size; +typedef struct { + Animation *head; + int size; } AnimationQueue; - void layout_init(Canvas *canvas); Canvas *layout_get_canvas(void); void call_leaving_handler(void); void layout_firmware_update_confirmation(void); void layout_standard_notification(const char *str1, const char *str2, NotificationType type); +void layout_constant_power_notification(const char *str1, const char *str2, NotificationType type); void layout_notification_icon(NotificationType type, DrawableParams *sp); void layout_warning(const char *prompt); void layout_warning_static(const char *str); @@ -117,7 +112,8 @@ void force_animation_start(void); void animating_progress_handler(const char *desc, int permil); void layoutProgress(const char *desc, int permil); void layoutProgressSwipe(const char *desc, int permil); -void layout_add_animation(AnimateCallback callback, void *data, uint32_t duration); +void layout_add_animation(AnimateCallback callback, void *data, + uint32_t duration); void layout_animate_images(void *data, uint32_t duration, uint32_t elapsed); void layout_clear(void); #if DEBUG_LINK diff --git a/include/keepkey/board/memory.h b/include/keepkey/board/memory.h index abc1d549c..14f6ff555 100644 --- a/include/keepkey/board/memory.h +++ b/include/keepkey/board/memory.h @@ -27,14 +27,14 @@ #include #include - +// clang-format off /* flash memory layout: -------------------- name | range | size | function | MPU Protection -----------+-------------------------+---------+------------------+---------------------- - Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootstrap code | signature dependent + Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootstrap code | signature dependent Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | storage/config | full access -----------+-------------------------+---------+------------------+---------------------- Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | storage/config | full access @@ -49,7 +49,7 @@ Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | application code | full access Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | application code | full access - Application metadata area: + Application metadata area (first 256 bytes of application code) ------------------------- offset | type/length | description --------+-------------+------------------------------- @@ -58,24 +58,25 @@ 0x0008 | uint8 | signature index #1 0x0009 | uint8 | signature index #2 0x000A | uint8 | signature index #3 - 0x000B | uint8 | flags - 0x000C | 52 bytes | reserved + 0x000B | uint8 | SIG_FLAG (old bootloaders test this entire byte as a flag) + 0x000C | uint32 | META_FLAGS + 0x0010 | 48 bytes | reserved 0x0040 | 64 bytes | signature #1 0x0080 | 64 bytes | signature #2 0x00C0 | 64 bytes | signature #3 0x0100 | 32K-256 B | persistent storage - flags & 0x01 -> restore storage after flashing (if signatures are ok) - flags & 0x02 -> boot into firmware update mode + SIG_FLAG != 0 -> restore storage after flashing (if signatures are ok) + META_FLAGS & 0x00000001 == true -> boot into firmware update mode */ - +// clang-format on #ifdef EMULATOR extern uint8_t *emulator_flash_base; -#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) +#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) #else -#define FLASH_PTR(x) (const uint8_t*) (x) +#define FLASH_PTR(x) (const uint8_t *)(x) #endif #define OPTION_BYTES_1 ((uint64_t *)0x1FFFC000) @@ -83,85 +84,95 @@ extern uint8_t *emulator_flash_base; #define OPTION_RDP 0xCCFF #define OPTION_WRP 0xFF9E -#define OTP_MFG_ADDR 0x1FFF7800 -#define OTP_MFG_SIG 0x08012015 -#define OTP_MFG_SIG_LEN 4 -#define OTP_MODEL_ADDR 0x1FFF7820 -#define OTP_BLK_LOCK(x) (0x1FFF7A00 + (x - 0x1FFF7800)/0x20) - -#define BSTRP_FLASH_SECT_LEN 0x4000 -#define STOR_FLASH_SECT_LEN 0x4000 -#define UNUSED_FLASH_SECT0_LEN 0x10000 -#define BLDR_FLASH_SECT_LEN 0x20000 -#define APP_FLASH_SECT_LEN 0x20000 +#define OTP_MFG_ADDR 0x1FFF7800 +#define OTP_MFG_SIG 0x08012015 +#define OTP_MFG_SIG_LEN 4 +#define OTP_MODEL_ADDR 0x1FFF7820 +#define OTP_BLK_LOCK(x) (0x1FFF7A00 + (x - 0x1FFF7800) / 0x20) -#define BSTRP_FLASH_SECT_START 0x08000000 -#define BLDR_FLASH_SECT_START 0x08020000 +#define BSTRP_FLASH_SECT_LEN 0x4000 +#define STOR_FLASH_SECT_LEN 0x4000 +#define UNUSED_FLASH_SECT0_LEN 0x10000 +#define BLDR_FLASH_SECT_LEN 0x20000 +#define APP_FLASH_SECT_LEN 0x20000 +#define BSTRP_FLASH_SECT_START 0x08000000 +#define BLDR_FLASH_SECT_START 0x08020000 /* meta info */ -#define META_MAGIC_STR "KPKY" +#define META_MAGIC_STR "KPKY" /* Flash Info */ -#define FLASH_ORIGIN (0x08000000) -#define FLASH_TOTAL_SIZE (1024 * 1024) -#define FLASH_END (FLASH_ORIGIN + FLASH_TOTAL_SIZE) +#define FLASH_ORIGIN (0x08000000) +#define FLASH_TOTAL_SIZE (1024 * 1024) +#define FLASH_END (FLASH_ORIGIN + FLASH_TOTAL_SIZE) /* Boot Strap Partition */ -#define FLASH_BOOTSTRAP_START (FLASH_ORIGIN) //0x0800_0000 - 0x0800_3FFF -#define FLASH_BOOTSTRAP_LEN (0x4000) +#define FLASH_BOOTSTRAP_START (FLASH_ORIGIN) // 0x0800_0000 - 0x0800_3FFF +#define FLASH_BOOTSTRAP_LEN (0x4000) /* Storage/Configuration Partition */ -#define FLASH_STORAGE_LEN (0x4000) +#define FLASH_STORAGE_LEN (0x4000) /*< 0x801_0000 - 0x801_FFFF is empty >*/ /* Boot Loader Partition */ -#define FLASH_BOOT_START (0x08020000) //0x0802_0000 - 0x0805_FFFF -#define FLASH_BOOT_LEN (0x40000) - +#define FLASH_BOOT_START (0x08020000) // 0x0802_0000 - 0x0805_FFFF +#define FLASH_BOOT_LEN (0x40000) /* Application Partition */ -#define FLASH_META_START (FLASH_BOOT_START + FLASH_BOOT_LEN) //0x0806_0000 -#define FLASH_META_DESC_LEN (0x100) - -#define FLASH_META_MAGIC (FLASH_META_START) -#define FLASH_META_CODELEN (FLASH_META_MAGIC + sizeof(((app_meta_td *)NULL)->magic)) -#define FLASH_META_SIGINDEX1 (FLASH_META_CODELEN + sizeof(((app_meta_td *)NULL)->code_len)) -#define FLASH_META_SIGINDEX2 (FLASH_META_SIGINDEX1 + sizeof(((app_meta_td *)NULL)->sig_index1)) -#define FLASH_META_SIGINDEX3 (FLASH_META_SIGINDEX2 + sizeof(((app_meta_td *)NULL)->sig_index2)) -#define FLASH_META_FLAGS (FLASH_META_SIGINDEX3 + sizeof(((app_meta_td *)NULL)->sig_index3)) -#define FLASH_META_RESERVE (FLASH_META_FLAGS + sizeof(((app_meta_td *)NULL)->flag)) -#define FLASH_META_SIG1 (FLASH_META_RESERVE + sizeof(((app_meta_td *)NULL)->rsv)) -#define FLASH_META_SIG2 (FLASH_META_SIG1 + sizeof(((app_meta_td *)NULL)->sig1)) -#define FLASH_META_SIG3 (FLASH_META_SIG2 + sizeof(((app_meta_td *)NULL)->sig2)) +#define FLASH_META_START (FLASH_BOOT_START + FLASH_BOOT_LEN) // 0x0806_0000 +#define FLASH_META_DESC_LEN (0x100) + +#define FLASH_META_MAGIC (FLASH_META_START) +#define FLASH_META_CODELEN \ + (FLASH_META_MAGIC + sizeof(((app_meta_td *)NULL)->magic)) +#define FLASH_META_SIGINDEX1 \ + (FLASH_META_CODELEN + sizeof(((app_meta_td *)NULL)->code_len)) +#define FLASH_META_SIGINDEX2 \ + (FLASH_META_SIGINDEX1 + sizeof(((app_meta_td *)NULL)->sig_index1)) +#define FLASH_META_SIGINDEX3 \ + (FLASH_META_SIGINDEX2 + sizeof(((app_meta_td *)NULL)->sig_index2)) +#define FLASH_SIG_FLAG \ + (FLASH_META_SIGINDEX3 + sizeof(((app_meta_td *)NULL)->sig_index3)) +#define FLASH_META_FLAGS \ + (FLASH_SIG_FLAG + sizeof(((app_meta_td *)NULL)->sig_flag)) +#define FLASH_META_RESERVE \ + (FLASH_META_FLAGS + sizeof(((app_meta_td *)NULL)->meta_flags)) +#define FLASH_META_SIG1 \ + (FLASH_META_RESERVE + sizeof(((app_meta_td *)NULL)->rsv)) +#define FLASH_META_SIG2 (FLASH_META_SIG1 + sizeof(((app_meta_td *)NULL)->sig1)) +#define FLASH_META_SIG3 (FLASH_META_SIG2 + sizeof(((app_meta_td *)NULL)->sig2)) + +#define META_MAGIC_SIZE (sizeof(((app_meta_td *)NULL)->magic)) + +#define FLASH_APP_START \ + (FLASH_META_START + FLASH_META_DESC_LEN) // 0x0806_0200 - 0x080F_FFFF +#define FLASH_APP_LEN (FLASH_END - FLASH_APP_START) + +#define SIG_FLAG (*(uint8_t const *)FLASH_SIG_FLAG) + +#define META_FLAGS (*(uint8_t const *)FLASH_META_FLAGS) -#define META_MAGIC_SIZE (sizeof(((app_meta_td *)NULL)->magic)) - -#define FLASH_APP_START (FLASH_META_START + FLASH_META_DESC_LEN) //0x0806_0200 - 0x080F_FFFF -#define FLASH_APP_LEN (FLASH_END - FLASH_APP_START) - -#define SIG_FLAG (*( uint8_t const *)FLASH_META_FLAGS) - /* Misc Info. */ #define FLASH_BOOTSTRAP_SECTOR 0 -#define FLASH_BOOTSTRAP_SECTOR_FIRST 0 -#define FLASH_BOOTSTRAP_SECTOR_LAST 0 +#define FLASH_BOOTSTRAP_SECTOR_FIRST 0 +#define FLASH_BOOTSTRAP_SECTOR_LAST 0 -#define FLASH_STORAGE_SECTOR_FIRST 1 -#define FLASH_STORAGE_SECTOR_LAST 3 +#define FLASH_STORAGE_SECTOR_FIRST 1 +#define FLASH_STORAGE_SECTOR_LAST 3 #define FLASH_VARIANT_SECTOR_FIRST 4 #define FLASH_VARIANT_SECTOR_LAST 4 #define FLASH_BOOT_SECTOR_FIRST 5 -#define FLASH_BOOT_SECTOR_LAST 6 +#define FLASH_BOOT_SECTOR_LAST 6 -#define FLASH_APP_SECTOR_FIRST 7 -#define FLASH_APP_SECTOR_LAST 11 +#define FLASH_APP_SECTOR_FIRST 7 +#define FLASH_APP_SECTOR_LAST 11 #define STORAGE_SECT_DEFAULT FLASH_STORAGE1 @@ -178,65 +189,65 @@ extern uint8_t *emulator_flash_base; // increase difficulty of glitching past the check: // // echo -n "boot allowed" | shasum -a 256 -#define STORAGE_PROTECT_OFF_MAGIC "\x31\x88\x4e\xb8\x48\x2a\x28\x09\xe3\x74\x61\xd9\x6a\xd7\xf0\xed\x8c\xdd\x7c\xa6\x07\x3e\x68\x6a\x15\xc0\x89\xc6\x11\x89\x95\xa0" -#define STORAGE_PROTECT_ON_MAGIC "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +#define STORAGE_PROTECT_OFF_MAGIC \ + "\x31\x88\x4e\xb8\x48\x2a\x28\x09\xe3\x74\x61\xd9\x6a\xd7\xf0\xed\x8c\xdd" \ + "\x7c\xa6\x07\x3e\x68\x6a\x15\xc0\x89\xc6\x11\x89\x95\xa0" +#define STORAGE_PROTECT_ON_MAGIC \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #define STORAGE_PROTECT_DISABLED 0x5ac35ac3 -#define STORAGE_PROTECT_ENABLED 0x00000000 +#define STORAGE_PROTECT_ENABLED 0x00000000 /* Application Meta format */ -typedef struct -{ - uint32_t magic; - uint32_t code_len; - uint8_t sig_index1; - uint8_t sig_index2; - uint8_t sig_index3; - uint8_t flag; - uint8_t rsv[52]; - uint8_t sig1[64]; - uint8_t sig2[64]; - uint8_t sig3[64]; +typedef struct { + uint32_t magic; + uint32_t code_len; + uint8_t sig_index1; + uint8_t sig_index2; + uint8_t sig_index3; + uint8_t sig_flag; + uint32_t meta_flags; + uint8_t rsv[48]; + uint8_t sig1[64]; + uint8_t sig2[64]; + uint8_t sig3[64]; } app_meta_td; -typedef enum -{ - FLASH_INVALID, - FLASH_BOOTSTRAP, - FLASH_STORAGE1, - FLASH_STORAGE2, - FLASH_STORAGE3, - FLASH_UNUSED0, - FLASH_BOOTLOADER, - FLASH_APP +typedef enum { + FLASH_INVALID, + FLASH_BOOTSTRAP, + FLASH_STORAGE1, + FLASH_STORAGE2, + FLASH_STORAGE3, + FLASH_UNUSED0, + FLASH_BOOTLOADER, + FLASH_APP } Allocation; -typedef struct -{ - int sector; - size_t start; - uint32_t len; - Allocation use; +typedef struct { + int sector; + size_t start; + uint32_t len; + Allocation use; } FlashSector; typedef void (*progress_handler_t)(void); -static const FlashSector flash_sector_map[] = -{ - { 0, 0x08000000, BSTRP_FLASH_SECT_LEN, FLASH_BOOTSTRAP }, - { 1, 0x08004000, STOR_FLASH_SECT_LEN, FLASH_STORAGE1 }, - { 2, 0x08008000, STOR_FLASH_SECT_LEN, FLASH_STORAGE2 }, - { 3, 0x0800C000, STOR_FLASH_SECT_LEN, FLASH_STORAGE3 }, - { 4, 0x08010000, UNUSED_FLASH_SECT0_LEN, FLASH_UNUSED0 }, - { 5, 0x08020000, BLDR_FLASH_SECT_LEN, FLASH_BOOTLOADER }, - { 6, 0x08040000, BLDR_FLASH_SECT_LEN, FLASH_BOOTLOADER }, - { 7, 0x08060000, APP_FLASH_SECT_LEN, FLASH_APP }, - { 8, 0x08080000, APP_FLASH_SECT_LEN, FLASH_APP }, - { 9, 0x080A0000, APP_FLASH_SECT_LEN, FLASH_APP }, - { 10, 0x080C0000, APP_FLASH_SECT_LEN, FLASH_APP }, - { 11, 0x080E0000, APP_FLASH_SECT_LEN, FLASH_APP }, - { -1, 0, 0, FLASH_INVALID} -}; +static const FlashSector flash_sector_map[] = { + {0, 0x08000000, BSTRP_FLASH_SECT_LEN, FLASH_BOOTSTRAP}, + {1, 0x08004000, STOR_FLASH_SECT_LEN, FLASH_STORAGE1}, + {2, 0x08008000, STOR_FLASH_SECT_LEN, FLASH_STORAGE2}, + {3, 0x0800C000, STOR_FLASH_SECT_LEN, FLASH_STORAGE3}, + {4, 0x08010000, UNUSED_FLASH_SECT0_LEN, FLASH_UNUSED0}, + {5, 0x08020000, BLDR_FLASH_SECT_LEN, FLASH_BOOTLOADER}, + {6, 0x08040000, BLDR_FLASH_SECT_LEN, FLASH_BOOTLOADER}, + {7, 0x08060000, APP_FLASH_SECT_LEN, FLASH_APP}, + {8, 0x08080000, APP_FLASH_SECT_LEN, FLASH_APP}, + {9, 0x080A0000, APP_FLASH_SECT_LEN, FLASH_APP}, + {10, 0x080C0000, APP_FLASH_SECT_LEN, FLASH_APP}, + {11, 0x080E0000, APP_FLASH_SECT_LEN, FLASH_APP}, + {-1, 0, 0, FLASH_INVALID}}; void mpu_config(int); @@ -246,7 +257,6 @@ void memory_protect(void); /// read-only sectors of flash. void memory_unlock(void); - /// Double sha256 hash of the bootloader. /// /// \param hash Buffer to be filled with hash. @@ -275,8 +285,8 @@ void storage_protect_wipe(uint32_t status); /// \returns STORAGE_PROTECT_{ENABLED,DISABLED} uint32_t storage_protect_status(void); -extern void * _timerusr_isr; -extern void * _buttonusr_isr; -extern void * _mmhusr_isr; +extern void *_timerusr_isr; +extern void *_buttonusr_isr; +extern void *_mmhusr_isr; #endif diff --git a/include/keepkey/board/messages.h b/include/keepkey/board/messages.h index 609838640..7fca69570 100644 --- a/include/keepkey/board/messages.h +++ b/include/keepkey/board/messages.h @@ -27,48 +27,33 @@ #include #include -#define MSG_TINY_BFR_SZ 64 +#define MSG_TINY_BFR_SZ 64 #define MSG_TINY_TYPE_ERROR 0xFFFF -#define MSG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - [ID].msg_id = (ID), \ - [ID].type = (NORMAL_MSG), \ - [ID].dir = (IN_MSG), \ - [ID].fields = (STRUCT_NAME ## _fields), \ - [ID].dispatch = (PARSABLE), \ - [ID].process_func = (void (*)(void*))(PROCESS_FUNC), - -#define MSG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) \ - [ID].msg_id = (ID), \ - [ID].type = (NORMAL_MSG), \ - [ID].dir = (OUT_MSG), \ - [ID].fields = (STRUCT_NAME ## _fields), \ - [ID].dispatch = (PARSABLE), \ - [ID].process_func = (void (*)(void*))(PROCESS_FUNC), - -#define RAW_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - [ID].msg_id = (ID), \ - [ID].type = (NORMAL_MSG), \ - [ID].dir = (IN_MSG), \ - [ID].fields = (STRUCT_NAME ## _fields), \ - [ID].dispatch = (RAW), \ - [ID].process_func = (void (*)(void*))(void*)(PROCESS_FUNC), - -#define DEBUG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - [ID].msg_id = (ID), \ - [ID].type = (DEBUG_MSG), \ - [ID].dir = (IN_MSG), \ - [ID].fields = (STRUCT_NAME ## _fields), \ - [ID].dispatch = (PARSABLE), \ - [ID].process_func = (void (*)(void*))(PROCESS_FUNC), - -#define DEBUG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) \ - [ID].msg_id = (ID), \ - [ID].type = (DEBUG_MSG), \ - [ID].dir = (OUT_MSG), \ - [ID].fields = (STRUCT_NAME ## _fields), \ - [ID].dispatch = (PARSABLE), \ - [ID].process_func = (void (*)(void*))(PROCESS_FUNC), +#define MSG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ + [ID].msg_id = (ID), [ID].type = (NORMAL_MSG), [ID].dir = (IN_MSG), \ + [ID].fields = (STRUCT_NAME##_fields), [ID].dispatch = (PARSABLE), \ + [ID].process_func = (void (*)(void *))(PROCESS_FUNC), + +#define MSG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) \ + [ID].msg_id = (ID), [ID].type = (NORMAL_MSG), [ID].dir = (OUT_MSG), \ + [ID].fields = (STRUCT_NAME##_fields), [ID].dispatch = (PARSABLE), \ + [ID].process_func = (void (*)(void *))(PROCESS_FUNC), + +#define RAW_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ + [ID].msg_id = (ID), [ID].type = (NORMAL_MSG), [ID].dir = (IN_MSG), \ + [ID].fields = (STRUCT_NAME##_fields), [ID].dispatch = (RAW), \ + [ID].process_func = (void (*)(void *))(void *)(PROCESS_FUNC), + +#define DEBUG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ + [ID].msg_id = (ID), [ID].type = (DEBUG_MSG), [ID].dir = (IN_MSG), \ + [ID].fields = (STRUCT_NAME##_fields), [ID].dispatch = (PARSABLE), \ + [ID].process_func = (void (*)(void *))(PROCESS_FUNC), + +#define DEBUG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) \ + [ID].msg_id = (ID), [ID].type = (DEBUG_MSG), [ID].dir = (OUT_MSG), \ + [ID].fields = (STRUCT_NAME##_fields), [ID].dispatch = (PARSABLE), \ + [ID].process_func = (void (*)(void *))(PROCESS_FUNC), #define NO_PROCESS_FUNC 0 @@ -80,48 +65,36 @@ typedef bool (*usb_tx_handler_t)(uint8_t *, uint32_t); typedef void (*msg_debug_link_get_state_t)(DebugLinkGetState *); #endif -typedef enum -{ - NORMAL_MSG, +typedef enum { + NORMAL_MSG, #if DEBUG_LINK - DEBUG_MSG, + DEBUG_MSG, #endif } MessageMapType; -typedef enum -{ - IN_MSG, - OUT_MSG -} MessageMapDirection; - -typedef enum -{ - PARSABLE, - RAW -} MessageMapDispatch; - -typedef struct -{ - const pb_field_t *fields; - msg_handler_t process_func; - MessageMapDispatch dispatch; - MessageMapType type; - MessageMapDirection dir; - MessageType msg_id; +typedef enum { IN_MSG, OUT_MSG } MessageMapDirection; + +typedef enum { PARSABLE, RAW } MessageMapDispatch; + +typedef struct { + const pb_field_t *fields; + msg_handler_t process_func; + MessageMapDispatch dispatch; + MessageMapType type; + MessageMapDirection dir; + MessageType msg_id; } MessagesMap_t; -typedef struct -{ - const uint8_t *buffer; - uint32_t length; +typedef struct { + const uint8_t *buffer; + uint32_t length; } RawMessage; -typedef enum -{ - RAW_MESSAGE_NOT_STARTED, - RAW_MESSAGE_STARTED, - RAW_MESSAGE_COMPLETE, - RAW_MESSAGE_ERROR +typedef enum { + RAW_MESSAGE_NOT_STARTED, + RAW_MESSAGE_STARTED, + RAW_MESSAGE_COMPLETE, + RAW_MESSAGE_ERROR } RawMessageState; typedef void (*raw_msg_handler_t)(RawMessage *msg, uint32_t frame_length); @@ -140,8 +113,8 @@ void set_msg_failure_handler(msg_failure_t failure_func); void call_msg_failure_handler(FailureType code, const char *text); #if DEBUG_LINK -void set_msg_debug_link_get_state_handler(msg_debug_link_get_state_t - debug_link_get_state_func); +void set_msg_debug_link_get_state_handler( + msg_debug_link_get_state_t debug_link_get_state_func); void call_msg_debug_link_get_state_handler(DebugLinkGetState *msg); #endif @@ -156,5 +129,6 @@ MessageType wait_for_tiny_msg(uint8_t *buf); MessageType check_for_tiny_msg(uint8_t *buf); uint32_t parse_pb_varint(RawMessage *msg, uint8_t varint_count); -int encode_pb(const void *source_ptr, const pb_field_t *fields, uint8_t *buffer, uint32_t len ); +int encode_pb(const void *source_ptr, const pb_field_t *fields, uint8_t *buffer, + uint32_t len); #endif diff --git a/include/keepkey/board/mpudefs.h b/include/keepkey/board/mpudefs.h index 45c9ed8fa..a175430c1 100644 --- a/include/keepkey/board/mpudefs.h +++ b/include/keepkey/board/mpudefs.h @@ -18,33 +18,31 @@ #ifndef MPUDEFS_H #define MPUDEFS_H - // MPU -#define MPU_RASR_SIZE_512B (0x08UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_2KB (0x0AUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512B (0x08UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_2KB (0x0AUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html -#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) -#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) +#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) #define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_B | MPU_RASR_ATTR_S) // subregion disable bits -#define MPU_RASR_DIS_SUB_8 (0b10000000UL << 8) - -#define FLASH_BASE (0x08000000U) -#define SRAM_BASE (0x20000000U) -#define BLPROTECT_BASE (0x2001F800U) +#define MPU_RASR_DIS_SUB_8 (0b10000000UL << 8) +#define FLASH_BASE (0x08000000U) +#define SRAM_BASE (0x20000000U) +#define BLPROTECT_BASE (0x2001F800U) #endif \ No newline at end of file diff --git a/include/keepkey/board/pin.h b/include/keepkey/board/pin.h index e2a3bbc4a..8a07a32cb 100644 --- a/include/keepkey/board/pin.h +++ b/include/keepkey/board/pin.h @@ -20,44 +20,38 @@ #ifndef PIN_H #define PIN_H - #ifndef EMULATOR -# include -# include +#include +#include #endif #include +#define SET_PIN(p) GPIO_BSRR((p).port) = (p).pin +#define CLEAR_PIN(p) GPIO_BSRR((p).port) = ((p).pin << 16) +#define TOGGLE_PIN(p) GPIO_ODR((p).port) ^= (p).pin -#define SET_PIN(p) GPIO_BSRR( (p).port ) = (p).pin -#define CLEAR_PIN(p) GPIO_BSRR( (p).port ) = ( (p).pin << 16 ) -#define TOGGLE_PIN(p) GPIO_ODR( (p).port ) ^= (p).pin - +typedef enum { + PUSH_PULL_MODE, + OPEN_DRAIN_MODE, -typedef enum -{ - PUSH_PULL_MODE, - OPEN_DRAIN_MODE, - - NUM_PIN_MODES + NUM_PIN_MODES } OutputMode; -typedef enum -{ - PULL_UP_MODE, - PULL_DOWN_MODE, - NO_PULL_MODE, +typedef enum { + PULL_UP_MODE, + PULL_DOWN_MODE, + NO_PULL_MODE, - NUM_PULL_MODES + NUM_PULL_MODES } PullMode; -typedef struct -{ - uint32_t port; - uint16_t pin; +typedef struct { + uint32_t port; + uint16_t pin; } Pin; - -void pin_init_output(const Pin *pin, OutputMode output_mode, PullMode pull_mode); +void pin_init_output(const Pin *pin, OutputMode output_mode, + PullMode pull_mode); #endif diff --git a/include/keepkey/board/pubkeys.h b/include/keepkey/board/pubkeys.h index c29a23752..f54425a05 100644 --- a/include/keepkey/board/pubkeys.h +++ b/include/keepkey/board/pubkeys.h @@ -27,58 +27,46 @@ #define PUBKEY_LENGTH 65 #define SIGNATURES 3 -#define SIG_OK 0x5A3CA5C3 +#define SIG_OK 0x5A3CA5C3 #define KEY_EXPIRED 0x00000001 -#define SIG_FAIL 0x00000000 +#define SIG_FAIL 0x00000000 -static const uint8_t pubkey[PUBKEYS][PUBKEY_LENGTH] = -{ - { - /* Public key 1 */ - 0x04, 0xa3, 0x3c, 0xec, 0x36, 0xd6, 0xd0, 0x11, 0xaf, 0x09, 0xe0, 0xc4, - 0x98, 0xd1, 0x7c, 0x3b, 0xa7, 0xab, 0x90, 0x7a, 0xbf, 0xbb, 0x64, 0xca, - 0xba, 0x16, 0xad, 0x90, 0x77, 0xca, 0xac, 0xd3, 0xe1, 0x98, 0xa3, 0x23, - 0x62, 0xc3, 0x2d, 0x0e, 0xf0, 0xa7, 0x26, 0x92, 0x59, 0xab, 0xbb, 0xcd, - 0x8a, 0x68, 0x8a, 0x0c, 0x8f, 0x54, 0xa6, 0xdb, 0xc4, 0x05, 0x45, 0x95, - 0x66, 0xcd, 0x65, 0x14, 0x1d - }, - { - /* Public key 2 */ - 0x04, 0xab, 0x29, 0x1f, 0x6b, 0xd3, 0x3d, 0x0e, 0x39, 0x74, 0xf2, 0x7e, - 0x50, 0x07, 0x0b, 0xe9, 0x33, 0x69, 0x5a, 0x0f, 0xab, 0x7b, 0x8b, 0x36, - 0x54, 0xe7, 0xc9, 0xdc, 0xe7, 0x4f, 0x7f, 0x98, 0xfd, 0x73, 0x9b, 0x1e, - 0xd8, 0x6e, 0xb0, 0xbe, 0x26, 0xf0, 0x26, 0xe4, 0xdc, 0x65, 0x19, 0xfd, - 0x28, 0x84, 0x95, 0x5f, 0xa1, 0x74, 0xf8, 0xa7, 0x83, 0xfe, 0x45, 0x5a, - 0xc4, 0x3f, 0x94, 0x4c, 0x70 - }, - { - /* Public key 3 */ - 0x04, 0xa9, 0xc2, 0x9f, 0x4e, 0x05, 0x3b, 0x35, 0xff, 0xd3, 0xb9, 0xa3, - 0x7b, 0x07, 0x31, 0x88, 0xb6, 0x24, 0xc0, 0x7c, 0x3a, 0x92, 0x62, 0x2c, - 0x13, 0x1e, 0xdf, 0x1a, 0x2b, 0x2c, 0x71, 0x22, 0x16, 0xa8, 0xc0, 0x6c, - 0x9d, 0xdf, 0xdc, 0xaa, 0x39, 0xb8, 0x1d, 0x9a, 0x86, 0xf0, 0x45, 0x94, - 0x80, 0xb0, 0x27, 0x7e, 0xab, 0x0e, 0x30, 0xa3, 0x4f, 0x1d, 0x26, 0xb3, - 0x26, 0xb8, 0x99, 0x5a, 0x33 - }, - { - /* Public key 4 */ - 0x04, 0xf2, 0x28, 0x44, 0x8e, 0xaf, 0x05, 0x17, 0x1c, 0xcb, 0x68, 0xa0, - 0x4a, 0x07, 0x24, 0xac, 0x58, 0x6b, 0x84, 0x6c, 0x54, 0xc5, 0xfd, 0x0a, - 0x52, 0x6f, 0x9d, 0x7c, 0x33, 0x96, 0xc9, 0x8d, 0xd4, 0x7a, 0xef, 0x6b, - 0x2f, 0xaf, 0x47, 0xb5, 0x4f, 0xfa, 0x8c, 0x28, 0x61, 0xc5, 0x49, 0x20, - 0xce, 0x6c, 0x2a, 0xa5, 0x60, 0x7c, 0x49, 0x68, 0x69, 0x02, 0x37, 0x24, - 0xdb, 0x28, 0x54, 0x95, 0xc6 - }, - { - /* Public key 5 */ - 0x04, 0x18, 0xa9, 0x0b, 0x53, 0x6e, 0x9f, 0xfb, 0x0e, 0xc3, 0x20, 0x29, - 0x3c, 0x33, 0x75, 0x4a, 0xf8, 0x9b, 0x14, 0x54, 0x75, 0xc4, 0xd9, 0x21, - 0xf8, 0x18, 0xe2, 0x06, 0x2c, 0x92, 0xb0, 0x1b, 0xe5, 0x26, 0x04, 0x7c, - 0xcf, 0xa0, 0x42, 0xb4, 0x71, 0x1f, 0xb5, 0x60, 0x3f, 0xe6, 0xbd, 0x79, - 0x80, 0x69, 0x31, 0x00, 0xb7, 0x1e, 0xe7, 0x66, 0xd8, 0x61, 0x16, 0xa3, - 0x69, 0x48, 0x73, 0xf3, 0x14 - } -}; +static const uint8_t pubkey[PUBKEYS][PUBKEY_LENGTH] = { + {/* Public key 1 */ + 0x04, 0xa3, 0x3c, 0xec, 0x36, 0xd6, 0xd0, 0x11, 0xaf, 0x09, 0xe0, + 0xc4, 0x98, 0xd1, 0x7c, 0x3b, 0xa7, 0xab, 0x90, 0x7a, 0xbf, 0xbb, + 0x64, 0xca, 0xba, 0x16, 0xad, 0x90, 0x77, 0xca, 0xac, 0xd3, 0xe1, + 0x98, 0xa3, 0x23, 0x62, 0xc3, 0x2d, 0x0e, 0xf0, 0xa7, 0x26, 0x92, + 0x59, 0xab, 0xbb, 0xcd, 0x8a, 0x68, 0x8a, 0x0c, 0x8f, 0x54, 0xa6, + 0xdb, 0xc4, 0x05, 0x45, 0x95, 0x66, 0xcd, 0x65, 0x14, 0x1d}, + {/* Public key 2 */ + 0x04, 0xab, 0x29, 0x1f, 0x6b, 0xd3, 0x3d, 0x0e, 0x39, 0x74, 0xf2, + 0x7e, 0x50, 0x07, 0x0b, 0xe9, 0x33, 0x69, 0x5a, 0x0f, 0xab, 0x7b, + 0x8b, 0x36, 0x54, 0xe7, 0xc9, 0xdc, 0xe7, 0x4f, 0x7f, 0x98, 0xfd, + 0x73, 0x9b, 0x1e, 0xd8, 0x6e, 0xb0, 0xbe, 0x26, 0xf0, 0x26, 0xe4, + 0xdc, 0x65, 0x19, 0xfd, 0x28, 0x84, 0x95, 0x5f, 0xa1, 0x74, 0xf8, + 0xa7, 0x83, 0xfe, 0x45, 0x5a, 0xc4, 0x3f, 0x94, 0x4c, 0x70}, + {/* Public key 3 */ + 0x04, 0xa9, 0xc2, 0x9f, 0x4e, 0x05, 0x3b, 0x35, 0xff, 0xd3, 0xb9, + 0xa3, 0x7b, 0x07, 0x31, 0x88, 0xb6, 0x24, 0xc0, 0x7c, 0x3a, 0x92, + 0x62, 0x2c, 0x13, 0x1e, 0xdf, 0x1a, 0x2b, 0x2c, 0x71, 0x22, 0x16, + 0xa8, 0xc0, 0x6c, 0x9d, 0xdf, 0xdc, 0xaa, 0x39, 0xb8, 0x1d, 0x9a, + 0x86, 0xf0, 0x45, 0x94, 0x80, 0xb0, 0x27, 0x7e, 0xab, 0x0e, 0x30, + 0xa3, 0x4f, 0x1d, 0x26, 0xb3, 0x26, 0xb8, 0x99, 0x5a, 0x33}, + {/* Public key 4 */ + 0x04, 0xf2, 0x28, 0x44, 0x8e, 0xaf, 0x05, 0x17, 0x1c, 0xcb, 0x68, + 0xa0, 0x4a, 0x07, 0x24, 0xac, 0x58, 0x6b, 0x84, 0x6c, 0x54, 0xc5, + 0xfd, 0x0a, 0x52, 0x6f, 0x9d, 0x7c, 0x33, 0x96, 0xc9, 0x8d, 0xd4, + 0x7a, 0xef, 0x6b, 0x2f, 0xaf, 0x47, 0xb5, 0x4f, 0xfa, 0x8c, 0x28, + 0x61, 0xc5, 0x49, 0x20, 0xce, 0x6c, 0x2a, 0xa5, 0x60, 0x7c, 0x49, + 0x68, 0x69, 0x02, 0x37, 0x24, 0xdb, 0x28, 0x54, 0x95, 0xc6}, + {/* Public key 5 */ + 0x04, 0x18, 0xa9, 0x0b, 0x53, 0x6e, 0x9f, 0xfb, 0x0e, 0xc3, 0x20, + 0x29, 0x3c, 0x33, 0x75, 0x4a, 0xf8, 0x9b, 0x14, 0x54, 0x75, 0xc4, + 0xd9, 0x21, 0xf8, 0x18, 0xe2, 0x06, 0x2c, 0x92, 0xb0, 0x1b, 0xe5, + 0x26, 0x04, 0x7c, 0xcf, 0xa0, 0x42, 0xb4, 0x71, 0x1f, 0xb5, 0x60, + 0x3f, 0xe6, 0xbd, 0x79, 0x80, 0x69, 0x31, 0x00, 0xb7, 0x1e, 0xe7, + 0x66, 0xd8, 0x61, 0x16, 0xa3, 0x69, 0x48, 0x73, 0xf3, 0x14}}; extern volatile const uint8_t valid_pubkey[PUBKEYS]; diff --git a/include/keepkey/board/resources.h b/include/keepkey/board/resources.h index ee5ed8275..68079ba1a 100644 --- a/include/keepkey/board/resources.h +++ b/include/keepkey/board/resources.h @@ -38,5 +38,5 @@ const VariantAnimation *get_logo_reversed_animation(void); uint32_t get_image_animation_duration(const VariantAnimation *animation); int get_image_animation_frame(const VariantAnimation *animation, - const uint32_t elapsed, bool loop); + const uint32_t elapsed, bool loop); #endif diff --git a/include/keepkey/board/supervise.h b/include/keepkey/board/supervise.h index e6ce251a9..92489444e 100644 --- a/include/keepkey/board/supervise.h +++ b/include/keepkey/board/supervise.h @@ -20,42 +20,41 @@ #ifndef __SUPERVISE_H__ #define __SUPERVISE_H__ -#define SVC_BUSR_RET 1 -#define SVC_TUSR_RET 2 -#define SVC_ENA_INTR 3 -#define SVC_DIS_INTR 4 -#define SVC_FLASH_ERASE 5 -#define SVC_FLASH_PGM_BLK 6 -#define SVC_FLASH_PGM_WORD 7 -#define SVC_FIRMWARE_PRIV 8 -#define SVC_FIRMWARE_UNPRIV 9 //WARNING: do not change this value unless you also change svc_firmware_unpriv in isr.s to match - - - -#ifndef __ASSEMBLER__ - +#define SVC_BUSR_RET 1 +#define SVC_TUSR_RET 2 +#define SVC_ENA_INTR 3 +#define SVC_DIS_INTR 4 +#define SVC_FLASH_ERASE 5 +#define SVC_FLASH_PGM_BLK 6 +#define SVC_FLASH_PGM_WORD 7 +#define SVC_FIRMWARE_PRIV 8 +#define SVC_FIRMWARE_UNPRIV \ + 9 // WARNING: do not change this value unless you also change + // svc_firmware_unpriv in isr.s to match + +#ifndef __ASSEMBLER__ extern uint32_t _param_1; extern uint32_t _param_2; extern uint32_t _param_3; - void svc_busr_return(void); void svc_tusr_return(void); void svc_enable_interrupts(void); void svc_disable_interrupts(void); -/// svc calls to erase and write the flash should not be done in bootloader, use direct erase and write functions +/// svc calls to erase and write the flash should not be done in bootloader, use +/// direct erase and write functions /** * svc_flash_erase_sector() - request to erase a flash sector * entry: * sector is the flash sector to erase (0-11) * exit: - * requested sector is erased if legal: note that bootstrap and bootloader sectors cannot - * be erased with this call. -**/ -void svc_flash_erase_sector(uint32_t sector); + * requested sector is erased if legal: note that bootstrap and + *bootloader sectors cannot be erased with this call. + **/ +void svc_flash_erase_sector(uint32_t sector); /** * svc_flash_pgm_blk() - request to program a block of data @@ -65,7 +64,7 @@ void svc_flash_erase_sector(uint32_t sector); * align is the alignment * exit: * returns true if successful, otherwise false -**/ + **/ bool svc_flash_pgm_blk(uint32_t beginAddr, uint32_t data, uint32_t align); /** @@ -75,51 +74,52 @@ bool svc_flash_pgm_blk(uint32_t beginAddr, uint32_t data, uint32_t align); * data is the data to write * exit: * returns true if successful, otherwise false -**/ + **/ bool svc_flash_pgm_word(uint32_t beginAddr, uint32_t data); - /// These are the handlers that reside in the bootloader /** - svhandler_flash_erase_sector() - handler to erase a sector + svhandler_flash_erase_sector() - handler to erase a sector - on entry: - _param_1: sector to erase - on exit: + on entry: + _param_1: sector to erase + on exit: - svc calls to erase and write the flash should not be done in bootloader, use direct erase and write functions + svc calls to erase and write the flash should not be done in bootloader, +use direct erase and write functions **/ void svhandler_flash_erase_sector(void); - void svhandler_button_usr_return(void); void svhandler_timer_usr_return(void); void svhandler_enable_interrupts(void); void svhandler_disable_interrupts(void); /** - svhandler_flash_pgm_blk() - handler to program a block - On entry: - _param_1 = address: uint32_t start address in flash + svhandler_flash_pgm_blk() - handler to program a block + On entry: + _param_1 = address: uint32_t start address in flash _param_2 = data: uint8_t * to data block to write _param_3 = length: uint32_t length to write - on exit: - _param_1 = true if write status good, otherwise false + on exit: + _param_1 = true if write status good, otherwise false - svc calls to erase and write the flash should not be done in bootloader, use direct erase and write functions + svc calls to erase and write the flash should not be done in bootloader, +use direct erase and write functions **/ void svhandler_flash_pgm_blk(void); /** svhandler_flash_pgm_word() - handler to program a word - On entry: - _param_1 = address: uint32_t start address in flash + On entry: + _param_1 = address: uint32_t start address in flash _param_2 = data: uint32_t of word to write - on exit: - _param_1 = true if write status good, otherwise false + on exit: + _param_1 = true if write status good, otherwise false - svc calls to erase and write the flash should not be done in bootloader, use direct erase and write functions + svc calls to erase and write the flash should not be done in + bootloader, use direct erase and write functions */ void svhandler_flash_pgm_word(void); diff --git a/include/keepkey/board/timer.h b/include/keepkey/board/timer.h index e62ebebbc..ad4321794 100644 --- a/include/keepkey/board/timer.h +++ b/include/keepkey/board/timer.h @@ -20,41 +20,36 @@ #ifndef TIMER_H #define TIMER_H - #include #include - -#define ONE_SEC 1100 /* Count for 1 second */ -#define HALF_SEC 500 /* Count for 0.5 second */ -#define MAX_RUNNABLES 3 /* Max number of queue for task manager */ - +#define ONE_SEC 1100 /* Count for 1 second */ +#define HALF_SEC 500 /* Count for 0.5 second */ +#define MAX_RUNNABLES 3 /* Max number of queue for task manager */ typedef void (*callback_func_t)(void); typedef void (*Runnable)(void *context); typedef struct RunnableNode RunnableNode; -struct RunnableNode -{ - uint32_t remaining; - Runnable runnable; - void *context; - uint32_t period; - bool repeating; - RunnableNode *next; +struct RunnableNode { + uint32_t remaining; + Runnable runnable; + void *context; + uint32_t period; + bool repeating; + RunnableNode *next; }; -typedef struct -{ - RunnableNode *head; - int size; +typedef struct { + RunnableNode *head; + int size; } RunnableQueue; - void timerisr_usr(void); /** - * kk_timer_init() - Timer 4 initialization. Main timer for round robin tasking. + * kk_timer_init() - Timer 4 initialization. Main timer for round robin + *tasking. * * INPUT * none diff --git a/include/keepkey/board/u2f_hid.h b/include/keepkey/board/u2f_hid.h index f29059da2..d79a3106a 100644 --- a/include/keepkey/board/u2f_hid.h +++ b/include/keepkey/board/u2f_hid.h @@ -11,9 +11,9 @@ #define __U2FHID_H_INCLUDED__ #ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else #include @@ -25,20 +25,20 @@ extern "C" { // Size of HID reports -#define HID_RPT_SIZE 64 // Default size of raw HID report +#define HID_RPT_SIZE 64 // Default size of raw HID report // Frame layout - command- and continuation frames -#define CID_BROADCAST 0xffffffff // Broadcast channel id +#define CID_BROADCAST 0xffffffff // Broadcast channel id -#define TYPE_MASK 0x80 // Frame type mask -#define TYPE_INIT 0x80 // Initial frame identifier -#define TYPE_CONT 0x00 // Continuation frame identifier +#define TYPE_MASK 0x80 // Frame type mask +#define TYPE_INIT 0x80 // Initial frame identifier +#define TYPE_CONT 0x00 // Continuation frame identifier typedef struct __attribute__((packed)) { - uint32_t cid; // Channel identifier + uint32_t cid; // Channel identifier union __attribute__((packed)) { - uint8_t type; // Frame type - b7 defines type + uint8_t type; // Frame type - b7 defines type struct __attribute__((packed)) { uint8_t cmd; // Command - b7 set uint8_t bcnth; // Message byte count - high part @@ -53,77 +53,78 @@ typedef struct __attribute__((packed)) { } U2FHID_FRAME; #define FRAME_TYPE(f) ((f).type & TYPE_MASK) -#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) -#define MSG_LEN(f) ((f).init.bcnth*256 + (f).init.bcntl) -#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) +#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) +#define MSG_LEN(f) ((f).init.bcnth * 256 + (f).init.bcntl) +#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) // HID usage- and usage-page definitions -#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page -#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection -#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report -#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report +#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page +#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection +#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report +#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report // General constants -#define U2FHID_IF_VERSION 2 // Current interface implementation version -#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms +#define U2FHID_IF_VERSION 2 // Current interface implementation version +#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms // U2FHID native commands -#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only -#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame -#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command -#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization -#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink -#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command -#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response +#define U2FHID_PING \ + (TYPE_INIT | 0x01) // Echo data through local processor only +#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame +#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command +#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization +#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink +#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command +#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response #define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command -#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command +#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command // U2FHID_INIT command defines -#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge -#define CAPFLAG_WINK 0x01 // Device supports WINK command -#define CAPFLAG_LOCK 0x02 // Device supports LOCK command +#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge +#define CAPFLAG_WINK 0x01 // Device supports WINK command +#define CAPFLAG_LOCK 0x02 // Device supports LOCK command typedef struct __attribute__((packed)) { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce } U2FHID_INIT_REQ; typedef struct __attribute__((packed)) { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce - uint32_t cid; // Channel identifier - uint8_t versionInterface; // Interface version - uint8_t versionMajor; // Major version number - uint8_t versionMinor; // Minor version number - uint8_t versionBuild; // Build version number - uint8_t capFlags; // Capabilities flags + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint32_t cid; // Channel identifier + uint8_t versionInterface; // Interface version + uint8_t versionMajor; // Major version number + uint8_t versionMinor; // Minor version number + uint8_t versionBuild; // Build version number + uint8_t capFlags; // Capabilities flags } U2FHID_INIT_RESP; // U2FHID_SYNC command defines typedef struct __attribute__((packed)) { - uint8_t nonce; // Client application nonce + uint8_t nonce; // Client application nonce } U2FHID_SYNC_REQ; typedef struct __attribute__((packed)) { - uint8_t nonce; // Client application nonce + uint8_t nonce; // Client application nonce } U2FHID_SYNC_RESP; // Low-level error codes. Return as negatives. -#define ERR_NONE 0x00 // No error -#define ERR_INVALID_CMD 0x01 // Invalid command -#define ERR_INVALID_PAR 0x02 // Invalid parameter -#define ERR_INVALID_LEN 0x03 // Invalid message length -#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing -#define ERR_MSG_TIMEOUT 0x05 // Message has timed out -#define ERR_CHANNEL_BUSY 0x06 // Channel busy -#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock -#define ERR_INVALID_CID 0x0b // Message on CID 0 -#define ERR_OTHER 0x7f // Other unspecified error +#define ERR_NONE 0x00 // No error +#define ERR_INVALID_CMD 0x01 // Invalid command +#define ERR_INVALID_PAR 0x02 // Invalid parameter +#define ERR_INVALID_LEN 0x03 // Invalid message length +#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing +#define ERR_MSG_TIMEOUT 0x05 // Message has timed out +#define ERR_CHANNEL_BUSY 0x06 // Channel busy +#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock +#define ERR_INVALID_CID 0x0b // Message on CID 0 +#define ERR_OTHER 0x7f // Other unspecified error #ifdef __cplusplus } diff --git a/include/keepkey/board/usb.h b/include/keepkey/board/usb.h index 2b21535fc..885a5a949 100644 --- a/include/keepkey/board/usb.h +++ b/include/keepkey/board/usb.h @@ -27,7 +27,7 @@ #include #ifndef EMULATOR -# include +#include #endif /* USB Board Config */ @@ -40,18 +40,18 @@ #define NUM_USB_STRINGS (sizeof(usb_strings) / sizeof(usb_strings[0])) /* USB endpoint */ -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) #if DEBUG_LINK -#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) -#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) +#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) #endif -#define ENDPOINT_ADDRESS_U2F_IN (0x83) -#define ENDPOINT_ADDRESS_U2F_OUT (0x03) +#define ENDPOINT_ADDRESS_U2F_IN (0x83) +#define ENDPOINT_ADDRESS_U2F_OUT (0x03) -/* Control buffer for use by the USB stack. We just allocate the +/* Control buffer for use by the USB stack. We just allocate the space for it. */ #define USBD_CONTROL_BUFFER_SIZE 128 diff --git a/include/keepkey/board/usb21_standard.h b/include/keepkey/board/usb21_standard.h index 4f6ccc5eb..7d16fe742 100644 --- a/include/keepkey/board/usb21_standard.h +++ b/include/keepkey/board/usb21_standard.h @@ -23,30 +23,31 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 -#define USB_DT_DEVICE_CAPABILITY 16 +#define USB_DT_BOS 15 +#define USB_DT_DEVICE_CAPABILITY 16 struct usb_device_capability_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; } __attribute__((packed)); struct usb_bos_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumDeviceCaps; - /* Descriptor ends here. The following are used internally: */ - const struct usb_device_capability_descriptor **capabilities; + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; + /* Descriptor ends here. The following are used internally: */ + const struct usb_device_capability_descriptor** capabilities; } __attribute__((packed)); #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_PLATFORM 5 +#define USB_DC_PLATFORM 5 -extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); +extern void usb21_setup(usbd_device* usbd_dev, + const struct usb_bos_descriptor* binary_object_store); #endif #endif diff --git a/include/keepkey/board/util.h b/include/keepkey/board/util.h index 996d60ce0..dd8b51ec7 100644 --- a/include/keepkey/board/util.h +++ b/include/keepkey/board/util.h @@ -25,8 +25,18 @@ #include #include -#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) -#define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#define MIN(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) +#define MAX(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) #define CONCAT_IMPL(A, B) A##B #define CONCAT(A, B) CONCAT_IMPL(A, B) diff --git a/include/keepkey/board/variant.h b/include/keepkey/board/variant.h index 55f6218c9..1599a7379 100644 --- a/include/keepkey/board/variant.h +++ b/include/keepkey/board/variant.h @@ -10,44 +10,43 @@ #define VARIANTINFO_MAGIC "KKWL" typedef struct Image_ { - uint16_t w; - uint16_t h; - uint32_t length; - const uint8_t *data; + uint16_t w; + uint16_t h; + uint32_t length; + const uint8_t *data; } Image; typedef struct AnimationFrame_ { - uint16_t x; - uint16_t y; - uint16_t duration; - uint8_t color; - const Image *image; + uint16_t x; + uint16_t y; + uint16_t duration; + uint8_t color; + const Image *image; } AnimationFrame; typedef struct VariantAnimation_ { - uint16_t count; - AnimationFrame frames[]; + uint16_t count; + AnimationFrame frames[]; } VariantAnimation; typedef struct VariantInfo_ { - uint16_t version; - const char *name; - const VariantAnimation *logo; - const VariantAnimation *logo_reversed; - uint32_t screensaver_timeout; // DEPRECATED - const VariantAnimation *screensaver; + uint16_t version; + const char *name; + const VariantAnimation *logo; + const VariantAnimation *logo_reversed; + uint32_t screensaver_timeout; // DEPRECATED + const VariantAnimation *screensaver; } VariantInfo; typedef struct SignedVariantInfo_ { - app_meta_td meta; - VariantInfo info; + app_meta_td meta; + VariantInfo info; } SignedVariantInfo; typedef enum Model_ { - MODEL_UNKNOWN, - #define MODEL_ENTRY(STRING, ENUM) \ - MODEL_ ##ENUM, - #include "keepkey/board/models.def" + MODEL_UNKNOWN, +#define MODEL_ENTRY(STRING, ENUM) MODEL_##ENUM, +#include "keepkey/board/models.def" } Model; /// Get the model of the device (Keepkey/SALT/etc) diff --git a/include/keepkey/board/webusb.h b/include/keepkey/board/webusb.h index beea8fa1f..a3699ea38 100644 --- a/include/keepkey/board/webusb.h +++ b/include/keepkey/board/webusb.h @@ -26,8 +26,10 @@ // Arbitrary #define WEBUSB_VENDOR_CODE 0x01 -extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; -extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page; +extern const struct webusb_platform_descriptor + webusb_platform_capability_descriptor; +extern const struct webusb_platform_descriptor + webusb_platform_capability_descriptor_no_landing_page; extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); diff --git a/include/keepkey/board/webusb_defs.h b/include/keepkey/board/webusb_defs.h index 45b5f2478..b8566f12c 100644 --- a/include/keepkey/board/webusb_defs.h +++ b/include/keepkey/board/webusb_defs.h @@ -21,7 +21,7 @@ #include -#define WEBUSB_REQ_GET_URL 0x02 +#define WEBUSB_REQ_GET_URL 0x02 #define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 #define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 @@ -32,28 +32,33 @@ #define WEBUSB_URL_SCHEME_HTTPS 1 struct webusb_platform_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - uint8_t bReserved; - uint8_t platformCapabilityUUID[16]; - uint16_t bcdVersion; - uint8_t bVendorCode; - uint8_t iLandingPage; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t platformCapabilityUUID[16]; + uint16_t bcdVersion; + uint8_t bVendorCode; + uint8_t iLandingPage; } __attribute__((packed)); -#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) +#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE \ + sizeof(struct webusb_platform_descriptor) // from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor // see also this (for endianness explanation) // https://github.com/WICG/webusb/issues/115#issuecomment-352206549 -#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} +#define WEBUSB_UUID \ + { \ + 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, \ + 0x88, 0x15, 0xB6, 0x65 \ + } struct webusb_url_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bScheme; - char URL[]; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char URL[]; } __attribute__((packed)); #define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 diff --git a/include/keepkey/board/winusb.h b/include/keepkey/board/winusb.h index df52804ec..0e59a1de3 100644 --- a/include/keepkey/board/winusb.h +++ b/include/keepkey/board/winusb.h @@ -25,7 +25,8 @@ typedef struct _usbd_device usbd_device; // Arbitrary, but must be equivalent to the last character in extra string #define WINUSB_MS_VENDOR_CODE '!' -#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} +#define WINUSB_EXTRA_STRING \ + { 'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE } extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); diff --git a/include/keepkey/board/winusb_defs.h b/include/keepkey/board/winusb_defs.h index 830e6b154..dd779b857 100644 --- a/include/keepkey/board/winusb_defs.h +++ b/include/keepkey/board/winusb_defs.h @@ -30,60 +30,65 @@ // Apparently using DeviceInterfaceGUID does not always work on Windows 7. // DeviceInterfaceGUIDs does seem to work. -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C \ + sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U \ + (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) // extra null is intentional - it's an array of GUIDs with 1 item -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) -#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA \ + u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C \ + sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U \ + (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 #define WINUSB_EXTRA_STRING_INDEX 0xee /* Table 2. Function Section */ struct winusb_compatible_id_function_section { - uint8_t bInterfaceNumber; - uint8_t reserved0[1]; - char compatibleId[8]; - char subCompatibleId[8]; - uint8_t reserved1[6]; + uint8_t bInterfaceNumber; + uint8_t reserved0[1]; + char compatibleId[8]; + char subCompatibleId[8]; + uint8_t reserved1[6]; } __attribute__((packed)); /* Table 1. Header Section */ struct winusb_compatible_id_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint8_t bNumSections; - uint8_t reserved[7]; + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bNumSections; + uint8_t reserved[7]; } __attribute__((packed)); struct winusb_compatible_id_descriptor { - struct winusb_compatible_id_descriptor_header header; - struct winusb_compatible_id_function_section functions[]; + struct winusb_compatible_id_descriptor_header header; + struct winusb_compatible_id_function_section functions[]; } __attribute__((packed)); struct winusb_extended_properties_feature_descriptor { - uint32_t dwLength; - uint32_t dwPropertyDataType; - uint16_t wNameLength; - uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; - uint32_t dwPropertyDataLength; - uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint16_t wNameLength; + uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; + uint32_t dwPropertyDataLength; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; } __attribute__((packed)); struct winusb_extended_properties_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint16_t wNumFeatures; + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wNumFeatures; } __attribute__((packed)); struct winusb_extended_properties_descriptor { - struct winusb_extended_properties_descriptor_header header; - struct winusb_extended_properties_feature_descriptor features[]; + struct winusb_extended_properties_descriptor_header header; + struct winusb_extended_properties_feature_descriptor features[]; } __attribute__((packed)); #endif diff --git a/include/keepkey/bootloader/bootloader_main.h b/include/keepkey/bootloader/bootloader_main.h index 0afe2e898..5cbf079b7 100644 --- a/include/keepkey/bootloader/bootloader_main.h +++ b/include/keepkey/bootloader/bootloader_main.h @@ -20,10 +20,8 @@ #ifndef BOOTLOADER_MAIN_H #define BOOTLOADER_MAIN_H - typedef void (*app_entry_t)(void); - bool check_fw_is_new(void); #endif \ No newline at end of file diff --git a/include/keepkey/bootloader/usb_flash.h b/include/keepkey/bootloader/usb_flash.h index d7e4ceb2c..e32731b2f 100644 --- a/include/keepkey/bootloader/usb_flash.h +++ b/include/keepkey/bootloader/usb_flash.h @@ -20,49 +20,46 @@ #ifndef USB_FLASH_H #define USB_FLASH_H - #include "keepkey/board/messages.h" #include #include +#define RESP_INIT(TYPE) \ + TYPE resp; \ + memset(&resp, 0, sizeof(TYPE)); -#define RESP_INIT(TYPE) TYPE resp; memset(&resp, 0, sizeof(TYPE)); - -#define UPLOAD_STATUS_FREQUENCY 1024 -#define PROTOBUF_FIRMWARE_HASH_START 2 -#define PROTOBUF_FIRMWARE_START 38 +#define UPLOAD_STATUS_FREQUENCY 1024 +#define PROTOBUF_FIRMWARE_HASH_START 2 +#define PROTOBUF_FIRMWARE_START 38 -#define FILL_CONFIG_DATA 0xaa +#define FILL_CONFIG_DATA 0xaa - -typedef enum -{ - UPLOAD_NOT_STARTED, - UPLOAD_STARTED, - UPLOAD_COMPLETE, - UPLOAD_ERROR +typedef enum { + UPLOAD_NOT_STARTED, + UPLOAD_STARTED, + UPLOAD_COMPLETE, + UPLOAD_ERROR } FirmwareUploadState; /* Generic message handler callback type */ -typedef void (*message_handler_t)(void* msg_struct); - +typedef void (*message_handler_t)(void* msg_struct); bool usb_flash_firmware(void); void storage_sectorInit(void); -void send_success(const char *text); -void send_failure(FailureType code, const char *text); +void send_success(const char* text); +void send_failure(FailureType code, const char* text); void handler_initialize(Initialize* msg); void handler_get_features(GetFeatures* msg); void handler_ping(Ping* msg); void handler_erase(FirmwareErase* msg); void handler_wipe(WipeDevice* msg); -void raw_handler_upload(RawMessage *msg, uint32_t frame_length); +void raw_handler_upload(RawMessage* msg, uint32_t frame_length); #if DEBUG_LINK -void handler_debug_link_get_state(DebugLinkGetState *msg); -void handler_debug_link_stop(DebugLinkStop *msg); -void handler_debug_link_fill_config(DebugLinkFillConfig *msg); +void handler_debug_link_get_state(DebugLinkGetState* msg); +void handler_debug_link_stop(DebugLinkStop* msg); +void handler_debug_link_fill_config(DebugLinkFillConfig* msg); #endif #endif diff --git a/include/keepkey/crypto/curves.h b/include/keepkey/crypto/curves.h index adb59f04f..57c6d9c1f 100644 --- a/include/keepkey/crypto/curves.h +++ b/include/keepkey/crypto/curves.h @@ -25,7 +25,7 @@ #define SECP256K1_STRING "secp256k1" #define NIST256P1_STRING "nist256p1" -#define ED25519_STRING "ed25519" +#define ED25519_STRING "ed25519" extern const char SECP256K1_NAME[]; extern const char NIST256P1_NAME[]; diff --git a/include/keepkey/firmware/app_confirm.h b/include/keepkey/firmware/app_confirm.h index 74b59b00b..e0425034a 100644 --- a/include/keepkey/firmware/app_confirm.h +++ b/include/keepkey/firmware/app_confirm.h @@ -32,12 +32,15 @@ bool confirm_cipher(bool encrypt, const char *key); bool confirm_encrypt_msg(const char *msg, bool signing); bool confirm_decrypt_msg(const char *msg, const char *address); bool confirm_exchange_output(const char *from_amount, const char *to_amount); -bool confirm_transfer_output(ButtonRequestType button_request, const char *amount, const char *to); -bool confirm_transaction_output(ButtonRequestType button_request, const char *amount, const char *to); +bool confirm_transfer_output(ButtonRequestType button_request, + const char *amount, const char *to); +bool confirm_transaction_output(ButtonRequestType button_request, + const char *amount, const char *to); bool confirm_transaction_output_no_bold(ButtonRequestType button_request, const char *amount, const char *to); -bool confirm_erc_token_transfer(ButtonRequestType button_request, const char *msg_body); +bool confirm_erc_token_transfer(ButtonRequestType button_request, + const char *msg_body); bool confirm_transaction(const char *total_amount, const char *fee); bool confirm_load_device(bool is_node); @@ -46,6 +49,8 @@ bool confirm_xpub(const char *node_str, const char *xpub); bool confirm_sign_identity(const IdentityType *identity, const char *challenge); bool confirm_ethereum_address(const char *desc, const char *address); bool confirm_nano_address(const char *desc, const char *address); -bool confirm_omni(ButtonRequestType button_request, const char *title, const uint8_t *data, uint32_t size); -bool confirm_data(ButtonRequestType button_request, const char *title, const uint8_t *data, uint32_t size); +bool confirm_omni(ButtonRequestType button_request, const char *title, + const uint8_t *data, uint32_t size); +bool confirm_data(ButtonRequestType button_request, const char *title, + const uint8_t *data, uint32_t size); #endif diff --git a/include/keepkey/firmware/app_layout.h b/include/keepkey/firmware/app_layout.h index 85b85ed7f..cac92bdfb 100644 --- a/include/keepkey/firmware/app_layout.h +++ b/include/keepkey/firmware/app_layout.h @@ -20,25 +20,23 @@ #ifndef APP_LAYOUT_H #define APP_LAYOUT_H - #include "keepkey/board/canvas.h" #include "keepkey/board/resources.h" #include "keepkey/board/draw.h" #include - /* Screen Test */ -#define TEST_COLOR 0xFF -#define TEST_X 1 -#define TEST_Y 1 -#define TEST_WIDTH 256 -#define TEST_HEIGHT 64 +#define TEST_COLOR 0xFF +#define TEST_X 1 +#define TEST_Y 1 +#define TEST_WIDTH 256 +#define TEST_HEIGHT 64 /* Transaction */ -#define TRANSACTION_TOP_MARGIN 4 -#define TRANSACTION_WIDTH 250 -#define NO_TITLE_WIDTH 250 +#define TRANSACTION_TOP_MARGIN 4 +#define TRANSACTION_WIDTH 250 +#define NO_TITLE_WIDTH 250 /* PIN Matrix */ #define MATRIX_MASK_COLOR 0x00 @@ -53,60 +51,52 @@ #define PIN_MATRIX_FOREGROUND 0xFF #define PIN_SLIDE_DELAY 20 #define PIN_MAX_ANIMATION_MS 1000 -#define PIN_LEFT_MARGIN 140 +#define PIN_LEFT_MARGIN 195 /* Recovery Cypher */ -#define CIPHER_ROWS 2 -#define CIPHER_LETTER_BY_ROW 13 -#define CIPHER_GRID_SIZE 13 -#define CIPHER_GRID_SPACING 1 -#define CIPHER_ANIMATION_FREQUENCY_MS 10 -#define CIPHER_STEP_1 0X22 -#define CIPHER_STEP_2 0X33 -#define CIPHER_STEP_3 0X55 -#define CIPHER_STEP_4 0X77 -#define CIPHER_FOREGROUND 0X99 -#define CIPHER_START_X 76 -#define CIPHER_START_Y 3 -#define CIPHER_MASK_COLOR 0x00 -#define CIPHER_FONT_COLOR 0x99 -#define CIPHER_MAP_FONT_COLOR 0xFF -#define CIPHER_HORIZONTAL_MASK_WIDTH 181 -#define CIPHER_HORIZONTAL_MASK_WIDTH_3 3 +#define CIPHER_ROWS 2 +#define CIPHER_LETTER_BY_ROW 13 +#define CIPHER_GRID_SIZE 13 +#define CIPHER_GRID_SPACING 1 +#define CIPHER_ANIMATION_FREQUENCY_MS 10 +#define CIPHER_STEP_1 0X22 +#define CIPHER_STEP_2 0X33 +#define CIPHER_STEP_3 0X55 +#define CIPHER_STEP_4 0X77 +#define CIPHER_FOREGROUND 0X99 +#define CIPHER_START_X 76 +#define CIPHER_START_Y 3 +#define CIPHER_MASK_COLOR 0x00 +#define CIPHER_FONT_COLOR 0x99 +#define CIPHER_MAP_FONT_COLOR 0xFF +#define CIPHER_HORIZONTAL_MASK_WIDTH 181 +#define CIPHER_HORIZONTAL_MASK_WIDTH_3 3 #define CIPHER_HORIZONTAL_MASK_HEIGHT_2 2 #define CIPHER_HORIZONTAL_MASK_HEIGHT_3 3 #define CIPHER_HORIZONTAL_MASK_HEIGHT_4 4 /* QR */ -#define ADDRESS_TOP_MARGIN 16 +#define ADDRESS_TOP_MARGIN 16 #define ADDRESS_XPUB_TOP_MARGIN 14 -#define MULTISIG_LEFT_MARGIN 40 -#define QR_DISPLAY_SCALE 1 -#define QR_DISPLAY_X 4 -#define QR_DISPLAY_Y 10 - - -typedef enum -{ - SLIDE_DOWN, - SLIDE_LEFT, - SLIDE_UP, - SLIDE_RIGHT +#define MULTISIG_LEFT_MARGIN 40 +#define QR_DISPLAY_SCALE 1 +#define QR_DISPLAY_X 4 +#define QR_DISPLAY_Y 10 + +typedef enum { + SLIDE_DOWN, + SLIDE_LEFT, + SLIDE_UP, + SLIDE_RIGHT } PINAnimationDirection; -typedef enum -{ - QR_LARGE, - QR_SMALL -} QRSize; +typedef enum { QR_LARGE, QR_SMALL } QRSize; -typedef struct -{ - PINAnimationDirection direction; - uint32_t elapsed_start_ms; +typedef struct { + PINAnimationDirection direction; + uint32_t elapsed_start_ms; } PINAnimationConfig; - void layout_screen_test(void); void layout_screensaver(void); void layout_tx_info(const char *address, uint64_t amount_in_satoshi); @@ -115,13 +105,13 @@ void layout_notification_no_title(const char *title, const char *body, void layout_notification_no_title_bold(const char *title, const char *body, NotificationType type); void layout_notification_no_title_no_bold(const char *title, const char *body, - NotificationType type); + NotificationType type); void layout_xpub_notification(const char *desc, const char *xpub, NotificationType type); void layout_address_notification(const char *desc, const char *address, NotificationType type); void layout_ethereum_address_notification(const char *desc, const char *address, - NotificationType type); + NotificationType type); void layout_nano_address_notification(const char *desc, const char *address, NotificationType type); void layout_pin(const char *prompt, char *pin); @@ -129,6 +119,7 @@ void layout_cipher(const char *current_word, const char *cipher); void layout_address(const char *address, QRSize qr_size); void set_leaving_handler(leaving_handler_t leaving_func); -void layoutU2FDialog(bool request, const char *title, const char *body, ...) __attribute__((format(printf, 3, 4))); +void layoutU2FDialog(bool request, const char *title, const char *body, ...) + __attribute__((format(printf, 3, 4))); #endif diff --git a/include/keepkey/firmware/binance.h b/include/keepkey/firmware/binance.h index b16c877f3..dffcad6e6 100644 --- a/include/keepkey/firmware/binance.h +++ b/include/keepkey/firmware/binance.h @@ -16,8 +16,7 @@ bool binance_signTxInit(const HDNode *node, const BinanceSignTx *msg); bool binance_serializeCoin(const BinanceCoin *coin); bool binance_serializeInputOutput(const BinanceInputOutput *io); bool binance_signTxUpdateTransfer(const BinanceTransferMsg *msg); -bool binance_signTxUpdateMsgSend(const uint64_t amount, - const char *to_address); +bool binance_signTxUpdateMsgSend(const uint64_t amount, const char *to_address); bool binance_signTxFinalize(uint8_t *public_key, uint8_t *signature); bool binance_signingIsInited(void); bool binance_signingIsFinished(void); diff --git a/include/keepkey/firmware/coins.h b/include/keepkey/firmware/coins.h index 096dbf1e4..61e2cc88d 100644 --- a/include/keepkey/firmware/coins.h +++ b/include/keepkey/firmware/coins.h @@ -23,47 +23,36 @@ #include "keepkey/transport/interface.h" #include "keepkey/board/util.h" -#define NA 0xFFFF /*etherum does not use P2PH or P2SH */ -#define ETHEREUM "Ethereum" -#define ETHEREUM_CLS "ETH Classic" -#define ETHEREUM_TST "ETH Testnet" +#define NA 0xFFFF /*etherum does not use P2PH or P2SH */ +#define ETHEREUM "Ethereum" +#define ETHEREUM_CLS "ETH Classic" +#define ETHEREUM_TST "ETH Testnet" enum { -#define X(\ -HAS_COIN_NAME, COIN_NAME, \ -HAS_COIN_SHORTCUT, COIN_SHORTCUT, \ -HAS_ADDRESS_TYPE, ADDRESS_TYPE, \ -HAS_MAXFEE_KB, MAXFEE_KB, \ -HAS_ADDRESS_TYPE_P2SH, ADDRESS_TYPE_P2SH, \ -HAS_SIGNED_MESSAGE_HEADER, SIGNED_MESSAGE_HEADER, \ -HAS_BIP44_ACCOUNT_PATH, BIP44_ACCOUNT_PATH, \ -HAS_FORKID, FORKID, \ -HAS_DECIMALS, DECIMALS, \ -HAS_CONTRACT_ADDRESS, CONTRACT_ADDRESS, \ -HAS_XPUB_MAGIC, XPUB_MAGIC, \ -HAS_SEGWIT, SEGWIT , \ -HAS_FORCE_BIP143, FORCE_BIP143, \ -HAS_CURVE_NAME, CURVE_NAME, \ -HAS_CASHADDR_PREFIX, CASHADDR_PREFIX, \ -HAS_BECH32_PREFIX, BECH32_PREFIX, \ -HAS_DECRED, DECRED , \ -HAS_XPUB_MAGIC_SEGWIT_P2SH, XPUB_MAGIC_SEGWIT_P2SH, \ -HAS_XPUB_MAGIC_SEGWIT_NATIVE, XPUB_MAGIC_SEGWIT_NATIVE, \ -HAS_NANOADDR_PREFIX, NANOADDR_PREFIX \ -) \ - CONCAT(CoinIndex, __COUNTER__), +#define X(HAS_COIN_NAME, COIN_NAME, HAS_COIN_SHORTCUT, COIN_SHORTCUT, \ + HAS_ADDRESS_TYPE, ADDRESS_TYPE, HAS_MAXFEE_KB, MAXFEE_KB, \ + HAS_ADDRESS_TYPE_P2SH, ADDRESS_TYPE_P2SH, HAS_SIGNED_MESSAGE_HEADER, \ + SIGNED_MESSAGE_HEADER, HAS_BIP44_ACCOUNT_PATH, BIP44_ACCOUNT_PATH, \ + HAS_FORKID, FORKID, HAS_DECIMALS, DECIMALS, HAS_CONTRACT_ADDRESS, \ + CONTRACT_ADDRESS, HAS_XPUB_MAGIC, XPUB_MAGIC, HAS_SEGWIT, SEGWIT, \ + HAS_FORCE_BIP143, FORCE_BIP143, HAS_CURVE_NAME, CURVE_NAME, \ + HAS_CASHADDR_PREFIX, CASHADDR_PREFIX, HAS_BECH32_PREFIX, \ + BECH32_PREFIX, HAS_DECRED, DECRED, HAS_XPUB_MAGIC_SEGWIT_P2SH, \ + XPUB_MAGIC_SEGWIT_P2SH, HAS_XPUB_MAGIC_SEGWIT_NATIVE, \ + XPUB_MAGIC_SEGWIT_NATIVE, HAS_NANOADDR_PREFIX, NANOADDR_PREFIX) \ + CONCAT(CoinIndex, __COUNTER__), #include "keepkey/firmware/coins.def" #define X(INDEX, NAME, SYMBOL, DECIMALS, CONTRACT_ADDRESS) \ - CONCAT(CoinIndex, __COUNTER__), + CONCAT(CoinIndex, __COUNTER__), #include "keepkey/firmware/tokens.def" - CoinIndexLast, - CoinIndexFirst = 0 + CoinIndexLast, + CoinIndexFirst = 0 }; -#define COINS_COUNT ((int)CoinIndexLast-(int)CoinIndexFirst) -#define NODE_STRING_LENGTH 50 +#define COINS_COUNT ((int)CoinIndexLast - (int)CoinIndexFirst) +#define NODE_STRING_LENGTH 50 #define COIN_FRACTION 100000000 @@ -78,7 +67,8 @@ const CoinType *coinBySlip44(uint32_t bip44_account_path); void coin_amnt_to_str(const CoinType *coin, uint64_t amnt, char *buf, int len); /// \brief Parses node path to precise BIP32 equivalent string -bool bip32_path_to_string(char *str, size_t len, const uint32_t *address_n, size_t address_n_count); +bool bip32_path_to_string(char *str, size_t len, const uint32_t *address_n, + size_t address_n_count); /** * \brief Parses node path to human-friendly BIP32 equivalent string @@ -89,9 +79,10 @@ bool bip32_path_to_string(char *str, size_t len, const uint32_t *address_n, size * \param[in] coin coin to use to determine bip44 path * \param[in] address_n node path * \param[in] address_n_count size of address_n array - * \param[in] whole_account true iff address_n refers to an entire account (not just an address) - * \param[in] show_addridx whether to display address indexes - * \returns true iff the path matches a known bip44/bip49/bip84/etc account + * \param[in] whole_account true iff address_n refers to an entire account + * (not just an address) \param[in] show_addridx whether to display + * address indexes \returns true iff the path matches a known + * bip44/bip49/bip84/etc account */ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, const uint32_t *address_n, size_t address_n_count, diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index 913632273..f6b86f063 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -10,8 +10,7 @@ typedef struct _CosmosSignTx CosmosSignTx; bool cosmos_signTxInit(const HDNode *_node, const CosmosSignTx *_msg); -bool cosmos_signTxUpdateMsgSend(const uint64_t amount, - const char *to_address); +bool cosmos_signTxUpdateMsgSend(const uint64_t amount, const char *to_address); bool cosmos_signTxFinalize(uint8_t *public_key, uint8_t *signature); bool cosmos_signingIsInited(void); bool cosmos_signingIsFinished(void); diff --git a/include/keepkey/firmware/crypto.h b/include/keepkey/firmware/crypto.h index 319bf668c..58a2a5bc6 100644 --- a/include/keepkey/firmware/crypto.h +++ b/include/keepkey/firmware/crypto.h @@ -36,31 +36,41 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(Hasher *hasher, uint32_t len); uint32_t deser_length(const uint8_t *in, uint32_t *out); -int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature); -int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature); -int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); +int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key); -int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinType *coin, HDNode *node, + InputScriptType script_type, const uint8_t *message, + size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature); +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, + size_t message_len, const char *address, + const uint8_t *signature); /* ECIES disabled // ECIES: http://memwallet.info/btcmssgs.html -int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, - bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, - size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, - const uint8_t *address_raw); -int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, - const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, - size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t +msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t +*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t +*privkey, const uint8_t *address_raw); int cryptoMessageDecrypt(curve_point +*nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t +hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool +*display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const CoinType *coin, const HDNodePathType *hdnodepath); -int cryptoMultisigPubkeyIndex(const CoinType *coin, const MultisigRedeemScriptType *multisig, +uint8_t *cryptoHDNodePathToPubkey(const CoinType *coin, + const HDNodePathType *hdnodepath); +int cryptoMultisigPubkeyIndex(const CoinType *coin, + const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); -int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, + uint8_t *hash); int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash); #endif diff --git a/include/keepkey/firmware/eos.h b/include/keepkey/firmware/eos.h index 87e3643c4..b905fb162 100644 --- a/include/keepkey/firmware/eos.h +++ b/include/keepkey/firmware/eos.h @@ -27,31 +27,31 @@ #include #include -#define EOS_NAME_STR_SIZE (12 + 1 + 1) +#define EOS_NAME_STR_SIZE (12 + 1 + 1) #define EOS_ASSET_STR_SIZE (1 + 21 + 1 + 12 + 1) // C++ constexpr would be neat here... typedef enum _EosActionName { - EOS_Transfer = 0xcdcd3c2d57000000L, - EOS_Owner = 0xa726ab8000000000L, - EOS_Active = 0x3232eda800000000L, - EOS_DelegateBW = 0x4aa2a61b2a3f0000L, - EOS_UndelegateBW = 0xd4d2a8a986ca8fc0L, - EOS_Refund = 0xba97a9a400000000L, - EOS_BuyRam = 0x3ebd734800000000L, - EOS_BuyRamBytes = 0x3ebd7348fecab000L, - EOS_SellRam = 0xc2a31b9a40000000L, - EOS_VoteProducer = 0xdd32aade89d21570L, - EOS_UpdateAuth = 0xd5526ca8dacb4000L, - EOS_DeleteAuth = 0x4aa2aca8dacb4000L, - EOS_LinkAuth = 0x8ba7036b2d000000L, - EOS_UnlinkAuth = 0xd4e2e9c0dacb4000L, - EOS_NewAccount = 0x9ab864229a9e4000L, + EOS_Transfer = 0xcdcd3c2d57000000L, + EOS_Owner = 0xa726ab8000000000L, + EOS_Active = 0x3232eda800000000L, + EOS_DelegateBW = 0x4aa2a61b2a3f0000L, + EOS_UndelegateBW = 0xd4d2a8a986ca8fc0L, + EOS_Refund = 0xba97a9a400000000L, + EOS_BuyRam = 0x3ebd734800000000L, + EOS_BuyRamBytes = 0x3ebd7348fecab000L, + EOS_SellRam = 0xc2a31b9a40000000L, + EOS_VoteProducer = 0xdd32aade89d21570L, + EOS_UpdateAuth = 0xd5526ca8dacb4000L, + EOS_DeleteAuth = 0x4aa2aca8dacb4000L, + EOS_LinkAuth = 0x8ba7036b2d000000L, + EOS_UnlinkAuth = 0xd4e2e9c0dacb4000L, + EOS_NewAccount = 0x9ab864229a9e4000L, } EosActionName; typedef enum _EosContractName { - EOS_eosio = 0x5530ea0000000000L, - EOS_eosio_token = 0x5530ea033482a600L, + EOS_eosio = 0x5530ea0000000000L, + EOS_eosio_token = 0x5530ea033482a600L, } EosContractName; /// \returns true iff the asset can be correctly decoded. diff --git a/include/keepkey/firmware/ethereum.h b/include/keepkey/firmware/ethereum.h index 58375f88f..41deeb13a 100644 --- a/include/keepkey/firmware/ethereum.h +++ b/include/keepkey/firmware/ethereum.h @@ -33,7 +33,8 @@ typedef struct _EthereumMessageSignature EthereumMessageSignature; typedef struct _TokenType TokenType; typedef struct _CoinType CoinType; -void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node, bool needs_confirm); +void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node, + bool needs_confirm); void ethereum_signing_abort(void); void ethereum_signing_txack(EthereumTxAck *msg); void format_ethereum_address(const uint8_t *to, char *destination_str, @@ -42,7 +43,8 @@ bool ethereum_isStandardERC20Transfer(const EthereumSignTx *msg); /// \pre requires that `ethereum_isStandardERC20Transfer(msg)` /// \returns true iff successful -bool ethereum_getStandardERC20Recipient(const EthereumSignTx *msg, char *address, size_t len); +bool ethereum_getStandardERC20Recipient(const EthereumSignTx *msg, + char *address, size_t len); /// \pre requires that `ethereum_isStandardERC20Transfer(msg)` /// \returns true iff successful @@ -50,19 +52,23 @@ bool ethereum_getStandardERC20Coin(const EthereumSignTx *msg, CoinType *coin); /// \pre requires that `ethereum_isStandardERC20Transfer(msg)` /// \returns true iff successful -bool ethereum_getStandardERC20Amount(const EthereumSignTx *msg, void **tx_out_amount); +bool ethereum_getStandardERC20Amount(const EthereumSignTx *msg, + void **tx_out_amount); /** * \brief Get the number of decimals associated with an erc20 token - * \param token_shorcut String corresponding to a token_shortcut in coins table in coins.c - * \returns uint32_t The number of decimals to interpret the token with + * \param token_shorcut String corresponding to a token_shortcut in coins + * table in coins.c \returns uint32_t The number of decimals to interpret + * the token with */ uint32_t ethereum_get_decimal(const char *token_shortcut); -void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, + EthereumMessageSignature *resp); int ethereum_message_verify(const EthereumVerifyMessage *msg); -void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, uint32_t chain_id, char *buf, int buflen); +void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, + uint32_t chain_id, char *buf, int buflen); void bn_from_bytes(const uint8_t *value, size_t value_len, bignum256 *val); diff --git a/include/keepkey/firmware/ethereum_tokens.h b/include/keepkey/firmware/ethereum_tokens.h index 5b7143d14..7081b28b7 100644 --- a/include/keepkey/firmware/ethereum_tokens.h +++ b/include/keepkey/firmware/ethereum_tokens.h @@ -27,19 +27,19 @@ enum { #define X(CHAIN_ID, CONTRACT_ADDR, TICKER, DECIMALS) \ - CONCAT(TokenIndex, __COUNTER__), + CONCAT(TokenIndex, __COUNTER__), #include "keepkey/firmware/ethereum_tokens.def" - TokenIndexLast, - TokenIndexFirst = 0 + TokenIndexLast, + TokenIndexFirst = 0 }; -#define TOKENS_COUNT ((int)TokenIndexLast-(int)TokenIndexFirst) +#define TOKENS_COUNT ((int)TokenIndexLast - (int)TokenIndexFirst) typedef struct _TokenType { - const char * const address; - const char * const ticker; - uint8_t chain_id; - uint8_t decimals; + const char *const address; + const char *const ticker; + uint8_t chain_id; + uint8_t decimals; } TokenType; typedef struct _CoinType CoinType; @@ -50,7 +50,8 @@ extern const TokenType *UnknownToken; const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address); -/// Tokens don't have unique tickers, so this might not return the one you're looking for :/ +/// Tokens don't have unique tickers, so this might not return the one you're +/// looking for :/ /// /// This is necessary because the way the KeepKey client handles TRANSFER /// messages, relying on the ticker to uniquely identify the token... which is a @@ -58,8 +59,10 @@ const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address); /// EthereumSignTx message, and get rid of this function. /// /// \param[out] token The found token, assuming it was uniquely determinable. -/// \returns true iff the token can be uniquely found in the list of known tokens. -bool tokenByTicker(uint8_t chain_id, const char *ticker, const TokenType **token); +/// \returns true iff the token can be uniquely found in the list of known +/// tokens. +bool tokenByTicker(uint8_t chain_id, const char *ticker, + const TokenType **token); void coinFromToken(CoinType *coin, const TokenType *token); #endif diff --git a/include/keepkey/firmware/exchange.h b/include/keepkey/firmware/exchange.h index 75397a090..e93df943c 100644 --- a/include/keepkey/firmware/exchange.h +++ b/include/keepkey/firmware/exchange.h @@ -21,22 +21,23 @@ #define EXCHANGE_H typedef enum { - NO_EXCHANGE_ERROR, - ERROR_EXCHANGE_SIGNATURE, - ERROR_EXCHANGE_DEPOSIT_COINTYPE, - ERROR_EXCHANGE_DEPOSIT_ADDRESS, - ERROR_EXCHANGE_DEPOSIT_AMOUNT, - ERROR_EXCHANGE_WITHDRAWAL_COINTYPE, - ERROR_EXCHANGE_WITHDRAWAL_ADDRESS, - ERROR_EXCHANGE_WITHDRAWAL_AMOUNT, - ERROR_EXCHANGE_RETURN_COINTYPE, - ERROR_EXCHANGE_RETURN_ADDRESS, - ERROR_EXCHANGE_CANCEL, - ERROR_EXCHANGE_RESPONSE_STRUCTURE, - ERROR_EXCHANGE_TYPE, + NO_EXCHANGE_ERROR, + ERROR_EXCHANGE_SIGNATURE, + ERROR_EXCHANGE_DEPOSIT_COINTYPE, + ERROR_EXCHANGE_DEPOSIT_ADDRESS, + ERROR_EXCHANGE_DEPOSIT_AMOUNT, + ERROR_EXCHANGE_WITHDRAWAL_COINTYPE, + ERROR_EXCHANGE_WITHDRAWAL_ADDRESS, + ERROR_EXCHANGE_WITHDRAWAL_AMOUNT, + ERROR_EXCHANGE_RETURN_COINTYPE, + ERROR_EXCHANGE_RETURN_ADDRESS, + ERROR_EXCHANGE_CANCEL, + ERROR_EXCHANGE_RESPONSE_STRUCTURE, + ERROR_EXCHANGE_TYPE, } ExchangeError; -bool process_exchange_contract(const CoinType *coin, void *vtx_out, const HDNode *root, bool needs_confirm); +bool process_exchange_contract(const CoinType *coin, void *vtx_out, + const HDNode *root, bool needs_confirm); ExchangeError get_exchange_error(void); #if DEBUG_LINK @@ -44,7 +45,8 @@ const char *get_exchange_msg(void); #endif #if DEBUG_LINK -#define set_exchange_error(error_code) set_exchange_errorDebug((error_code), __FILE__ ":" VERSTR(__LINE__) ":") +#define set_exchange_error(error_code) \ + set_exchange_errorDebug((error_code), __FILE__ ":" VERSTR(__LINE__) ":") void set_exchange_errorDebug(ExchangeError error_code, const char *msg); #else void set_exchange_error(ExchangeError error_code); @@ -54,12 +56,13 @@ bool ether_for_display(const uint8_t *value, uint32_t value_len, char *out_str); /** * \brief Format an ethereum token value with the proper number of decimals - * \param value The token value interpreted as a 32byte big endian number - * \param value_len Length in bytes of value - * \param decimal The number of decimals to format this token amount to - * \param out_str 128 byte buffer to store string result - * \returns boolean representing wethere the token value was successfully formatted + * \param value The token value interpreted as a 32byte big endian + * number \param value_len Length in bytes of value \param decimal The + * number of decimals to format this token amount to \param out_str 128 + * byte buffer to store string result \returns boolean representing + * wethere the token value was successfully formatted */ -bool ether_token_for_display(const uint8_t *value, uint32_t value_len, uint32_t decimal, char *out_str, size_t out_len); +bool ether_token_for_display(const uint8_t *value, uint32_t value_len, + uint32_t decimal, char *out_str, size_t out_len); #endif diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index ea0b59cbe..a093e4270 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -23,15 +23,15 @@ #include "keepkey/transport/interface.h" #include "keepkey/board/messages.h" -#define RESP_INIT(TYPE) \ - TYPE *resp = (TYPE *)msg_resp; \ - _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE" is too large"); \ - memset(resp, 0, sizeof(TYPE)); +#define RESP_INIT(TYPE) \ + TYPE *resp = (TYPE *)msg_resp; \ + _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ + memset(resp, 0, sizeof(TYPE)); #define ENTROPY_BUF sizeof(((Entropy *)NULL)->entropy.bytes) -#define BTC_ADDRESS_SIZE 35 -#define RAW_TX_ACK_VARINT_COUNT 4 +#define BTC_ADDRESS_SIZE 35 +#define RAW_TX_ACK_VARINT_COUNT 4 #define STR(X) #X #define VERSTR(X) STR(X) @@ -41,9 +41,11 @@ void fsm_init(void); void fsm_sendSuccess(const char *text); #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); +void fsm_sendFailureDebug(FailureType code, const char *text, + const char *source); -#define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") +#define fsm_sendFailure(code, text) \ + fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") #else void fsm_sendFailure(FailureType code, const char *text); #endif @@ -53,6 +55,7 @@ void fsm_msgGetFeatures(GetFeatures *msg); void fsm_msgGetCoinTable(GetCoinTable *msg); void fsm_msgPing(Ping *msg); void fsm_msgChangePin(ChangePin *msg); +void fsm_msgChangeWipeCode(ChangeWipeCode *msg); void fsm_msgWipeDevice(WipeDevice *msg); void fsm_msgFirmwareErase(FirmwareErase *msg); void fsm_msgFirmwareUpload(FirmwareUpload *msg); @@ -61,13 +64,13 @@ void fsm_msgGetPublicKey(GetPublicKey *msg); void fsm_msgLoadDevice(LoadDevice *msg); void fsm_msgResetDevice(ResetDevice *msg); void fsm_msgSignTx(SignTx *msg); -//void fsm_msgPinMatrixAck(PinMatrixAck *msg); +// void fsm_msgPinMatrixAck(PinMatrixAck *msg); void fsm_msgCancel(Cancel *msg); void fsm_msgTxAck(TxAck *msg); void fsm_msgCipherKeyValue(CipherKeyValue *msg); void fsm_msgClearSession(ClearSession *msg); void fsm_msgApplySettings(ApplySettings *msg); -//void fsm_msgButtonAck(ButtonAck *msg); +// void fsm_msgButtonAck(ButtonAck *msg); void fsm_msgGetAddress(GetAddress *msg); void fsm_msgEntropyAck(EntropyAck *msg); void fsm_msgSignMessage(SignMessage *msg); @@ -75,7 +78,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg); void fsm_msgSignIdentity(SignIdentity *msg); void fsm_msgEncryptMessage(EncryptMessage *msg); void fsm_msgDecryptMessage(DecryptMessage *msg); -//void fsm_msgPassphraseAck(PassphraseAck *msg); +// void fsm_msgPassphraseAck(PassphraseAck *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); void fsm_msgWordAck(WordAck *msg); @@ -109,7 +112,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg); void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg); #if DEBUG_LINK -//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); +// void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); void fsm_msgDebugLinkGetState(DebugLinkGetState *msg); void fsm_msgDebugLinkStop(DebugLinkStop *msg); #endif diff --git a/include/keepkey/firmware/home_sm.h b/include/keepkey/firmware/home_sm.h index aded2f0ed..19ea6c921 100644 --- a/include/keepkey/firmware/home_sm.h +++ b/include/keepkey/firmware/home_sm.h @@ -25,11 +25,7 @@ #include /* State for Home SM */ -typedef enum { - AT_HOME, - AWAY_FROM_HOME, - SCREENSAVER -} HomeState; +typedef enum { AT_HOME, AWAY_FROM_HOME, SCREENSAVER } HomeState; void layoutHome(void); void layoutHomeForced(void); diff --git a/include/keepkey/firmware/nano.h b/include/keepkey/firmware/nano.h index eab26b346..edfe1f605 100644 --- a/include/keepkey/firmware/nano.h +++ b/include/keepkey/firmware/nano.h @@ -10,27 +10,24 @@ #define MAX_NANO_ADDR_SIZE 100 -bool nano_path_mismatched(const CoinType *coin, - const uint32_t *address_n, +bool nano_path_mismatched(const CoinType *coin, const uint32_t *address_n, const uint32_t address_n_count); -bool nano_bip32_to_string(char *node_str, size_t len, - const CoinType *coin, +bool nano_bip32_to_string(char *node_str, size_t len, const CoinType *coin, const uint32_t *address_n, const size_t address_n_count); void nano_hash_block_data(const uint8_t account_pk[32], - const uint8_t parent_hash[32], - const uint8_t link[32], + const uint8_t parent_hash[32], const uint8_t link[32], const uint8_t representative_pk[32], - const uint8_t balance[16], - uint8_t out_hash[32]); + const uint8_t balance[16], uint8_t out_hash[32]); const char *nano_getKnownRepName(const char *addr); void nano_truncateAddress(const CoinType *coin, char *str); void nano_signingAbort(void); -bool nano_signingInit(const NanoSignTx *msg, const HDNode *node, const CoinType *coin); +bool nano_signingInit(const NanoSignTx *msg, const HDNode *node, + const CoinType *coin); bool nano_parentHash(const NanoSignTx *msg); bool nano_currentHash(const NanoSignTx *msg, const HDNode *recip); bool nano_sanityCheck(const NanoSignTx *nano); diff --git a/include/keepkey/firmware/passphrase_sm.h b/include/keepkey/firmware/passphrase_sm.h index 92e97aae4..41ae172be 100644 --- a/include/keepkey/firmware/passphrase_sm.h +++ b/include/keepkey/firmware/passphrase_sm.h @@ -20,40 +20,36 @@ #ifndef PASSPHRASE_SM_H #define PASSPHRASE_SM_H - #include "keepkey/transport/interface.h" #include - #define PASSPHRASE_BUF sizeof(((PassphraseAck *)NULL)->passphrase) - /* State for Passphrase SM */ typedef enum { - PASSPHRASE_REQUEST, - PASSPHRASE_WAITING, - PASSPHRASE_ACK, - PASSPHRASE_FINISHED + PASSPHRASE_REQUEST, + PASSPHRASE_WAITING, + PASSPHRASE_ACK, + PASSPHRASE_FINISHED } PassphraseState; -/* While waiting for a passphrase ack, these are the types of messages we expect to - * see. +/* While waiting for a passphrase ack, these are the types of messages we expect + * to see. */ typedef enum { - PASSPHRASE_ACK_WAITING, - PASSPHRASE_ACK_RECEIVED, - PASSPHRASE_ACK_CANCEL_BY_INIT, - PASSPHRASE_ACK_CANCEL + PASSPHRASE_ACK_WAITING, + PASSPHRASE_ACK_RECEIVED, + PASSPHRASE_ACK_CANCEL_BY_INIT, + PASSPHRASE_ACK_CANCEL } PassphraseAckMsg; /* Contains passphrase received info */ typedef struct { - PassphraseAckMsg passphrase_ack_msg; - char passphrase[PASSPHRASE_BUF]; + PassphraseAckMsg passphrase_ack_msg; + char passphrase[PASSPHRASE_BUF]; } PassphraseInfo; - bool passphrase_protect(void); #endif diff --git a/include/keepkey/firmware/pin_sm.h b/include/keepkey/firmware/pin_sm.h index 6b489f82a..5e075ee02 100644 --- a/include/keepkey/firmware/pin_sm.h +++ b/include/keepkey/firmware/pin_sm.h @@ -26,30 +26,26 @@ #define PIN_BUF sizeof(((PinMatrixAck *)NULL)->pin) -#define PIN_FAIL_DELAY_START 2 -#define MAX_PIN_FAIL_ATTEMPTS 32 +#define PIN_FAIL_DELAY_START 2 +#define MAX_PIN_FAIL_ATTEMPTS 32 /// State for PIN SM. -typedef enum { - PIN_REQUEST, - PIN_WAITING, - PIN_ACK, - PIN_FINISHED -} PINState; +typedef enum { PIN_REQUEST, PIN_WAITING, PIN_ACK, PIN_FINISHED } PINState; -/// While waiting for a PIN ack, these are the types of messages we expect to see. +/// While waiting for a PIN ack, these are the types of messages we expect to +/// see. typedef enum { - PIN_ACK_WAITING, - PIN_ACK_RECEIVED, - PIN_ACK_CANCEL_BY_INIT, - PIN_ACK_CANCEL + PIN_ACK_WAITING, + PIN_ACK_RECEIVED, + PIN_ACK_CANCEL_BY_INIT, + PIN_ACK_CANCEL } PINAckMsg; /// PIN received info. typedef struct { - PinMatrixRequestType type; - PINAckMsg pin_ack_msg; - char pin[PIN_BUF]; + PinMatrixRequestType type; + PINAckMsg pin_ack_msg; + char pin[PIN_BUF]; } PINInfo; /// Authenticate user PIN for device access. @@ -70,6 +66,10 @@ bool pin_protect_uncached(void); /// \returns true iff the PIN was successfully changed. bool change_pin(void); +/// Process a wipe code change. +/// \returns true iff the wipe code was successfully changed. +bool change_wipe_code(void); + #if DEBUG_LINK /// Gets randomized PIN matrix. const char *get_pin_matrix(void); diff --git a/include/keepkey/firmware/policy.h b/include/keepkey/firmware/policy.h index 0def2650f..563d4290d 100644 --- a/include/keepkey/firmware/policy.h +++ b/include/keepkey/firmware/policy.h @@ -34,6 +34,7 @@ static const PolicyType policies[] = { {true, "AdvancedMode", true, false}, }; -int run_policy_compile_output(const CoinType *coin, const HDNode *root, void *vin, void *vout, bool needs_confirm); +int run_policy_compile_output(const CoinType *coin, const HDNode *root, + void *vin, void *vout, bool needs_confirm); #endif diff --git a/include/keepkey/firmware/recovery_cipher.h b/include/keepkey/firmware/recovery_cipher.h index baa83e9a0..a6ec97fed 100644 --- a/include/keepkey/firmware/recovery_cipher.h +++ b/include/keepkey/firmware/recovery_cipher.h @@ -23,10 +23,10 @@ #include #include -#define MNEMONIC_BUF 24 * 12 -#define CURRENT_WORD_BUF 32 -#define ENGLISH_ALPHABET_BUF 32 -#define BIP39_MAX_WORD_LEN 8 +#define MNEMONIC_BUF 24 * 12 +#define CURRENT_WORD_BUF 32 +#define ENGLISH_ALPHABET_BUF 32 +#define BIP39_MAX_WORD_LEN 8 void recovery_cipher_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, @@ -40,11 +40,10 @@ void recovery_cipher_finalize(void); void recovery_cipher_abort(void); #if DEBUG_LINK -const char* recovery_get_cipher(void); -const char* recovery_get_auto_completed_word(void); +const char *recovery_get_cipher(void); +const char *recovery_get_auto_completed_word(void); #endif - /// Determine if two strings are exact matches for length passed /// (does not stop at null termination) /// @@ -55,8 +54,8 @@ bool exact_str_match(const char *str1, const char *str2, uint32_t len); /// \brief Attempts to auto complete a partial word /// -/// \param partial_word[in/out] word that will be attempted to be auto completed. -/// \returns true iff partial_word was auto completed +/// \param partial_word[in/out] word that will be attempted to be auto +/// completed. \returns true iff partial_word was auto completed bool attempt_auto_complete(char *partial_word); #endif diff --git a/include/keepkey/firmware/reset.h b/include/keepkey/firmware/reset.h index 40db44d8a..9e785b7f7 100644 --- a/include/keepkey/firmware/reset.h +++ b/include/keepkey/firmware/reset.h @@ -25,16 +25,17 @@ #define MAX_WORDS 24 #define MAX_WORD_LEN 10 -#define MAX_PAGES 3 +#define MAX_PAGES 6 #define ADDITIONAL_WORD_PAD 5 #define WORDS_PER_SCREEN 24 #define TOKENED_MNEMONIC_BUF MAX_WORDS * (MAX_WORD_LEN + 1) + 1 #define FORMATTED_MNEMONIC_BUF MAX_WORDS * (MAX_WORD_LEN + ADDITIONAL_WORD_PAD) + 1 #define MNEMONIC_BY_SCREEN_BUF WORDS_PER_SCREEN * (MAX_WORD_LEN + 1) + 1 -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, - bool pin_protection, const char *language, const char *label, - bool no_backup, uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter); +void reset_init(bool display_random, uint32_t _strength, + bool passphrase_protection, bool pin_protection, + const char *language, const char *label, bool no_backup, + uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); diff --git a/include/keepkey/firmware/ripple.h b/include/keepkey/firmware/ripple.h index 0696d32ce..d4230a4d4 100644 --- a/include/keepkey/firmware/ripple.h +++ b/include/keepkey/firmware/ripple.h @@ -24,7 +24,7 @@ #include "messages-ripple.pb.h" -#define RIPPLE_MIN_FEE 10 +#define RIPPLE_MIN_FEE 10 #define RIPPLE_MAX_FEE 1000000 #define RIPPLE_DECIMALS 6 @@ -32,16 +32,16 @@ #define RIPPLE_FLAG_FULLY_CANONICAL 0x80000000 typedef enum { - RFT_INT16 = 1, - RFT_INT32 = 2, - RFT_AMOUNT = 6, - RFT_VL = 7, - RFT_ACCOUNT = 8, + RFT_INT16 = 1, + RFT_INT32 = 2, + RFT_AMOUNT = 6, + RFT_VL = 7, + RFT_ACCOUNT = 8, } RippleFieldType; typedef struct _RippleFieldMapping { - RippleFieldType type; - int key; + RippleFieldType type; + int key; } RippleFieldMapping; extern const RippleFieldMapping RFM_account; @@ -56,7 +56,8 @@ extern const RippleFieldMapping RFM_txnSignature; extern const RippleFieldMapping RFM_lastLedgerSequence; extern const RippleFieldMapping RFM_destinationTag; -bool ripple_getAddress(const uint8_t public_key[33], char address[MAX_ADDR_SIZE]); +bool ripple_getAddress(const uint8_t public_key[33], + char address[MAX_ADDR_SIZE]); void ripple_formatAmount(char *buf, size_t len, uint64_t amount); @@ -72,7 +73,8 @@ void ripple_serializeInt32(bool *ok, uint8_t **buf, const uint8_t *end, void ripple_serializeAmount(bool *ok, uint8_t **buf, const uint8_t *end, const RippleFieldMapping *m, int64_t amount); -void ripple_serializeVarint(bool *ok, uint8_t **buf, const uint8_t *end, int val); +void ripple_serializeVarint(bool *ok, uint8_t **buf, const uint8_t *end, + int val); void ripple_serializeBytes(bool *ok, uint8_t **buf, const uint8_t *end, const uint8_t *bytes, size_t count); @@ -81,15 +83,13 @@ void ripple_serializeAddress(bool *ok, uint8_t **buf, const uint8_t *end, const RippleFieldMapping *m, const char *address); void ripple_serializeVL(bool *ok, uint8_t **buf, const uint8_t *end, - const RippleFieldMapping *m, - const uint8_t *bytes, size_t count); + const RippleFieldMapping *m, const uint8_t *bytes, + size_t count); bool ripple_serialize(uint8_t **buf, const uint8_t *end, const RippleSignTx *tx, - const char *source_address, - const uint8_t *pubkey, const uint8_t *sig, - size_t sig_len); + const char *source_address, const uint8_t *pubkey, + const uint8_t *sig, size_t sig_len); -void ripple_signTx(const HDNode *node, RippleSignTx *tx, - RippleSignedTx *resp); +void ripple_signTx(const HDNode *node, RippleSignTx *tx, RippleSignedTx *resp); #endif diff --git a/include/keepkey/firmware/signing.h b/include/keepkey/firmware/signing.h index 6b58ae7dc..1295d1984 100644 --- a/include/keepkey/firmware/signing.h +++ b/include/keepkey/firmware/signing.h @@ -25,7 +25,8 @@ #include #include -void signing_init(const SignTx *msg, const CoinType *_coin, const HDNode *_root); +void signing_init(const SignTx *msg, const CoinType *_coin, + const HDNode *_root); void signing_abort(void); void signing_txack(TransactionType *tx); void send_fsm_co_error_message(int co_error); diff --git a/include/keepkey/firmware/storage.h b/include/keepkey/firmware/storage.h index e47b25672..7d7ac6821 100644 --- a/include/keepkey/firmware/storage.h +++ b/include/keepkey/firmware/storage.h @@ -23,13 +23,15 @@ #include "trezor/crypto/bip32.h" #include "keepkey/board/memory.h" -#define STORAGE_VERSION 15 /* Must add case fallthrough in storage_fromFlash after increment*/ +#define STORAGE_VERSION \ + 16 /* Must add case fallthrough in storage_fromFlash after increment*/ #define STORAGE_RETRIES 3 #define RANDOM_SALT_LEN 32 -#define STORAGE_DEFAULT_SCREENSAVER_TIMEOUT (10U * 60U * 1000U) /* 10 minutes */ -#define STORAGE_MIN_SCREENSAVER_TIMEOUT ( 30U * 1000U) /* 30 seconds */ +#define STORAGE_DEFAULT_SCREENSAVER_TIMEOUT (10U * 60U * 1000U) /* 10 minutes \ + */ +#define STORAGE_MIN_SCREENSAVER_TIMEOUT (30U * 1000U) /* 30 seconds */ /// \brief Validate storage content and copy data to shadow memory. void storage_init(void); @@ -43,6 +45,9 @@ void storage_reset(void); /// \brief Clear storage. void storage_wipe(void); +/// \brief Clear storage key and storage key fingerprint. +void storage_clearKeys(void); + /// \brief Reset session states. /// \param clear_pin whether to clear the pin as well. void session_clear(bool clear_pin); @@ -88,10 +93,16 @@ const char *storage_getLanguage(void); /// \return true iff the privided pin is correct. bool storage_isPinCorrect(const char *pin); +/// \brief Validate wipe code. +/// \return true iff the privided wipe code is correct. +bool storage_isWipeCodeCorrect(const char *wipe_code); + bool storage_hasPin(void); void storage_setPin(const char *pin); void session_cachePin(const char *pin); bool session_isPinCached(void); +bool storage_hasWipeCode(void); +void storage_setWipeCode(const char *wipe_code); void storage_resetPinFails(void); void storage_increasePinFails(void); uint32_t storage_getPinFails(void); @@ -109,7 +120,8 @@ void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); /// \brief Set config mnemonic in shadow memory from words. -void storage_setMnemonicFromWords(const char (*words)[12], unsigned int num_words); +void storage_setMnemonicFromWords(const char (*words)[12], + unsigned int num_words); /// \brief Set config mnemonic from a recovery sentence. void storage_setMnemonic(const char *mnemonic); diff --git a/include/keepkey/firmware/tendermint.h b/include/keepkey/firmware/tendermint.h index 373da52c1..586e85879 100644 --- a/include/keepkey/firmware/tendermint.h +++ b/include/keepkey/firmware/tendermint.h @@ -13,8 +13,7 @@ typedef struct _SHA256_CTX SHA256_CTX; /** * \returns false iff the provided bip32 derivation path matches the given coin. */ -bool tendermint_pathMismatched(const CoinType *coin, - const uint32_t *address_n, +bool tendermint_pathMismatched(const CoinType *coin, const uint32_t *address_n, const uint32_t address_n_count); /** @@ -26,11 +25,13 @@ bool tendermint_pathMismatched(const CoinType *coin, * * \returns true if successful */ -bool tendermint_getAddress(const HDNode *node, const char *prefix, char *address); +bool tendermint_getAddress(const HDNode *node, const char *prefix, + char *address); void tendermint_sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len); bool tendermint_snprintf(SHA256_CTX *ctx, char *temp, size_t len, - const char *format, ...) __attribute__((format(printf, 4, 5))); + const char *format, ...) + __attribute__((format(printf, 4, 5))); #endif diff --git a/include/keepkey/firmware/transaction.h b/include/keepkey/firmware/transaction.h index 627e6c9d4..5edc96da0 100644 --- a/include/keepkey/firmware/transaction.h +++ b/include/keepkey/firmware/transaction.h @@ -24,71 +24,92 @@ #include "trezor/crypto/bip32.h" #include "keepkey/transport/interface.h" - #include #include #define TX_OVERWINTERED 0x80000000 /* Transaction output compilation errors */ -#define TXOUT_OK 1 -#define TXOUT_COMPILE_ERROR 0 -#define TXOUT_CANCEL -1 -#define TXOUT_EXCHANGE_CONTRACT_ERROR -2 - +#define TXOUT_OK 1 +#define TXOUT_COMPILE_ERROR 0 +#define TXOUT_CANCEL -1 +#define TXOUT_EXCHANGE_CONTRACT_ERROR -2 typedef struct { - uint32_t inputs_len; - uint32_t outputs_len; + uint32_t inputs_len; + uint32_t outputs_len; - uint32_t version; - uint32_t version_group_id; - uint32_t lock_time; - uint32_t expiry; - bool is_segwit; - bool is_decred; + uint32_t version; + uint32_t version_group_id; + uint32_t lock_time; + uint32_t expiry; + bool is_segwit; + bool is_decred; - uint32_t have_inputs; - uint32_t have_outputs; + uint32_t have_inputs; + uint32_t have_outputs; - bool overwintered; - uint32_t extra_data_len; - uint32_t extra_data_received; + bool overwintered; + uint32_t extra_data_len; + uint32_t extra_data_received; - uint32_t size; + uint32_t size; - Hasher hasher; + Hasher hasher; } TxStruct; -bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); -uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); -uint32_t compile_script_multisig(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t *out); -uint32_t compile_script_multisig_hash(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); -uint32_t serialize_script_multisig(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); +bool compute_address(const CoinType *coin, InputScriptType script_type, + const HDNode *node, bool has_multisig, + const MultisigRedeemScriptType *multisig, + char address[MAX_ADDR_SIZE]); +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, + uint8_t *out); +uint32_t compile_script_multisig(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *out); +uint32_t compile_script_multisig_hash(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *hash); +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, + const uint8_t *pubkey, uint32_t pubkey_len, + uint8_t sighash, uint8_t *out); +uint32_t serialize_script_multisig(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t sighash, uint8_t *out); +int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, + TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, + bool decred); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); - -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id); +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, + uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, + uint8_t *out); +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, + uint8_t *out); + +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, + uint32_t version, uint32_t lock_time, uint32_t expiry, + uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, + uint32_t version_group_id); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); -uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, + uint32_t datalen); +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, + const TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t tx_input_weight(const CoinType *coin, const TxInputType *txinput); -uint32_t tx_output_weight(const CoinType *coin, const curve_info *curve, const TxOutputType *txoutput); +uint32_t tx_output_weight(const CoinType *coin, const curve_info *curve, + const TxOutputType *txoutput); uint32_t tx_decred_witness_weight(const TxInputType *txinput); #endif diff --git a/include/keepkey/firmware/txin_check.h b/include/keepkey/firmware/txin_check.h new file mode 100644 index 000000000..4b4f0070f --- /dev/null +++ b/include/keepkey/firmware/txin_check.h @@ -0,0 +1,37 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef TXIN_CHECK_H +#define TXIN_CHECK_H + +#include +#include + +#define DIGEST_STR_LEN (2 * SHA256_DIGEST_LENGTH) + 1 +#define AMT_STR_LEN 32 +#define ADDR_STR_LEN 130 + +void txin_dgst_addto(const uint8_t *data, size_t len); +void txin_dgst_initialize(void); +bool txin_dgst_compare(const char *amt_str, const char *addr_str); +void txin_dgst_final(void); +void txin_dgst_getstrs(char *prev, char *cur, size_t len); +void txin_dgst_save_and_reset(char *amt_str, char *addr_str); + +#endif diff --git a/include/keepkey/firmware/u2f.h b/include/keepkey/firmware/u2f.h index 9bc192a44..d8049ee38 100644 --- a/include/keepkey/firmware/u2f.h +++ b/include/keepkey/firmware/u2f.h @@ -28,9 +28,9 @@ #define U2F_KEY_PATH 0x80553246 typedef struct { - uint8_t cla, ins, p1, p2; - uint8_t lc1, lc2, lc3; - uint8_t data[]; + uint8_t cla, ins, p1, p2; + uint8_t lc1, lc2, lc3; + uint8_t data[]; } APDU; #define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3)) @@ -56,7 +56,7 @@ void send_u2f_msg(const uint8_t *data, uint32_t len); void send_u2f_error(uint16_t err); void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, - const uint32_t len); + const uint32_t len); void send_u2fhid_error(uint32_t fcid, uint8_t err); #endif diff --git a/include/keepkey/firmware/u2f/u2f.h b/include/keepkey/firmware/u2f/u2f.h index b06771396..8e9c2432a 100644 --- a/include/keepkey/firmware/u2f/u2f.h +++ b/include/keepkey/firmware/u2f/u2f.h @@ -11,9 +11,9 @@ #define __U2F_H_INCLUDED__ #ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else #include @@ -25,86 +25,85 @@ extern "C" { // General constants -#define U2F_EC_KEY_SIZE 32 // EC key size in bytes -#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point -#define U2F_MAX_KH_SIZE 128 // Max size of key handle -#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate -#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature -#define U2F_CTR_SIZE 4 // Size of counter field -#define U2F_APPID_SIZE 32 // Size of application id -#define U2F_CHAL_SIZE 32 // Size of challenge +#define U2F_EC_KEY_SIZE 32 // EC key size in bytes +#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point +#define U2F_MAX_KH_SIZE 128 // Max size of key handle +#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate +#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature +#define U2F_CTR_SIZE 4 // Size of counter field +#define U2F_APPID_SIZE 32 // Size of application id +#define U2F_CHAL_SIZE 32 // Size of challenge -#define ENC_SIZE(x) ((x + 7) & 0xfff8) +#define ENC_SIZE(x) ((x + 7) & 0xfff8) // EC (uncompressed) point -#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format +#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format typedef struct __attribute__((packed)) { - uint8_t pointFormat; // Point type - uint8_t x[U2F_EC_KEY_SIZE]; // X-value - uint8_t y[U2F_EC_KEY_SIZE]; // Y-value + uint8_t pointFormat; // Point type + uint8_t x[U2F_EC_KEY_SIZE]; // X-value + uint8_t y[U2F_EC_KEY_SIZE]; // Y-value } U2F_EC_POINT; // U2F native commands -#define U2F_REGISTER 0x01 // Registration command -#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command -#define U2F_VERSION 0x03 // Read version string command +#define U2F_REGISTER 0x01 // Registration command +#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command +#define U2F_VERSION 0x03 // Read version string command -#define U2F_VENDOR_FIRST 0x40 // First vendor defined command -#define U2F_VENDOR_LAST 0xbf // Last vendor defined command +#define U2F_VENDOR_FIRST 0x40 // First vendor defined command +#define U2F_VENDOR_LAST 0xbf // Last vendor defined command // U2F_CMD_REGISTER command defines -#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier -#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier +#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier +#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier typedef struct __attribute__((packed)) { - uint8_t chal[U2F_CHAL_SIZE]; // Challenge - uint8_t appId[U2F_APPID_SIZE]; // Application id + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id } U2F_REGISTER_REQ; typedef struct __attribute__((packed)) { - uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) - U2F_EC_POINT pubKey; // Generated public key - uint8_t keyHandleLen; // Length of key handle - uint8_t keyHandleCertSig[ - U2F_MAX_KH_SIZE + // Key handle - U2F_MAX_ATT_CERT_SIZE + // Attestation certificate - U2F_MAX_EC_SIG_SIZE]; // Registration signature + uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) + U2F_EC_POINT pubKey; // Generated public key + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle + U2F_MAX_ATT_CERT_SIZE + // Attestation certificate + U2F_MAX_EC_SIG_SIZE]; // Registration signature } U2F_REGISTER_RESP; // U2F_CMD_AUTHENTICATE command defines // Authentication control byte -#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign -#define U2F_AUTH_CHECK_ONLY 0x07 // Check only -#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set +#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign +#define U2F_AUTH_CHECK_ONLY 0x07 // Check only +#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set typedef struct __attribute__((packed)) { - uint8_t chal[U2F_CHAL_SIZE]; // Challenge - uint8_t appId[U2F_APPID_SIZE]; // Application id - uint8_t keyHandleLen; // Length of key handle - uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle } U2F_AUTHENTICATE_REQ; typedef struct __attribute__((packed)) { - uint8_t flags; // U2F_AUTH_FLAG_ values - uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) - uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature + uint8_t flags; // U2F_AUTH_FLAG_ values + uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) + uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature } U2F_AUTHENTICATE_RESP; // Command status responses -#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR -#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH -#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA -#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED -#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED -#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED -#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00 // SW_CLA_NOT_SUPPORTED +#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR +#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH +#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA +#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED +#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED +#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED +#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00 // SW_CLA_NOT_SUPPORTED #ifdef __cplusplus } diff --git a/include/keepkey/firmware/u2f/u2f_hid.h b/include/keepkey/firmware/u2f/u2f_hid.h index f29059da2..d79a3106a 100644 --- a/include/keepkey/firmware/u2f/u2f_hid.h +++ b/include/keepkey/firmware/u2f/u2f_hid.h @@ -11,9 +11,9 @@ #define __U2FHID_H_INCLUDED__ #ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else #include @@ -25,20 +25,20 @@ extern "C" { // Size of HID reports -#define HID_RPT_SIZE 64 // Default size of raw HID report +#define HID_RPT_SIZE 64 // Default size of raw HID report // Frame layout - command- and continuation frames -#define CID_BROADCAST 0xffffffff // Broadcast channel id +#define CID_BROADCAST 0xffffffff // Broadcast channel id -#define TYPE_MASK 0x80 // Frame type mask -#define TYPE_INIT 0x80 // Initial frame identifier -#define TYPE_CONT 0x00 // Continuation frame identifier +#define TYPE_MASK 0x80 // Frame type mask +#define TYPE_INIT 0x80 // Initial frame identifier +#define TYPE_CONT 0x00 // Continuation frame identifier typedef struct __attribute__((packed)) { - uint32_t cid; // Channel identifier + uint32_t cid; // Channel identifier union __attribute__((packed)) { - uint8_t type; // Frame type - b7 defines type + uint8_t type; // Frame type - b7 defines type struct __attribute__((packed)) { uint8_t cmd; // Command - b7 set uint8_t bcnth; // Message byte count - high part @@ -53,77 +53,78 @@ typedef struct __attribute__((packed)) { } U2FHID_FRAME; #define FRAME_TYPE(f) ((f).type & TYPE_MASK) -#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) -#define MSG_LEN(f) ((f).init.bcnth*256 + (f).init.bcntl) -#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) +#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) +#define MSG_LEN(f) ((f).init.bcnth * 256 + (f).init.bcntl) +#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) // HID usage- and usage-page definitions -#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page -#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection -#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report -#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report +#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page +#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection +#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report +#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report // General constants -#define U2FHID_IF_VERSION 2 // Current interface implementation version -#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms +#define U2FHID_IF_VERSION 2 // Current interface implementation version +#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms // U2FHID native commands -#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only -#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame -#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command -#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization -#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink -#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command -#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response +#define U2FHID_PING \ + (TYPE_INIT | 0x01) // Echo data through local processor only +#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame +#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command +#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization +#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink +#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command +#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response #define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command -#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command +#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command // U2FHID_INIT command defines -#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge -#define CAPFLAG_WINK 0x01 // Device supports WINK command -#define CAPFLAG_LOCK 0x02 // Device supports LOCK command +#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge +#define CAPFLAG_WINK 0x01 // Device supports WINK command +#define CAPFLAG_LOCK 0x02 // Device supports LOCK command typedef struct __attribute__((packed)) { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce } U2FHID_INIT_REQ; typedef struct __attribute__((packed)) { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce - uint32_t cid; // Channel identifier - uint8_t versionInterface; // Interface version - uint8_t versionMajor; // Major version number - uint8_t versionMinor; // Minor version number - uint8_t versionBuild; // Build version number - uint8_t capFlags; // Capabilities flags + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint32_t cid; // Channel identifier + uint8_t versionInterface; // Interface version + uint8_t versionMajor; // Major version number + uint8_t versionMinor; // Minor version number + uint8_t versionBuild; // Build version number + uint8_t capFlags; // Capabilities flags } U2FHID_INIT_RESP; // U2FHID_SYNC command defines typedef struct __attribute__((packed)) { - uint8_t nonce; // Client application nonce + uint8_t nonce; // Client application nonce } U2FHID_SYNC_REQ; typedef struct __attribute__((packed)) { - uint8_t nonce; // Client application nonce + uint8_t nonce; // Client application nonce } U2FHID_SYNC_RESP; // Low-level error codes. Return as negatives. -#define ERR_NONE 0x00 // No error -#define ERR_INVALID_CMD 0x01 // Invalid command -#define ERR_INVALID_PAR 0x02 // Invalid parameter -#define ERR_INVALID_LEN 0x03 // Invalid message length -#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing -#define ERR_MSG_TIMEOUT 0x05 // Message has timed out -#define ERR_CHANNEL_BUSY 0x06 // Channel busy -#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock -#define ERR_INVALID_CID 0x0b // Message on CID 0 -#define ERR_OTHER 0x7f // Other unspecified error +#define ERR_NONE 0x00 // No error +#define ERR_INVALID_CMD 0x01 // Invalid command +#define ERR_INVALID_PAR 0x02 // Invalid parameter +#define ERR_INVALID_LEN 0x03 // Invalid message length +#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing +#define ERR_MSG_TIMEOUT 0x05 // Message has timed out +#define ERR_CHANNEL_BUSY 0x06 // Channel busy +#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock +#define ERR_INVALID_CID 0x0b // Message on CID 0 +#define ERR_OTHER 0x7f // Other unspecified error #ifdef __cplusplus } diff --git a/include/keepkey/firmware/u2f/u2f_keys.h b/include/keepkey/firmware/u2f/u2f_keys.h index 6e4ec0b62..13180918d 100644 --- a/include/keepkey/firmware/u2f/u2f_keys.h +++ b/include/keepkey/firmware/u2f/u2f_keys.h @@ -4,31 +4,35 @@ #include const uint8_t U2F_ATT_PRIV_KEY[] = { - 0x30, 0x6e, 0xf6, 0x85, 0xc7, 0x84, 0x7a, 0x12, - 0xf2, 0x7d, 0xbd, 0x75, 0xe1, 0xa4, 0xb0, 0x9e, - 0x1e, 0xd7, 0x4c, 0xda, 0x92, 0x1f, 0x74, 0x15, - 0x83, 0x80, 0x16, 0xab, 0x71, 0xcf, 0x08, 0xd4 -}; + 0x30, 0x6e, 0xf6, 0x85, 0xc7, 0x84, 0x7a, 0x12, 0xf2, 0x7d, 0xbd, + 0x75, 0xe1, 0xa4, 0xb0, 0x9e, 0x1e, 0xd7, 0x4c, 0xda, 0x92, 0x1f, + 0x74, 0x15, 0x83, 0x80, 0x16, 0xab, 0x71, 0xcf, 0x08, 0xd4}; const uint8_t U2F_ATT_CERT[] = { - 0x30, 0x82, 0x01, 0x1b, 0x30, 0x81, 0xc2, 0x02, 0x09, 0x00, 0xf7, 0x7a, 0x58, 0x7a, 0xaf, 0xba, - 0x23, 0x98, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x16, - 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x4b, 0x65, 0x65, 0x70, 0x4b, - 0x65, 0x79, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x30, 0x30, 0x34, - 0x32, 0x33, 0x33, 0x36, 0x33, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x30, 0x30, 0x31, 0x32, - 0x33, 0x33, 0x36, 0x33, 0x32, 0x5a, 0x30, 0x16, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, - 0x03, 0x0c, 0x0b, 0x4b, 0x65, 0x65, 0x70, 0x4b, 0x65, 0x79, 0x20, 0x55, 0x32, 0x46, 0x30, 0x59, - 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xd1, 0x26, 0x19, 0x31, 0x55, 0xe9, 0x4e, - 0xc1, 0x68, 0x46, 0x46, 0xd1, 0xf7, 0xeb, 0xb0, 0x50, 0xc1, 0x85, 0x74, 0x4d, 0xba, 0xa8, 0x2c, - 0x1f, 0x95, 0xa6, 0x71, 0xd2, 0x9b, 0x24, 0xfd, 0x75, 0x76, 0xa9, 0xf9, 0xcc, 0xd9, 0x5b, 0xc8, - 0xc4, 0xd0, 0x08, 0xe0, 0x89, 0x8c, 0x9f, 0x07, 0x80, 0x7d, 0xe6, 0x63, 0x7e, 0xf3, 0x2b, 0x93, - 0x57, 0xf5, 0x7b, 0x0a, 0x97, 0x88, 0xf1, 0x20, 0xeb, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0x96, 0xdf, 0x7e, - 0xa3, 0xd4, 0x60, 0x93, 0x2b, 0x77, 0xbe, 0xfe, 0x2c, 0xa6, 0x73, 0x5e, 0x95, 0xbb, 0x67, 0x52, - 0x36, 0xb2, 0x36, 0x9c, 0xba, 0x67, 0xb1, 0x79, 0x07, 0xa8, 0xd9, 0xaf, 0xdc, 0x02, 0x20, 0x3e, - 0x71, 0x24, 0xe0, 0xb4, 0x1e, 0xaf, 0xe8, 0x12, 0x6c, 0x12, 0x98, 0xa6, 0xfc, 0xb1, 0x04, 0x26, - 0x01, 0x6b, 0x08, 0x85, 0x39, 0x1e, 0xf5, 0xd1, 0xda, 0x4e, 0x7a, 0x1a, 0x5a, 0x8b, 0xe4, + 0x30, 0x82, 0x01, 0x1b, 0x30, 0x81, 0xc2, 0x02, 0x09, 0x00, 0xf7, 0x7a, + 0x58, 0x7a, 0xaf, 0xba, 0x23, 0x98, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x16, 0x31, 0x14, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x4b, 0x65, 0x65, 0x70, 0x4b, + 0x65, 0x79, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, + 0x31, 0x30, 0x30, 0x34, 0x32, 0x33, 0x33, 0x36, 0x33, 0x32, 0x5a, 0x17, + 0x0d, 0x32, 0x38, 0x31, 0x30, 0x30, 0x31, 0x32, 0x33, 0x33, 0x36, 0x33, + 0x32, 0x5a, 0x30, 0x16, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x0b, 0x4b, 0x65, 0x65, 0x70, 0x4b, 0x65, 0x79, 0x20, 0x55, + 0x32, 0x46, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, + 0x07, 0x03, 0x42, 0x00, 0x04, 0xd1, 0x26, 0x19, 0x31, 0x55, 0xe9, 0x4e, + 0xc1, 0x68, 0x46, 0x46, 0xd1, 0xf7, 0xeb, 0xb0, 0x50, 0xc1, 0x85, 0x74, + 0x4d, 0xba, 0xa8, 0x2c, 0x1f, 0x95, 0xa6, 0x71, 0xd2, 0x9b, 0x24, 0xfd, + 0x75, 0x76, 0xa9, 0xf9, 0xcc, 0xd9, 0x5b, 0xc8, 0xc4, 0xd0, 0x08, 0xe0, + 0x89, 0x8c, 0x9f, 0x07, 0x80, 0x7d, 0xe6, 0x63, 0x7e, 0xf3, 0x2b, 0x93, + 0x57, 0xf5, 0x7b, 0x0a, 0x97, 0x88, 0xf1, 0x20, 0xeb, 0x30, 0x0a, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, + 0x30, 0x45, 0x02, 0x21, 0x00, 0x96, 0xdf, 0x7e, 0xa3, 0xd4, 0x60, 0x93, + 0x2b, 0x77, 0xbe, 0xfe, 0x2c, 0xa6, 0x73, 0x5e, 0x95, 0xbb, 0x67, 0x52, + 0x36, 0xb2, 0x36, 0x9c, 0xba, 0x67, 0xb1, 0x79, 0x07, 0xa8, 0xd9, 0xaf, + 0xdc, 0x02, 0x20, 0x3e, 0x71, 0x24, 0xe0, 0xb4, 0x1e, 0xaf, 0xe8, 0x12, + 0x6c, 0x12, 0x98, 0xa6, 0xfc, 0xb1, 0x04, 0x26, 0x01, 0x6b, 0x08, 0x85, + 0x39, 0x1e, 0xf5, 0xd1, 0xda, 0x4e, 0x7a, 0x1a, 0x5a, 0x8b, 0xe4, }; -#endif // __U2F_KEYS_H_INCLUDED__ +#endif // __U2F_KEYS_H_INCLUDED__ diff --git a/include/keepkey/transport/interface.h b/include/keepkey/transport/interface.h index ac7087e8f..614fe7260 100644 --- a/include/keepkey/transport/interface.h +++ b/include/keepkey/transport/interface.h @@ -36,9 +36,9 @@ #ifndef EMULATOR /* The max size of a decoded protobuf */ -# define MAX_DECODE_SIZE (13 * 1024) +#define MAX_DECODE_SIZE (13 * 1024) #else -# define MAX_DECODE_SIZE (26 * 1024) +#define MAX_DECODE_SIZE (26 * 1024) #endif #endif diff --git a/include/keepkey/transport/trezor_transport.h b/include/keepkey/transport/trezor_transport.h index 344126133..279a6a195 100644 --- a/include/keepkey/transport/trezor_transport.h +++ b/include/keepkey/transport/trezor_transport.h @@ -22,56 +22,49 @@ #include - #ifdef EMULATOR -# define MAX_FRAME_SIZE (64 * 1024) +#define MAX_FRAME_SIZE (64 * 1024) #else -# define MAX_FRAME_SIZE (12 * 1024) +#define MAX_FRAME_SIZE (12 * 1024) #endif - #pragma pack(1) /* This structure is derived from the Trezor protocol. Note that the values come in as big endian, so they'll need to be swapped. */ -typedef struct -{ - uint8_t hid_type; /* First byte is always 0x3f */ +typedef struct { + uint8_t hid_type; /* First byte is always 0x3f */ } UsbHeader; /* Trezor frame header */ -typedef struct -{ - /* Start of Trezor frame */ - uint8_t pre1; - uint8_t pre2; +typedef struct { + /* Start of Trezor frame */ + uint8_t pre1; + uint8_t pre2; - /* Protobuf ID */ - uint16_t id; + /* Protobuf ID */ + uint16_t id; - /* Length of the following message */ - uint32_t len; + /* Length of the following message */ + uint32_t len; } TrezorFrameHeaderFirst; /* Second+ continuation fragment. */ -typedef struct -{ - UsbHeader header; - uint8_t contents[0]; +typedef struct { + UsbHeader header; + uint8_t contents[0]; } TrezorFrameFragment; -typedef struct -{ - UsbHeader usb_header; - TrezorFrameHeaderFirst header; - uint8_t contents[0]; +typedef struct { + UsbHeader usb_header; + TrezorFrameHeaderFirst header; + uint8_t contents[0]; } TrezorFrame; -typedef struct -{ - TrezorFrame frame; - uint8_t buffer[MAX_FRAME_SIZE+ /* VERSION + DL? + U2F_OK */ 4]; +typedef struct { + TrezorFrame frame; + uint8_t buffer[MAX_FRAME_SIZE + /* VERSION + DL? + U2F_OK */ 4]; } TrezorFrameBuffer; #pragma pack() diff --git a/include/keepkey/variant/keepkey.h b/include/keepkey/variant/keepkey.h index 79eb98dec..345008a8a 100644 --- a/include/keepkey/variant/keepkey.h +++ b/include/keepkey/variant/keepkey.h @@ -3,13 +3,10 @@ #include "keepkey/board/variant.h" -#define VARIANTINFO_KEEPKEY \ - .version = 1, \ - .name = "KeepKey", \ - .logo = &kk_logo, \ - .logo_reversed = &kk_logo_reversed, \ - .screensaver_timeout = ONE_SEC * 60 * 10, \ - .screensaver = &kk_screensaver, +#define VARIANTINFO_KEEPKEY \ + .version = 1, .name = "KeepKey", .logo = &kk_logo, \ + .logo_reversed = &kk_logo_reversed, \ + .screensaver_timeout = ONE_SEC * 60 * 10, .screensaver = &kk_screensaver, extern const VariantInfo variant_keepkey; extern const VariantAnimation kk_logo; diff --git a/include/keepkey/variant/poweredBy.h b/include/keepkey/variant/poweredBy.h index 0750154f1..ba4b130c5 100644 --- a/include/keepkey/variant/poweredBy.h +++ b/include/keepkey/variant/poweredBy.h @@ -3,13 +3,10 @@ #include "keepkey/board/variant.h" -#define VARIANTINFO_POWERED_BY \ - .version = 1, \ - .name = "POWERED_BY", \ - .logo = &poweredBy_logo, \ - .logo_reversed = &poweredBy_logo_reversed, \ - .screensaver_timeout = ONE_SEC * 60 * 10, \ - .screensaver = &poweredBy_logo, +#define VARIANTINFO_POWERED_BY \ + .version = 1, .name = "POWERED_BY", .logo = &poweredBy_logo, \ + .logo_reversed = &poweredBy_logo_reversed, \ + .screensaver_timeout = ONE_SEC * 60 * 10, .screensaver = &poweredBy_logo, extern const VariantInfo variant_poweredBy; extern const VariantAnimation poweredBy_logo; diff --git a/include/keepkey/variant/salt.h b/include/keepkey/variant/salt.h index 2f370ddd2..ad632b650 100644 --- a/include/keepkey/variant/salt.h +++ b/include/keepkey/variant/salt.h @@ -3,13 +3,10 @@ #include "keepkey/board/variant.h" -#define VARIANTINFO_SALT \ - .version = 1, \ - .name = "SALT", \ - .logo = &salt_logo, \ - .logo_reversed = &salt_logo_reversed, \ - .screensaver_timeout = ONE_SEC * 60 * 10, \ - .screensaver = &salt_screensaver, +#define VARIANTINFO_SALT \ + .version = 1, .name = "SALT", .logo = &salt_logo, \ + .logo_reversed = &salt_logo_reversed, \ + .screensaver_timeout = ONE_SEC * 60 * 10, .screensaver = &salt_screensaver, extern const VariantInfo variant_salt; extern const VariantAnimation salt_logo; diff --git a/include/pb.h b/include/pb.h index fc0fe7a26..ce36d512b 100644 --- a/include/pb.h +++ b/include/pb.h @@ -37,7 +37,6 @@ * This was the default until nanopb-0.2.1. */ /* #define PB_OLD_CALLBACK_STYLE */ - /* Don't encode scalar arrays as packed. This is only to be used when * the decoder on the receiving side cannot process packed scalar arrays. * Such example is older protobuf.js. */ @@ -48,10 +47,9 @@ * Feel free to look around and use the defined macros, though. * ******************************************************************/ - /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.3.9.4 +#define NANOPB_VERSION nanopb - 0.3.9.4 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -81,30 +79,30 @@ * This just reduces memory requirements, but is not required. */ #if defined(PB_NO_PACKED_STRUCTS) - /* Disable struct packing */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed +/* Disable struct packing */ +#define PB_PACKED_STRUCT_START +#define PB_PACKED_STRUCT_END +#define pb_packed #elif defined(__GNUC__) || defined(__clang__) - /* For GCC and clang */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed __attribute__((packed)) +/* For GCC and clang */ +#define PB_PACKED_STRUCT_START +#define PB_PACKED_STRUCT_END +#define pb_packed __attribute__((packed)) #elif defined(__ICCARM__) || defined(__CC_ARM) - /* For IAR ARM and Keil MDK-ARM compilers */ -# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") -# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") -# define pb_packed +/* For IAR ARM and Keil MDK-ARM compilers */ +#define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +#define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +#define pb_packed #elif defined(_MSC_VER) && (_MSC_VER >= 1500) - /* For Microsoft Visual C++ */ -# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) -# define PB_PACKED_STRUCT_END __pragma(pack(pop)) -# define pb_packed +/* For Microsoft Visual C++ */ +#define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +#define PB_PACKED_STRUCT_END __pragma(pack(pop)) +#define pb_packed #else - /* Unknown compiler */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed +/* Unknown compiler */ +#define PB_PACKED_STRUCT_START +#define PB_PACKED_STRUCT_END +#define pb_packed #endif /* Handly macro for suppressing unreferenced-parameter compiler warnings. */ @@ -123,12 +121,16 @@ */ #ifndef PB_NO_STATIC_ASSERT #ifndef PB_STATIC_ASSERT -#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; -#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) -#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#define PB_STATIC_ASSERT(COND, MSG) \ + typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, \ + __COUNTER__)[(COND) ? 1 : -1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) \ + PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) \ + pb_static_assertion_##MSG##LINE##COUNTER #endif #else -#define PB_STATIC_ASSERT(COND,MSG) +#define PB_STATIC_ASSERT(COND, MSG) #endif /* Number of required fields to keep track of. */ @@ -150,8 +152,8 @@ typedef uint_least8_t pb_type_t; /**** Field data types ****/ /* Numeric types */ -#define PB_LTYPE_BOOL 0x00 /* bool */ -#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ +#define PB_LTYPE_BOOL 0x00 /* bool */ +#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ #define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ #define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ #define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ @@ -191,32 +193,32 @@ typedef uint_least8_t pb_type_t; #define PB_HTYPE_REQUIRED 0x00 #define PB_HTYPE_OPTIONAL 0x10 #define PB_HTYPE_REPEATED 0x20 -#define PB_HTYPE_ONEOF 0x30 -#define PB_HTYPE_MASK 0x30 +#define PB_HTYPE_ONEOF 0x30 +#define PB_HTYPE_MASK 0x30 /**** Field allocation types ****/ - -#define PB_ATYPE_STATIC 0x00 -#define PB_ATYPE_POINTER 0x80 + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 #define PB_ATYPE_CALLBACK 0x40 -#define PB_ATYPE_MASK 0xC0 +#define PB_ATYPE_MASK 0xC0 -#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) -#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) -#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) +#define PB_ATYPE(x) ((x)&PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x)&PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x)&PB_LTYPE_MASK) /* Data type used for storing sizes of struct fields * and array counts. */ #if defined(PB_FIELD_32BIT) - typedef uint32_t pb_size_t; - typedef int32_t pb_ssize_t; +typedef uint32_t pb_size_t; +typedef int32_t pb_ssize_t; #elif defined(PB_FIELD_16BIT) - typedef uint_least16_t pb_size_t; - typedef int_least16_t pb_ssize_t; +typedef uint_least16_t pb_size_t; +typedef int_least16_t pb_ssize_t; #else - typedef uint_least8_t pb_size_t; - typedef int_least8_t pb_ssize_t; +typedef uint_least8_t pb_size_t; +typedef int_least8_t pb_ssize_t; #endif #define PB_SIZE_MAX ((pb_size_t)-1) @@ -237,17 +239,18 @@ typedef uint_least8_t pb_byte_t; PB_PACKED_STRUCT_START typedef struct pb_field_s pb_field_t; struct pb_field_s { - pb_size_t tag; - pb_type_t type; - pb_size_t data_offset; /* Offset of field data, relative to previous field. */ - pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ - pb_size_t data_size; /* Data size in bytes for a single item */ - pb_size_t array_size; /* Maximum number of entries in array */ - - /* Field definitions for submessage - * OR default value for all other non-array, non-callback types - * If null, then field will zeroed. */ - const void *ptr; + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t + size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; } pb_packed; PB_PACKED_STRUCT_END @@ -266,12 +269,17 @@ PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) * It has the number of bytes in the beginning, and after that an array. * Note that actual structs used will have a different length of bytes array. */ -#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } -#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) +#define PB_BYTES_ARRAY_T(n) \ + struct { \ + pb_size_t size; \ + pb_byte_t bytes[n]; \ + } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) \ + ((size_t)n + offsetof(pb_bytes_array_t, bytes)) struct pb_bytes_array_s { - pb_size_t size; - pb_byte_t bytes[1]; + pb_size_t size; + pb_byte_t bytes[1]; }; typedef struct pb_bytes_array_s pb_bytes_array_t; @@ -298,29 +306,31 @@ typedef struct pb_ostream_s pb_ostream_t; typedef struct pb_callback_s pb_callback_t; struct pb_callback_s { #ifdef PB_OLD_CALLBACK_STYLE - /* Deprecated since nanopb-0.2.1 */ - union { - bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); - bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); - } funcs; + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, + const void *arg); + } funcs; #else - /* New function signature, which allows modifying arg contents in callback. */ - union { - bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); - bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); - } funcs; -#endif - - /* Free arg for use by callback */ - void *arg; + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, + void *const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; }; /* Wire types. Library user needs these only in encoder callbacks. */ typedef enum { - PB_WT_VARINT = 0, - PB_WT_64BIT = 1, - PB_WT_STRING = 2, - PB_WT_32BIT = 5 + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 } pb_wire_type_t; /* Structure for defining the handling of unknown/extension fields. @@ -332,55 +342,55 @@ typedef enum { typedef struct pb_extension_type_s pb_extension_type_t; typedef struct pb_extension_s pb_extension_t; struct pb_extension_type_s { - /* Called for each unknown field in the message. - * If you handle the field, read off all of its data and return true. - * If you do not handle the field, do not read anything and return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, - uint32_t tag, pb_wire_type_t wire_type); - - /* Called once after all regular fields have been encoded. - * If you have something to write, do so and return true. - * If you do not have anything to write, just return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); - - /* Free field for use by the callback. */ - const void *arg; + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, + pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; }; struct pb_extension_s { - /* Type describing the extension field. Usually you'll initialize - * this to a pointer to the automatically generated structure. */ - const pb_extension_type_t *type; - - /* Destination for the decoded data. This must match the datatype - * of the extension field. */ - void *dest; - - /* Pointer to the next extension handler, or NULL. - * If this extension does not match a field, the next handler is - * automatically called. */ - pb_extension_t *next; - - /* The decoder sets this to true if the extension was found. - * Ignored for encoding. */ - bool found; + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; }; /* Memory allocation functions to use. You can define pb_realloc and * pb_free to custom functions if you want. */ #ifdef PB_ENABLE_MALLOC -# ifndef pb_realloc -# define pb_realloc(ptr, size) realloc(ptr, size) -# endif -# ifndef pb_free -# define pb_free(ptr) free(ptr) -# endif +#ifndef pb_realloc +#define pb_realloc(ptr, size) realloc(ptr, size) +#endif +#ifndef pb_free +#define pb_free(ptr) free(ptr) +#endif #endif /* This is used to inform about need to regenerate .pb.h/.pb.c files. */ @@ -388,90 +398,115 @@ struct pb_extension_s { /* These macros are used to declare pb_field_t's in the constant array. */ /* Size of a structure member, in bytes. */ -#define pb_membersize(st, m) (sizeof ((st*)0)->m) +#define pb_membersize(st, m) (sizeof((st *)0)->m) /* Number of entries in an array. */ #define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) /* Delta from start of one member to the start of another member. */ #define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) /* Marks the end of the field list */ -#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} +#define PB_LAST_FIELD \ + { 0, (pb_type_t)0, 0, 0, 0, 0, 0 } /* Macros for filling in the data_offset field */ /* data_offset for first field in a message */ #define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) /* data_offset for subsequent fields */ -#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +#define PB_DATAOFFSET_OTHER(st, m1, m2) \ + (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) /* data offset for subsequent fields inside an union (oneof) */ #define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX) -/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ -#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ - ? PB_DATAOFFSET_FIRST(st, m1, m2) \ - : PB_DATAOFFSET_OTHER(st, m1, m2)) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards + * compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) \ + (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) /* Required fields are the simplest. They just have delta (padding) from * previous field end, and the size of the field. Pointer is used for * submessages and default values. */ -#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } /* Optional fields add the delta to the has_ variable. */ -#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ - fd, \ - pb_delta(st, has_ ## m, m), \ - pb_membersize(st, m), 0, ptr} - -#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -/* Repeated fields have a _count field and also the maximum number of entries. */ -#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ - fd, \ - pb_delta(st, m ## _count, m), \ - pb_membersize(st, m[0]), \ - pb_arraysize(st, m), ptr} +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, fd, \ + pb_delta(st, has_##m, m), pb_membersize(st, m), 0, ptr \ + } + +#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } + +/* Repeated fields have a _count field and also the maximum number of entries. + */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, fd, \ + pb_delta(st, m##_count, m), pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr \ + } /* Allocated fields carry the size of the actual data, not the pointer */ -#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m[0]), 0, ptr} +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, fd, 0, \ + pb_membersize(st, m[0]), 0, ptr \ + } -/* Optional fields don't need a has_ variable, as information would be redundant */ -#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m[0]), 0, ptr} +/* Optional fields don't need a has_ variable, as information would be redundant + */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, fd, 0, \ + pb_membersize(st, m[0]), 0, ptr \ + } /* Same as optional fields*/ -#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m[0]), 0, ptr} +#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, fd, 0, \ + pb_membersize(st, m[0]), 0, ptr \ + } /* Repeated fields have a _count field and a pointer to array of pointers */ -#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ - fd, pb_delta(st, m ## _count, m), \ - pb_membersize(st, m[0]), 0, ptr} +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, fd, \ + pb_delta(st, m##_count, m), pb_membersize(st, m[0]), 0, ptr \ + } /* Callbacks are much like required fields except with special datatype. */ -#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } + +#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, fd, 0, \ + pb_membersize(st, m), 0, ptr \ + } /* Optional extensions don't have the has_ field, as that would be redundant. * Furthermore, the combination of OPTIONAL without has_ field is used @@ -479,38 +514,38 @@ struct pb_extension_s { * so they should be encoded according to proto2 rules. To avoid the conflict, * extensions are marked as REQUIRED instead. */ -#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ - 0, \ - 0, \ - pb_membersize(st, m), 0, ptr} +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, 0, 0, \ + pb_membersize(st, m), 0, ptr \ + } #define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ - PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) + PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) #define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ - PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) + PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) /* The mapping from protobuf types to LTYPEs is done using these macros. */ -#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL -#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES -#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT -#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE -#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING -#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION +#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION #define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES /* This is the actual macro used in field descriptions. @@ -521,58 +556,70 @@ struct pb_extension_s { * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION * - Field rules: REQUIRED, OPTIONAL or REPEATED * - Allocation: STATIC, CALLBACK or POINTER - * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * - Placement: FIRST or OTHER, depending on if this is the first field in + * structure. * - Message name * - Field name * - Previous field name (or field name again for first field) * - Pointer to default value or submsg fields. */ -#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ - PB_DATAOFFSET_ ## placement(message, field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, \ + prevfield, ptr) \ + PB_##rules##_##allocation( \ + tag, message, field, \ + PB_DATAOFFSET_##placement(message, field, prevfield), \ + PB_LTYPE_MAP_##type, ptr) /* Field description for repeated static fixed count fields.*/ -#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \ - PB_DATAOFFSET_ ## placement(message, field, prevfield), \ - 0, \ - pb_membersize(message, field[0]), \ - pb_arraysize(message, field), ptr} +#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, \ + prevfield, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_##type, \ + PB_DATAOFFSET_##placement(message, field, prevfield), 0, \ + pb_membersize(message, field[0]), pb_arraysize(message, field), ptr \ + } /* Field description for oneof fields. This requires taking into account the * union name also, that's why a separate set of macros is needed. */ -#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ - fd, pb_delta(st, which_ ## u, u.m), \ - pb_membersize(st, u.m), 0, ptr} - -#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ - fd, pb_delta(st, which_ ## u, u.m), \ - pb_membersize(st, u.m[0]), 0, ptr} - -#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ONEOF_ ## allocation(union_name, tag, message, field, \ - PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) +#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, fd, \ + pb_delta(st, which_##u, u.m), pb_membersize(st, u.m), 0, ptr \ + } + +#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, fd, \ + pb_delta(st, which_##u, u.m), pb_membersize(st, u.m[0]), 0, ptr \ + } + +#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, \ + message, field, prevfield, ptr) \ + PB_ONEOF_##allocation( \ + union_name, tag, message, field, \ + PB_DATAOFFSET_##placement(message, union_name.field, prevfield), \ + PB_LTYPE_MAP_##type, ptr) #define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ - fd, pb_delta(st, which_ ## u, m), \ - pb_membersize(st, m), 0, ptr} - -#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ - fd, pb_delta(st, which_ ## u, m), \ - pb_membersize(st, m[0]), 0, ptr} - -#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ - PB_DATAOFFSET_ ## placement(message, field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) + { \ + tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, fd, \ + pb_delta(st, which_##u, m), pb_membersize(st, m), 0, ptr \ + } + +#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + { \ + tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, fd, \ + pb_delta(st, which_##u, m), pb_membersize(st, m[0]), 0, ptr \ + } + +#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, \ + placement, message, field, prevfield, ptr) \ + PB_ANONYMOUS_ONEOF_##allocation( \ + union_name, tag, message, field, \ + PB_DATAOFFSET_##placement(message, field, prevfield), \ + PB_LTYPE_MAP_##type, ptr) /* These macros are used for giving out error messages. * They are mostly a debugging aid; the main error information @@ -590,7 +637,8 @@ struct pb_extension_s { #define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) #define PB_GET_ERROR(stream) "(errmsg disabled)" #else -#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) +#define PB_SET_ERROR(stream, msg) \ + (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) #define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") #endif diff --git a/include/pb_common.h b/include/pb_common.h index 60b3d3749..397feda76 100644 --- a/include/pb_common.h +++ b/include/pb_common.h @@ -13,18 +13,20 @@ extern "C" { /* Iterator for pb_field_t list */ struct pb_field_iter_s { - const pb_field_t *start; /* Start of the pb_field_t array */ - const pb_field_t *pos; /* Current position of the iterator */ - unsigned required_field_index; /* Zero-based index that counts only the required fields */ - void *dest_struct; /* Pointer to start of the structure */ - void *pData; /* Pointer to current field value */ - void *pSize; /* Pointer to count/has field */ + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the + required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ }; typedef struct pb_field_iter_s pb_field_iter_t; /* Initialize the field iterator structure to beginning. * Returns false if the message type is empty. */ -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, + void *dest_struct); /* Advance the iterator to the next field. * Returns false when the iterator wraps back to the first field. */ @@ -39,4 +41,3 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); #endif #endif - diff --git a/include/pb_decode.h b/include/pb_decode.h index 3577c2016..a4327d2df 100644 --- a/include/pb_decode.h +++ b/include/pb_decode.h @@ -15,7 +15,7 @@ extern "C" { /* Structure for defining custom input streams. You will need to provide * a callback function to read the bytes from your storage, which can be * for example a file or a network socket. - * + * * The callback must conform to these rules: * * 1) Return false on IO errors. This will cause decoding to abort. @@ -25,47 +25,47 @@ extern "C" { * is different than from the main stream. Don't use bytes_left to compute * any pointers. */ -struct pb_istream_s -{ +struct pb_istream_s { #ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - */ - int *callback; + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; #else - bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); + bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); #endif - void *state; /* Free field for use by callback implementation */ - size_t bytes_left; - + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + #ifndef PB_NO_ERRMSG - const char *errmsg; + const char *errmsg; #endif }; /*************************** * Main decoding functions * ***************************/ - -/* Decode a single protocol buffers message from input stream into a C structure. - * Returns true on success, false on any failure. - * The actual struct pointed to by dest must match the description in fields. - * Callback fields of the destination structure must be initialized by caller. - * All other fields will be initialized by this function. + +/* Decode a single protocol buffers message from input stream into a C + * structure. Returns true on success, false on any failure. The actual struct + * pointed to by dest must match the description in fields. Callback fields of + * the destination structure must be initialized by caller. All other fields + * will be initialized by this function. * * Example usage: * MyMessage msg = {}; * uint8_t buffer[64]; * pb_istream_t stream; - * + * * // ... read some data into buffer ... * * stream = pb_istream_from_buffer(buffer, count); * pb_decode(&stream, MyMessage_fields, &msg); */ -bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct); /* Same as pb_decode, except does not initialize the destination structure * to default values. This is slightly faster if you need no default values @@ -77,35 +77,38 @@ bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struc * Note: If this function returns with an error, it will not release any * dynamically allocated fields. You will need to call pb_release() yourself. */ -bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct); /* Same as pb_decode, except expects the stream to start with the message size * encoded as varint. Corresponds to parseDelimitedFrom() in Google's * protobuf API. */ -bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct); -/* Same as pb_decode_delimited, except that it does not initialize the destination structure. - * See pb_decode_noinit +/* Same as pb_decode_delimited, except that it does not initialize the + * destination structure. See pb_decode_noinit */ -bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct); -/* Same as pb_decode, except allows the message to be terminated with a null byte. - * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour - * is not supported in most other protobuf implementations, so pb_decode_delimited() - * is a better option for compatibility. +/* Same as pb_decode, except allows the message to be terminated with a null + * byte. NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. + * This behaviour is not supported in most other protobuf implementations, so + * pb_decode_delimited() is a better option for compatibility. */ -bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct); #ifdef PB_ENABLE_MALLOC -/* Release any allocated pointer fields. If you use dynamic allocation, you should - * call this for any successfully decoded message when you are done with it. If - * pb_decode() returns with an error, the message is already released. +/* Release any allocated pointer fields. If you use dynamic allocation, you + * should call this for any successfully decoded message when you are done with + * it. If pb_decode() returns with an error, the message is already released. */ void pb_release(const pb_field_t fields[], void *dest_struct); #endif - /************************************** * Functions for manipulating streams * **************************************/ @@ -122,14 +125,14 @@ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); */ bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); - /************************************************ * Helper functions for writing field callbacks * ************************************************/ /* Decode the tag for the next field in the stream. Gives the wire type and * field tag. At end of the message, returns false and sets eof to true. */ -bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, + uint32_t *tag, bool *eof); /* Skip the field payload data, given the wire type. */ bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); diff --git a/include/pb_encode.h b/include/pb_encode.h index 8bf78dd53..cb2eba1aa 100644 --- a/include/pb_encode.h +++ b/include/pb_encode.h @@ -24,25 +24,24 @@ extern "C" { * 4) Substreams will modify max_size and bytes_written. Don't use them * to calculate any pointers. */ -struct pb_ostream_s -{ +struct pb_ostream_s { #ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - * Also, NULL pointer marks a 'sizing stream' that does not - * write anything. - */ - int *callback; + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; #else - bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); + bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); #endif - void *state; /* Free field for use by callback implementation. */ - size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ - size_t bytes_written; /* Number of bytes written so far. */ - + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + #ifndef PB_NO_ERRMSG - const char *errmsg; + const char *errmsg; #endif }; @@ -52,8 +51,8 @@ struct pb_ostream_s /* Encode a single protocol buffers message from C structure into a stream. * Returns true on success, false on any failure. - * The actual struct pointed to by src_struct must match the description in fields. - * All required fields in the struct are assumed to have been filled in. + * The actual struct pointed to by src_struct must match the description in + * fields. All required fields in the struct are assumed to have been filled in. * * Example usage: * MyMessage msg = {}; @@ -64,22 +63,26 @@ struct pb_ostream_s * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); * pb_encode(&stream, MyMessage_fields, &msg); */ -bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct); /* Same as pb_encode, but prepends the length of the message as a varint. * Corresponds to writeDelimitedTo() in Google's protobuf API. */ -bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct); /* Same as pb_encode, but appends a null byte to the message for termination. - * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() - * is a better option for compatibility. + * NOTE: This behaviour is not supported in most other protobuf implementations, + * so pb_encode_delimited() is a better option for compatibility. */ -bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct); /* Encode the message to get the size of the encoded data, but do not store * the data. */ -bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], + const void *src_struct); /************************************** * Functions for manipulating streams * @@ -96,7 +99,7 @@ pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); /* Pseudo-stream for measuring the size of a message without actually storing * the encoded data. - * + * * Example usage: * MyMessage msg = {}; * pb_ostream_t stream = PB_OSTREAM_SIZING; @@ -104,9 +107,11 @@ pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); * printf("Message size is %d\n", stream.bytes_written); */ #ifndef PB_NO_ERRMSG -#define PB_OSTREAM_SIZING {0,0,0,0,0} +#define PB_OSTREAM_SIZING \ + { 0, 0, 0, 0, 0 } #else -#define PB_OSTREAM_SIZING {0,0,0,0} +#define PB_OSTREAM_SIZING \ + { 0, 0, 0, 0 } #endif /* Function to write into a pb_ostream_t stream. You can use this if you need @@ -114,7 +119,6 @@ pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); */ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); - /************************************************ * Helper functions for writing field callbacks * ************************************************/ @@ -125,7 +129,8 @@ bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); /* Encode field header by manually specifing wire type. You need to use this * if you want to write out packed arrays from a callback field. */ -bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, + uint32_t field_number); /* Encode an integer in the varint format. * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ @@ -144,7 +149,8 @@ bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); #endif /* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ -bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); +bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, + size_t size); /* Encode a fixed32, sfixed32 or float value. * You need to pass a pointer to a 4-byte wide C variable. */ @@ -161,7 +167,8 @@ bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); * with pb_encode(). This internally encodes the submessage twice, first to * calculate message size and then to actually write it out. */ -bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct); #ifdef __cplusplus } /* extern "C" */ diff --git a/lib/board/check_bootloader.c b/lib/board/check_bootloader.c index 1077a36b1..ce53a74ec 100644 --- a/lib/board/check_bootloader.c +++ b/lib/board/check_bootloader.c @@ -20,7 +20,7 @@ #include "keepkey/board/check_bootloader.h" #ifndef EMULATOR -# include +#include #endif #include "trezor/crypto/sha2.h" @@ -31,84 +31,107 @@ #include #include -char bl_hash_v1_0_0_hotpatched[32] = "\xf1\x3c\xe2\x28\xc0\xbb\x2b\xdb\xc5\x6b\xdc\xb5\xf4\x56\x93\x67\xf8\xe3\x01\x10\x74\xcc\xc6\x33\x31\x34\x8d\xeb\x49\x8f\x2d\x8f"; -char bl_hash_v1_0_1_hotpatched[32] = "\xec\x61\x88\x36\xf8\x64\x23\xdb\xd3\x11\x4c\x37\xd6\xe3\xe4\xff\xdf\xb8\x7d\x9e\x4c\x61\x99\xcf\x3e\x16\x3a\x67\xb2\x74\x98\xa2"; -char bl_hash_v1_0_2_hotpatched[32] = "\xbc\xaf\xb3\x8c\xd0\xfb\xd6\xe2\xbd\xbe\xa8\x9f\xb9\x02\x35\x55\x9f\xdd\xa3\x60\x76\x5b\x74\xe4\xa8\x75\x8b\x4e\xff\x2d\x49\x21"; -char bl_hash_v1_0_3_hotpatched[32] = "\x83\xd1\x4c\xb6\xc7\xc4\x8a\xf2\xa8\x3b\xc3\x26\x35\x3e\xe6\xb9\xab\xdd\x74\xcf\xe4\x7b\xa5\x67\xde\x1c\xb5\x64\xda\x65\xe8\xe9"; -char bl_hash_v1_0_3_sig_hotpatched[32] = "\x91\x7d\x19\x52\x26\x0c\x9b\x89\xf3\xa9\x6b\xea\x07\xee\xa4\x07\x4a\xfd\xcc\x0e\x8c\xdd\x5d\x06\x4e\x36\x86\x8b\xdd\x68\xba\x7d"; -char bl_hash_v1_0_3_elf_hotpatched[32] = "\xdb\x4b\xc3\x89\x33\x5e\x87\x6e\x94\x2a\xe3\xb1\x25\x58\xce\xcd\x20\x2b\x74\x59\x03\xe7\x9b\x34\xdd\x2c\x32\x53\x27\x08\x86\x0e"; -char bl_hash_v1_0_4_hotpatched[32] = "\xfc\x4e\x5c\x4d\xc2\xe5\x12\x7b\x68\x14\xa3\xf6\x94\x24\xc9\x36\xf1\xdc\x24\x1d\x1d\xaf\x2c\x5a\x2d\x8f\x07\x28\xeb\x69\xd2\x0d"; - -char bl_hash_v1_0_0_unpatched[32] = "\x63\x97\xc4\x46\xf6\xb9\x00\x2a\x8b\x15\x0b\xf4\xb9\xb4\xe0\xbb\x66\x80\x0e\xd0\x99\xb8\x81\xca\x49\x70\x01\x39\xb0\x55\x9f\x10"; -char bl_hash_v1_0_1_unpatched[32] = "\xd5\x44\xb5\xe0\x6b\x0c\x35\x5d\x68\xb8\x68\xac\x75\x80\xe9\xba\xb2\xd2\x24\xa1\xe2\x44\x08\x81\xcc\x1b\xca\x2b\x81\x67\x52\xd5"; -char bl_hash_v1_0_2_unpatched[32] = "\xcd\x70\x2b\x91\x02\x8a\x2c\xfa\x55\xaf\x43\xd3\x40\x7b\xa0\xf6\xf7\x52\xa4\xa2\xbe\x05\x83\xa1\x72\x98\x3b\x30\x3a\xb1\x03\x2e"; -char bl_hash_v1_0_3_unpatched[32] = "\x2e\x38\x95\x01\x43\xcf\x35\x03\x45\xa6\xdd\xad\xa4\xc0\xc4\xf2\x1e\xb2\xed\x33\x73\x09\xf3\x9c\x5d\xbc\x70\xb6\xc0\x91\xae\x00"; -char bl_hash_v1_0_3_sig_unpatched[32] = "\xcb\x22\x25\x48\xa3\x9f\xf6\xcb\xe2\xae\x2f\x02\xc8\xd4\x31\xc9\xae\x0d\xf8\x50\xf8\x14\x44\x49\x11\xf5\x21\xb9\x5a\xb0\x2f\x4c"; -char bl_hash_v1_0_3_elf_unpatched[32] = "\x64\x65\xbc\x50\x55\x86\x70\x0a\x81\x11\xc4\xbf\x7d\xb6\xf4\x0a\xf7\x3e\x72\x0f\x9e\x48\x8d\x20\xdb\x56\x13\x5e\x5a\x69\x0c\x4f"; -char bl_hash_v1_0_4_unpatched[32] = "\x77\x0b\x30\xaa\xa0\xbe\x88\x4e\xe8\x62\x18\x59\xf5\xd0\x55\x43\x7f\x89\x4a\x5c\x9c\x7c\xa2\x26\x35\xe7\x02\x4e\x05\x98\x57\xb7"; - -char bl_hash_v1_1_0[32] = "\xe4\x5f\x58\x7f\xb0\x75\x33\xd8\x32\x54\x84\x02\xd0\xe7\x1d\x8e\x82\x34\x88\x1d\xa5\x4d\x86\xc4\xb6\x99\xc2\x8a\x64\x82\xb0\xee"; -char bl_hash_v2_0_0[32] = "\x9b\xf1\x58\x0d\x1b\x21\x25\x0f\x92\x2b\x68\x79\x4c\xda\xdd\x6c\x8e\x16\x6a\xe5\xb1\x5c\xe1\x60\xa4\x2f\x8c\x44\xa2\xf0\x59\x36"; +char bl_hash_v1_0_0_hotpatched[32] = + "\xf1\x3c\xe2\x28\xc0\xbb\x2b\xdb\xc5\x6b\xdc\xb5\xf4\x56\x93\x67\xf8\xe3" + "\x01\x10\x74\xcc\xc6\x33\x31\x34\x8d\xeb\x49\x8f\x2d\x8f"; +char bl_hash_v1_0_1_hotpatched[32] = + "\xec\x61\x88\x36\xf8\x64\x23\xdb\xd3\x11\x4c\x37\xd6\xe3\xe4\xff\xdf\xb8" + "\x7d\x9e\x4c\x61\x99\xcf\x3e\x16\x3a\x67\xb2\x74\x98\xa2"; +char bl_hash_v1_0_2_hotpatched[32] = + "\xbc\xaf\xb3\x8c\xd0\xfb\xd6\xe2\xbd\xbe\xa8\x9f\xb9\x02\x35\x55\x9f\xdd" + "\xa3\x60\x76\x5b\x74\xe4\xa8\x75\x8b\x4e\xff\x2d\x49\x21"; +char bl_hash_v1_0_3_hotpatched[32] = + "\x83\xd1\x4c\xb6\xc7\xc4\x8a\xf2\xa8\x3b\xc3\x26\x35\x3e\xe6\xb9\xab\xdd" + "\x74\xcf\xe4\x7b\xa5\x67\xde\x1c\xb5\x64\xda\x65\xe8\xe9"; +char bl_hash_v1_0_3_sig_hotpatched[32] = + "\x91\x7d\x19\x52\x26\x0c\x9b\x89\xf3\xa9\x6b\xea\x07\xee\xa4\x07\x4a\xfd" + "\xcc\x0e\x8c\xdd\x5d\x06\x4e\x36\x86\x8b\xdd\x68\xba\x7d"; +char bl_hash_v1_0_3_elf_hotpatched[32] = + "\xdb\x4b\xc3\x89\x33\x5e\x87\x6e\x94\x2a\xe3\xb1\x25\x58\xce\xcd\x20\x2b" + "\x74\x59\x03\xe7\x9b\x34\xdd\x2c\x32\x53\x27\x08\x86\x0e"; +char bl_hash_v1_0_4_hotpatched[32] = + "\xfc\x4e\x5c\x4d\xc2\xe5\x12\x7b\x68\x14\xa3\xf6\x94\x24\xc9\x36\xf1\xdc" + "\x24\x1d\x1d\xaf\x2c\x5a\x2d\x8f\x07\x28\xeb\x69\xd2\x0d"; + +char bl_hash_v1_0_0_unpatched[32] = + "\x63\x97\xc4\x46\xf6\xb9\x00\x2a\x8b\x15\x0b\xf4\xb9\xb4\xe0\xbb\x66\x80" + "\x0e\xd0\x99\xb8\x81\xca\x49\x70\x01\x39\xb0\x55\x9f\x10"; +char bl_hash_v1_0_1_unpatched[32] = + "\xd5\x44\xb5\xe0\x6b\x0c\x35\x5d\x68\xb8\x68\xac\x75\x80\xe9\xba\xb2\xd2" + "\x24\xa1\xe2\x44\x08\x81\xcc\x1b\xca\x2b\x81\x67\x52\xd5"; +char bl_hash_v1_0_2_unpatched[32] = + "\xcd\x70\x2b\x91\x02\x8a\x2c\xfa\x55\xaf\x43\xd3\x40\x7b\xa0\xf6\xf7\x52" + "\xa4\xa2\xbe\x05\x83\xa1\x72\x98\x3b\x30\x3a\xb1\x03\x2e"; +char bl_hash_v1_0_3_unpatched[32] = + "\x2e\x38\x95\x01\x43\xcf\x35\x03\x45\xa6\xdd\xad\xa4\xc0\xc4\xf2\x1e\xb2" + "\xed\x33\x73\x09\xf3\x9c\x5d\xbc\x70\xb6\xc0\x91\xae\x00"; +char bl_hash_v1_0_3_sig_unpatched[32] = + "\xcb\x22\x25\x48\xa3\x9f\xf6\xcb\xe2\xae\x2f\x02\xc8\xd4\x31\xc9\xae\x0d" + "\xf8\x50\xf8\x14\x44\x49\x11\xf5\x21\xb9\x5a\xb0\x2f\x4c"; +char bl_hash_v1_0_3_elf_unpatched[32] = + "\x64\x65\xbc\x50\x55\x86\x70\x0a\x81\x11\xc4\xbf\x7d\xb6\xf4\x0a\xf7\x3e" + "\x72\x0f\x9e\x48\x8d\x20\xdb\x56\x13\x5e\x5a\x69\x0c\x4f"; +char bl_hash_v1_0_4_unpatched[32] = + "\x77\x0b\x30\xaa\xa0\xbe\x88\x4e\xe8\x62\x18\x59\xf5\xd0\x55\x43\x7f\x89" + "\x4a\x5c\x9c\x7c\xa2\x26\x35\xe7\x02\x4e\x05\x98\x57\xb7"; + +char bl_hash_v1_1_0[32] = + "\xe4\x5f\x58\x7f\xb0\x75\x33\xd8\x32\x54\x84\x02\xd0\xe7\x1d\x8e\x82\x34" + "\x88\x1d\xa5\x4d\x86\xc4\xb6\x99\xc2\x8a\x64\x82\xb0\xee"; +char bl_hash_v2_0_0[32] = + "\x9b\xf1\x58\x0d\x1b\x21\x25\x0f\x92\x2b\x68\x79\x4c\xda\xdd\x6c\x8e\x16" + "\x6a\xe5\xb1\x5c\xe1\x60\xa4\x2f\x8c\x44\xa2\xf0\x59\x36"; +char bl_hash_v2_1_0[32]; // TODO: Update this with the release hash of the + // bootloader BootloaderKind get_bootloaderKind(void) { - static uint8_t bl_hash[SHA256_DIGEST_LENGTH]; - if (32 != memory_bootloader_hash(bl_hash, /*cached=*/ false)) - return BLK_UNKNOWN; + static uint8_t bl_hash[SHA256_DIGEST_LENGTH]; + if (32 != memory_bootloader_hash(bl_hash, /*cached=*/false)) + return BLK_UNKNOWN; - // Hotpatch unnecessary - // -------------------- - if (0 == memcmp(bl_hash, bl_hash_v1_1_0, 32)) - return BLK_v1_1_0; + // Hotpatch unnecessary + // -------------------- + if (0 == memcmp(bl_hash, bl_hash_v1_1_0, 32)) return BLK_v1_1_0; - if (0 == memcmp(bl_hash, bl_hash_v2_0_0, 32)) - return BLK_v2_0_0; + if (0 == memcmp(bl_hash, bl_hash_v2_0_0, 32)) return BLK_v2_0_0; - // Hotpatched bootloaders - // ---------------------- - if (0 == memcmp(bl_hash, bl_hash_v1_0_0_hotpatched, 32)) - return BLK_v1_0_0; + if (0 == memcmp(bl_hash, bl_hash_v2_1_0, 32)) return BLK_v2_1_0; - if (0 == memcmp(bl_hash, bl_hash_v1_0_1_hotpatched, 32)) - return BLK_v1_0_1; + // Hotpatched bootloaders + // ---------------------- + if (0 == memcmp(bl_hash, bl_hash_v1_0_0_hotpatched, 32)) return BLK_v1_0_0; - if (0 == memcmp(bl_hash, bl_hash_v1_0_2_hotpatched, 32)) - return BLK_v1_0_2; + if (0 == memcmp(bl_hash, bl_hash_v1_0_1_hotpatched, 32)) return BLK_v1_0_1; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_hotpatched, 32)) - return BLK_v1_0_3; + if (0 == memcmp(bl_hash, bl_hash_v1_0_2_hotpatched, 32)) return BLK_v1_0_2; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_sig_hotpatched, 32)) - return BLK_v1_0_3_sig; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_hotpatched, 32)) return BLK_v1_0_3; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_elf_hotpatched, 32)) - return BLK_v1_0_3_elf; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_sig_hotpatched, 32)) + return BLK_v1_0_3_sig; - if (0 == memcmp(bl_hash, bl_hash_v1_0_4_hotpatched, 32)) - return BLK_v1_0_4; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_elf_hotpatched, 32)) + return BLK_v1_0_3_elf; - // Unpatched bootloaders - // --------------------- - if (0 == memcmp(bl_hash, bl_hash_v1_0_0_unpatched, 32)) - return BLK_v1_0_0; + if (0 == memcmp(bl_hash, bl_hash_v1_0_4_hotpatched, 32)) return BLK_v1_0_4; - if (0 == memcmp(bl_hash, bl_hash_v1_0_1_unpatched, 32)) - return BLK_v1_0_1; + // Unpatched bootloaders + // --------------------- + if (0 == memcmp(bl_hash, bl_hash_v1_0_0_unpatched, 32)) return BLK_v1_0_0; - if (0 == memcmp(bl_hash, bl_hash_v1_0_2_unpatched, 32)) - return BLK_v1_0_2; + if (0 == memcmp(bl_hash, bl_hash_v1_0_1_unpatched, 32)) return BLK_v1_0_1; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_unpatched, 32)) - return BLK_v1_0_3; + if (0 == memcmp(bl_hash, bl_hash_v1_0_2_unpatched, 32)) return BLK_v1_0_2; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_sig_unpatched, 32)) - return BLK_v1_0_3_sig; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_unpatched, 32)) return BLK_v1_0_3; - if (0 == memcmp(bl_hash, bl_hash_v1_0_3_elf_unpatched, 32)) - return BLK_v1_0_3_elf; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_sig_unpatched, 32)) + return BLK_v1_0_3_sig; - if (0 == memcmp(bl_hash, bl_hash_v1_0_4_unpatched, 32)) - return BLK_v1_0_4; + if (0 == memcmp(bl_hash, bl_hash_v1_0_3_elf_unpatched, 32)) + return BLK_v1_0_3_elf; - return BLK_UNKNOWN; -} + if (0 == memcmp(bl_hash, bl_hash_v1_0_4_unpatched, 32)) return BLK_v1_0_4; + return BLK_UNKNOWN; +} diff --git a/lib/board/common.c b/lib/board/common.c index 85b3cb554..06e4518d6 100644 --- a/lib/board/common.c +++ b/lib/board/common.c @@ -25,7 +25,7 @@ #include "trezor/crypto/rand.h" #ifndef EMULATOR -# include +#include #endif #include diff --git a/lib/board/confirm_sm.c b/lib/board/confirm_sm.c index 85098325f..d35a514c5 100644 --- a/lib/board/confirm_sm.c +++ b/lib/board/confirm_sm.c @@ -28,7 +28,7 @@ #include "trezor/crypto/memzero.h" #ifndef EMULATOR -# include +#include #endif #include @@ -48,117 +48,113 @@ static CONFIDENTIAL char strbuf[BODY_CHAR_MAX]; /// Handler for push button being pressed. /// \param context current state context. -static void handle_screen_press(void *context) -{ - assert(context != NULL); +static void handle_screen_press(void *context) { + assert(context != NULL); - StateInfo *si = (StateInfo *)context; + StateInfo *si = (StateInfo *)context; - if(button_request_acked) - { - switch(si->display_state) - { - case HOME: - si->active_layout = LAYOUT_CONFIRM_ANIMATION; - si->display_state = CONFIRM_WAIT; - break; + if (button_request_acked) { + switch (si->display_state) { + case HOME: + si->active_layout = LAYOUT_CONFIRM_ANIMATION; + si->display_state = CONFIRM_WAIT; + break; - default: - break; - } + default: + break; } + } } /// Handler for push button being pressed. /// \param context current state context. -static void handle_screen_release(void *context) -{ - assert(context != NULL); +static void handle_screen_release(void *context) { + assert(context != NULL); - StateInfo *si = (StateInfo *)context; + StateInfo *si = (StateInfo *)context; - switch(si->display_state) - { - case CONFIRM_WAIT: - si->active_layout = LAYOUT_REQUEST_NO_ANIMATION; - si->display_state = HOME; - break; + switch (si->display_state) { + case CONFIRM_WAIT: + si->active_layout = LAYOUT_REQUEST_NO_ANIMATION; + si->display_state = HOME; + break; - case CONFIRMED: - si->active_layout = LAYOUT_FINISHED; - si->display_state = FINISHED; - break; + case CONFIRMED: + si->active_layout = LAYOUT_FINISHED; + si->display_state = FINISHED; + break; - default: - break; - } + default: + break; + } } /// User has held down the push button for duration as requested. /// \param context current state context. -static void handle_confirm_timeout(void *context) -{ - assert(context != NULL); +static void handle_confirm_timeout(void *context) { + assert(context != NULL); - StateInfo *si = (StateInfo *)context; - si->display_state = CONFIRMED; - si->active_layout = LAYOUT_CONFIRMED; + StateInfo *si = (StateInfo *)context; + si->display_state = CONFIRMED; + si->active_layout = LAYOUT_CONFIRMED; } /// Changes the active layout of the confirmation screen. /// \param active_layout The layout to swtich to. /// \param si current state information. -/// \param layout_notification_func layout callback for displaying confirm message. +/// \param layout_notification_func layout callback for displaying confirm +/// message. static void swap_layout(ActiveLayout active_layout, volatile StateInfo *si, - layout_notification_t layout_notification_func) -{ - switch(active_layout) - { - case LAYOUT_REQUEST: - (*layout_notification_func)(si->lines[active_layout].request_title, - si->lines[active_layout].request_body, NOTIFICATION_REQUEST); - remove_runnable(&handle_confirm_timeout); - break; - - case LAYOUT_REQUEST_NO_ANIMATION: - (*layout_notification_func)(si->lines[active_layout].request_title, - si->lines[active_layout].request_body, NOTIFICATION_REQUEST_NO_ANIMATION); - remove_runnable(&handle_confirm_timeout); - break; - - case LAYOUT_CONFIRM_ANIMATION: - (*layout_notification_func)(si->lines[active_layout].request_title, - si->lines[active_layout].request_body, NOTIFICATION_CONFIRM_ANIMATION); - post_delayed(&handle_confirm_timeout, (void *)si, CONFIRM_TIMEOUT_MS); - break; - - case LAYOUT_CONFIRMED: - - /* Finish confirming animation */ - while(is_animating()) - { - animate(); - display_refresh(); - } - - (*layout_notification_func)(si->lines[active_layout].request_title, - si->lines[active_layout].request_body, NOTIFICATION_CONFIRMED); - remove_runnable(&handle_confirm_timeout); - break; + layout_notification_t layout_notification_func) { + switch (active_layout) { + case LAYOUT_REQUEST: + (*layout_notification_func)(si->lines[active_layout].request_title, + si->lines[active_layout].request_body, + NOTIFICATION_REQUEST); + remove_runnable(&handle_confirm_timeout); + break; + + case LAYOUT_REQUEST_NO_ANIMATION: + (*layout_notification_func)(si->lines[active_layout].request_title, + si->lines[active_layout].request_body, + NOTIFICATION_REQUEST_NO_ANIMATION); + remove_runnable(&handle_confirm_timeout); + break; + + case LAYOUT_CONFIRM_ANIMATION: + (*layout_notification_func)(si->lines[active_layout].request_title, + si->lines[active_layout].request_body, + NOTIFICATION_CONFIRM_ANIMATION); + post_delayed(&handle_confirm_timeout, (void *)si, CONFIRM_TIMEOUT_MS); + break; + + case LAYOUT_CONFIRMED: + + /* Finish confirming animation */ + while (is_animating()) { + animate(); + display_refresh(); + } - default: - assert(0); - }; + (*layout_notification_func)(si->lines[active_layout].request_title, + si->lines[active_layout].request_body, + NOTIFICATION_CONFIRMED); + remove_runnable(&handle_confirm_timeout); + break; + default: + assert(0); + }; } /// Common confirmation function. /// \param request_title The confirmation's title. /// \param requesta_body The body of the confirmation message. -/// \param layout_notification_func layout callback for displaying confirm message. -/// \returns true iff the device confirmed. +/// \param layout_notification_func layout callback for displaying confirm +/// message. \returns true iff the device confirmed. static bool confirm_helper(const char *request_title, const char *request_body, - layout_notification_t layout_notification_func) + layout_notification_t layout_notification_func, + bool constant_power) { bool ret_stat = false; volatile StateInfo state_info; @@ -168,49 +164,50 @@ static bool confirm_helper(const char *request_title, const char *request_body, static CONFIDENTIAL uint8_t msg_tiny_buf[MSG_TINY_BFR_SZ]; #if DEBUG_LINK - DebugLinkDecision *dld; - bool debug_decided = false; + DebugLinkDecision *dld; + bool debug_decided = false; #endif - reset_msg_stack = false; + reset_msg_stack = false; - memset((void *)&state_info, 0, sizeof(state_info)); - state_info.display_state = HOME; - state_info.active_layout = LAYOUT_REQUEST; + memset((void *)&state_info, 0, sizeof(state_info)); + state_info.display_state = HOME; + state_info.active_layout = LAYOUT_REQUEST; - /* Request */ - state_info.lines[LAYOUT_REQUEST].request_title = request_title; - state_info.lines[LAYOUT_REQUEST].request_body = request_body; - state_info.lines[LAYOUT_REQUEST_NO_ANIMATION].request_title = request_title; - state_info.lines[LAYOUT_REQUEST_NO_ANIMATION].request_body = request_body; + /* Request */ + state_info.lines[LAYOUT_REQUEST].request_title = request_title; + state_info.lines[LAYOUT_REQUEST].request_body = request_body; + state_info.lines[LAYOUT_REQUEST_NO_ANIMATION].request_title = request_title; + state_info.lines[LAYOUT_REQUEST_NO_ANIMATION].request_body = request_body; - /* Confirming */ - state_info.lines[LAYOUT_CONFIRM_ANIMATION].request_title = request_title; - state_info.lines[LAYOUT_CONFIRM_ANIMATION].request_body = request_body; + /* Confirming */ + state_info.lines[LAYOUT_CONFIRM_ANIMATION].request_title = request_title; + state_info.lines[LAYOUT_CONFIRM_ANIMATION].request_body = request_body; - /* Confirmed */ - state_info.lines[LAYOUT_CONFIRMED].request_title = request_title; - state_info.lines[LAYOUT_CONFIRMED].request_body = request_body; + /* Confirmed */ + state_info.lines[LAYOUT_CONFIRMED].request_title = request_title; + state_info.lines[LAYOUT_CONFIRMED].request_body = request_body; - keepkey_button_set_on_press_handler(&handle_screen_press, (void *)&state_info); - keepkey_button_set_on_release_handler(&handle_screen_release, (void *)&state_info); + keepkey_button_set_on_press_handler(&handle_screen_press, + (void *)&state_info); + keepkey_button_set_on_release_handler(&handle_screen_release, + (void *)&state_info); - cur_layout = LAYOUT_INVALID; + cur_layout = LAYOUT_INVALID; - while(1) - { + while (1) { #ifndef EMULATOR - svc_disable_interrupts(); + svc_disable_interrupts(); #endif - new_layout = state_info.active_layout; - new_ds = state_info.display_state; + new_layout = state_info.active_layout; + new_ds = state_info.display_state; #ifndef EMULATOR - svc_enable_interrupts(); + svc_enable_interrupts(); #endif - /* Don't process usb tiny message unless usb has been initialized */ + /* Don't process usb tiny message unless usb has been initialized */ #ifndef EMULATOR - if (usbInitialized()) + if (usbInitialized()) #else if(1) #endif @@ -272,16 +269,18 @@ static bool confirm_helper(const char *request_title, const char *request_body, #endif + display_constant_power(constant_power); + display_refresh(); animate(); } confirm_helper_exit: - keepkey_button_set_on_press_handler(NULL, NULL); - keepkey_button_set_on_release_handler(NULL, NULL); + keepkey_button_set_on_press_handler(NULL, NULL); + keepkey_button_set_on_release_handler(NULL, NULL); - return(ret_stat); + return (ret_stat); } bool confirm(ButtonRequestType type, const char *request_title, const char *request_body, @@ -301,11 +300,35 @@ bool confirm(ButtonRequestType type, const char *request_title, const char *requ resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification); + bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification, false); memzero(strbuf, sizeof(strbuf)); return ret; } +bool confirm_constant_power(ButtonRequestType type, const char *request_title, const char *request_body, + ...) +{ + button_request_acked = false; + + va_list vl; + va_start(vl, request_body); + vsnprintf(strbuf, BODY_CHAR_MAX, request_body, vl); + va_end(vl); + + /* Send button request */ + ButtonRequest resp; + memset(&resp, 0, sizeof(ButtonRequest)); + resp.has_code = true; + resp.code = type; + msg_write(MessageType_MessageType_ButtonRequest, &resp); + + bool ret = confirm_helper(request_title, strbuf, &layout_constant_power_notification, true); + memzero(strbuf, sizeof(strbuf)); + return ret; +} + + + bool confirm_with_custom_button_request(ButtonRequest *button_request, const char *request_title, const char *request_body, ...) @@ -320,7 +343,7 @@ bool confirm_with_custom_button_request(ButtonRequest *button_request, /* Send button request */ msg_write(MessageType_MessageType_ButtonRequest, button_request); - bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification); + bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification, false); memzero(strbuf, sizeof(strbuf)); return ret; } @@ -343,7 +366,7 @@ bool confirm_with_custom_layout(layout_notification_t layout_notification_func, resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - bool ret = confirm_helper(request_title, strbuf, layout_notification_func); + bool ret = confirm_helper(request_title, strbuf, layout_notification_func, false); memzero(strbuf, sizeof(strbuf)); return ret; } @@ -358,7 +381,7 @@ bool confirm_without_button_request(const char *request_title, const char *reque vsnprintf(strbuf, BODY_CHAR_MAX, request_body, vl); va_end(vl); - bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification); + bool ret = confirm_helper(request_title, strbuf, &layout_standard_notification, false); memzero(strbuf, sizeof(strbuf)); return ret; } @@ -380,7 +403,7 @@ bool review(ButtonRequestType type, const char *request_title, const char *reque resp.code = type; msg_write(MessageType_MessageType_ButtonRequest, &resp); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification); + (void)confirm_helper(request_title, strbuf, &layout_standard_notification, false); memzero(strbuf, sizeof(strbuf)); return true; } @@ -395,7 +418,7 @@ bool review_without_button_request(const char *request_title, const char *reques vsnprintf(strbuf, BODY_CHAR_MAX, request_body, vl); va_end(vl); - (void)confirm_helper(request_title, strbuf, &layout_standard_notification); + (void)confirm_helper(request_title, strbuf, &layout_standard_notification, false); memzero(strbuf, sizeof(strbuf)); return true; } diff --git a/lib/board/draw.c b/lib/board/draw.c index a8494ddc8..7c5cb896e 100644 --- a/lib/board/draw.c +++ b/lib/board/draw.c @@ -42,64 +42,57 @@ * OUTPUT * true/false whether image was drawn */ -bool draw_char_with_shift(Canvas *canvas, DrawableParams *p, - uint16_t *x_shift, uint16_t *y_shift, const CharacterImage *img) -{ - bool ret_stat = false; - - uint16_t start_index = (p->y * canvas->width) + p->x; - /* Check start_index, p->x, p->y are within bounds */ - if (start_index >= (KEEPKEY_DISPLAY_HEIGHT * KEEPKEY_DISPLAY_WIDTH)){ - return false; - } - uint8_t *canvas_pixel = &canvas->buffer[ start_index ]; - uint8_t *canvas_end = &canvas->buffer[canvas->width * canvas->height]; - - /* Check that this was a character that we have in the font */ - if(img != NULL) - { - /* Check that it's within bounds. */ - if(((img->width + p->x) <= canvas->width) && - ((img->height + p->y) <= canvas->height)) - { - const uint8_t *img_pixel = &img->data[ 0 ]; - - int y; - - for(y = 0; y < img->height; y++) - { - int x; - - for(x = 0; x < img->width; x++) - { - if (canvas_pixel >= canvas_end){ - return false; // defensive bounds check - } - *canvas_pixel = (*img_pixel == 0x00) ? p->color : *canvas_pixel; - canvas_pixel++; - img_pixel++; - } - - canvas_pixel += (canvas->width - img->width); - } - - if(x_shift != NULL) - { - *x_shift += img->width; - } - - if(y_shift != NULL) - { - *y_shift += img->height; - } - - ret_stat = true; +bool draw_char_with_shift(Canvas *canvas, DrawableParams *p, uint16_t *x_shift, + uint16_t *y_shift, const CharacterImage *img) { + bool ret_stat = false; + + uint16_t start_index = (p->y * canvas->width) + p->x; + /* Check start_index, p->x, p->y are within bounds */ + if (start_index >= (KEEPKEY_DISPLAY_HEIGHT * KEEPKEY_DISPLAY_WIDTH)) { + return false; + } + uint8_t *canvas_pixel = &canvas->buffer[start_index]; + uint8_t *canvas_end = &canvas->buffer[canvas->width * canvas->height]; + + /* Check that this was a character that we have in the font */ + if (img != NULL) { + /* Check that it's within bounds. */ + if (((img->width + p->x) <= canvas->width) && + ((img->height + p->y) <= canvas->height)) { + const uint8_t *img_pixel = &img->data[0]; + + int y; + + for (y = 0; y < img->height; y++) { + int x; + + for (x = 0; x < img->width; x++) { + if (canvas_pixel >= canvas_end) { + return false; // defensive bounds check + } + *canvas_pixel = (*img_pixel == 0x00) ? p->color : *canvas_pixel; + canvas_pixel++; + img_pixel++; } + + canvas_pixel += (canvas->width - img->width); + } + + if (x_shift != NULL) { + *x_shift += img->width; + } + + if (y_shift != NULL) { + *y_shift += img->height; + } + + ret_stat = true; } + } - canvas->dirty = true; + canvas->dirty = true; - return(ret_stat); + return (ret_stat); } /* @@ -116,66 +109,60 @@ bool draw_char_with_shift(Canvas *canvas, DrawableParams *p, * none */ void draw_string(Canvas *canvas, const Font *font, const char *str_write, - DrawableParams *p, uint16_t width, uint16_t line_height) -{ - if (!canvas) { - return; + DrawableParams *p, uint16_t width, uint16_t line_height) { + if (!canvas) { + return; + } + + bool have_space = true; + uint16_t x_offset = 0; + DrawableParams char_params = *p; + + while (*str_write && have_space) { + const CharacterImage *img = font_get_char(font, *str_write); + uint16_t word_width = img->width; + char *next_c = (char *)str_write + 1; + + /* Allow line breaks */ + if (*str_write == '\n') { + char_params.y += line_height; + x_offset = 0; + str_write++; + continue; } - bool have_space = true; - uint16_t x_offset = 0; - DrawableParams char_params = *p; - - while(*str_write && have_space) - { - const CharacterImage *img = font_get_char(font, *str_write); - uint16_t word_width = img->width; - char *next_c = (char *)str_write + 1; - - /* Allow line breaks */ - if(*str_write == '\n') - { - char_params.y += line_height; - x_offset = 0; - str_write++; - continue; - } - - /* - * Calculate the next word width while - * removing spacings at beginning of lines - */ - if(*str_write == ' ') - { - - while(*next_c && *next_c != ' ' && *next_c != '\n') - { - word_width += font_get_char(font, *next_c)->width; - next_c++; - } - } - - /* Determine if we need a line break */ - if((width != 0) && (width <= canvas->width) && (x_offset + word_width > width)) - { - char_params.y += line_height; - x_offset = 0; - } + /* + * Calculate the next word width while + * removing spacings at beginning of lines + */ + if (*str_write == ' ') { + while (*next_c && *next_c != ' ' && *next_c != '\n') { + word_width += font_get_char(font, *next_c)->width; + next_c++; + } + } - /* Remove spaces from beginning of of line */ - if(x_offset == 0 && *str_write == ' ') - { - str_write++; - continue; - } + /* Determine if we need a line break */ + if ((width != 0) && (width <= canvas->width) && + (x_offset + word_width > width)) { + char_params.y += line_height; + x_offset = 0; + } - /* Draw Character */ - char_params.x = x_offset + p->x; - have_space = draw_char_with_shift(canvas, &char_params, &x_offset, NULL, img); - str_write++; + /* Remove spaces from beginning of of line */ + if (x_offset == 0 && *str_write == ' ') { + str_write++; + continue; } - canvas->dirty = true; + /* Draw Character */ + char_params.x = x_offset + p->x; + have_space = + draw_char_with_shift(canvas, &char_params, &x_offset, NULL, img); + str_write++; + } + + canvas->dirty = true; } /* @@ -189,15 +176,14 @@ void draw_string(Canvas *canvas, const Font *font, const char *str_write, * OUTPUT * none */ -void draw_char(Canvas *canvas, const Font *font, char c, DrawableParams *p) -{ - const CharacterImage *img = font_get_char(font, c); - uint16_t x_offset = 0; +void draw_char(Canvas *canvas, const Font *font, char c, DrawableParams *p) { + const CharacterImage *img = font_get_char(font, c); + uint16_t x_offset = 0; - /* Draw Character */ - draw_char_with_shift(canvas, p, &x_offset, NULL, img); + /* Draw Character */ + draw_char_with_shift(canvas, p, &x_offset, NULL, img); - canvas->dirty = true; + canvas->dirty = true; } /* @@ -214,15 +200,14 @@ void draw_char(Canvas *canvas, const Font *font, char c, DrawableParams *p) * OUTPUT * none */ -void draw_char_simple(Canvas *canvas, const Font *font, char c, uint8_t color, uint16_t x, - uint16_t y) -{ - DrawableParams p; - p.color = color; - p.x = x; - p.y = y; - - draw_char(canvas, font, c, &p); +void draw_char_simple(Canvas *canvas, const Font *font, char c, uint8_t color, + uint16_t x, uint16_t y) { + DrawableParams p; + p.color = color; + p.x = x; + p.y = y; + + draw_char(canvas, font, c, &p); } /* @@ -234,40 +219,35 @@ void draw_char_simple(Canvas *canvas, const Font *font, char c, uint8_t color, u * OUTPUT * none */ -void draw_box(Canvas *canvas, BoxDrawableParams *p) -{ - uint16_t start_row = p->base.y; - uint16_t end_row = start_row + p->height; - end_row = (end_row >= canvas->height) ? canvas->height - 1 : end_row; - - uint16_t start_col = p->base.x; - uint16_t end_col = p->base.x + p->width; - end_col = (end_col >= canvas->width) ? canvas->width - 1 : end_col; - - uint16_t start_index = (start_row * canvas->width) + start_col; - uint8_t *canvas_pixel = &canvas->buffer[ start_index ]; - uint8_t *canvas_end = &canvas->buffer[canvas->width * canvas->height]; - - uint16_t height = end_row - start_row; - uint16_t width = end_col - start_col; - - - - for(uint16_t y = 0; y < height; y++) - { - for(uint16_t x = 0; x < width; x++) - { - if (canvas_pixel >= canvas_end){ - return; // defensive bounds check - } - *canvas_pixel = p->base.color; - canvas_pixel++; - } - - canvas_pixel += (canvas->width - width); +void draw_box(Canvas *canvas, BoxDrawableParams *p) { + uint16_t start_row = p->base.y; + uint16_t end_row = start_row + p->height; + end_row = (end_row >= canvas->height) ? canvas->height - 1 : end_row; + + uint16_t start_col = p->base.x; + uint16_t end_col = p->base.x + p->width; + end_col = (end_col >= canvas->width) ? canvas->width - 1 : end_col; + + uint16_t start_index = (start_row * canvas->width) + start_col; + uint8_t *canvas_pixel = &canvas->buffer[start_index]; + uint8_t *canvas_end = &canvas->buffer[canvas->width * canvas->height]; + + uint16_t height = end_row - start_row; + uint16_t width = end_col - start_col; + + for (uint16_t y = 0; y < height; y++) { + for (uint16_t x = 0; x < width; x++) { + if (canvas_pixel >= canvas_end) { + return; // defensive bounds check + } + *canvas_pixel = p->base.color; + canvas_pixel++; } - canvas->dirty = true; + canvas_pixel += (canvas->width - width); + } + + canvas->dirty = true; } /* @@ -283,10 +263,10 @@ void draw_box(Canvas *canvas, BoxDrawableParams *p) * OUTPUT * none */ -void draw_box_simple(Canvas *canvas, uint8_t color, uint16_t x, uint16_t y, uint16_t width, uint16_t height) -{ - BoxDrawableParams box_params = {{color, x, y}, height, width}; - draw_box(canvas, &box_params); +void draw_box_simple(Canvas *canvas, uint8_t color, uint16_t x, uint16_t y, + uint16_t width, uint16_t height) { + BoxDrawableParams box_params = {{color, x, y}, height, width}; + draw_box(canvas, &box_params); } /* @@ -298,75 +278,66 @@ void draw_box_simple(Canvas *canvas, uint8_t color, uint16_t x, uint16_t y, uint * OUTPUT * true/false whether image was drawn */ -bool draw_bitmap_mono_rle(Canvas *canvas, const AnimationFrame *frame, bool erase) -{ - if (!frame || !canvas) { - return false; - } +bool draw_bitmap_mono_rle(Canvas *canvas, const AnimationFrame *frame, + bool erase) { + if (!frame || !canvas) { + return false; + } + + const Image *img = frame->image; + const uint8_t color = erase ? 0x0 : frame->color; + + /* Check that image will fit in bounds */ + if (((img->w + frame->x) > canvas->width) || + ((img->h + frame->y) > canvas->height)) { + return false; + } + + int8_t sequence = 0; + int8_t nonsequence = 0; + uint32_t pixel_index = 0; + + for (int y0 = 0; y0 < img->h; y0++) { + for (int x0 = 0; x0 < img->w; x0++) { + if (pixel_index >= img->length) { + return false; // defensive bounds check + } + + // sequence > 0 implies the next x pixels are the same + // sequence < 0 implies the next -x pixels are all different + if ((sequence == 0) && (nonsequence == 0)) { + sequence = img->data[pixel_index]; + pixel_index++; + + if (sequence < 0) { + nonsequence = -sequence; + sequence = 0; + } + } - const Image *img = frame->image; - const uint8_t color = erase ? 0x0 : frame->color; + if (pixel_index >= img->length) { + return false; // defensive bounds check + } - /* Check that image will fit in bounds */ - if(((img->w + frame->x) > canvas->width) || - ((img->h + frame->y) > canvas->height)) - { - return false; - } + const uint32_t canvas_index = + ((frame->y + y0) * canvas->width) + frame->x + x0; + canvas->buffer[canvas_index] = + (uint8_t)((int)img->data[pixel_index] * color / 100); - int8_t sequence = 0; - int8_t nonsequence = 0; - uint32_t pixel_index = 0; - - for(int y0 = 0; y0 < img->h; y0++) - { - for(int x0 = 0; x0 < img->w; x0++) - { - - if (pixel_index >= img->length){ - return false; // defensive bounds check - } - - // sequence > 0 implies the next x pixels are the same - // sequence < 0 implies the next -x pixels are all different - if((sequence == 0) && (nonsequence == 0)) - { - sequence = img->data[pixel_index]; - pixel_index++; - - if(sequence < 0) - { - nonsequence = -sequence; - sequence = 0; - } - } - - if (pixel_index >= img->length){ - return false; // defensive bounds check - } - - const uint32_t canvas_index = ((frame->y + y0) * canvas->width) + frame->x + x0; - canvas->buffer[canvas_index] = (uint8_t)((int)img->data[pixel_index] * color / 100); - - if(sequence > 0) - { - sequence--; - if(sequence == 0) - { - pixel_index++; - } - } - else - { - assert(nonsequence > 0); - pixel_index++; - nonsequence--; - } + if (sequence > 0) { + sequence--; + if (sequence == 0) { + pixel_index++; } + } else { + assert(nonsequence > 0); + pixel_index++; + nonsequence--; + } } + } - canvas->dirty = true; - return true; + canvas->dirty = true; + return true; } #pragma GCC pop_options - diff --git a/lib/board/font.c b/lib/board/font.c index 4962cf226..4c09da7e8 100644 --- a/lib/board/font.c +++ b/lib/board/font.c @@ -17,31 +17,24 @@ * along with this library. If not, see . */ - #include "keepkey/board/font.h" #include - /* --- Pin Font ------------------------------------------------------------ */ -static const uint8_t image_font_sadface_9x10[9 * 10] = -{ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, - 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff -}; -static const CharacterImage sadface_9x10 = { image_font_sadface_9x10, 9, 10}; - -static const uint8_t image_font_segwit_12x10[12 * 10] = -{ +static const uint8_t image_font_sadface_9x10[9 * 10] = { + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; +static const CharacterImage sadface_9x10 = {image_font_sadface_9x10, 9, 10}; + +static const uint8_t image_font_segwit_12x10[12 * 10] = { 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, @@ -53,10 +46,9 @@ static const uint8_t image_font_segwit_12x10[12 * 10] = 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, }; -static const CharacterImage segwit_12x10 = { image_font_segwit_12x10, 12, 10}; +static const CharacterImage segwit_12x10 = {image_font_segwit_12x10, 12, 10}; -static const uint8_t image_font_unlocked_12x10[12 * 10] = -{ +static const uint8_t image_font_unlocked_12x10[12 * 10] = { 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -68,11 +60,10 @@ static const uint8_t image_font_unlocked_12x10[12 * 10] = 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, }; -static const CharacterImage unlocked_12x10 = { image_font_unlocked_12x10, 12, 10}; +static const CharacterImage unlocked_12x10 = {image_font_unlocked_12x10, 12, + 10}; - -static const uint8_t image_font_locked_12x10[12 * 10] = -{ +static const uint8_t image_font_locked_12x10[12 * 10] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, @@ -84,163 +75,104 @@ static const uint8_t image_font_locked_12x10[12 * 10] = 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, }; -static const CharacterImage locked_12x10 = { image_font_locked_12x10, 12, 10}; - -static const uint8_t image_data_pin_font_0x31[48] = -{ - 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00 -}; -static const CharacterImage pin_font_0x31 = { image_data_pin_font_0x31, 4, 12}; - -static const uint8_t image_data_pin_font_0x32[96] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static const CharacterImage pin_font_0x32 = { image_data_pin_font_0x32, 8, 12}; - -static const uint8_t image_data_pin_font_0x33[96] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage pin_font_0x33 = { image_data_pin_font_0x33, 8, 12}; - -static const uint8_t image_data_pin_font_0x34[96] = -{ - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff -}; -static const CharacterImage pin_font_0x34 = { image_data_pin_font_0x34, 8, 12}; - -static const uint8_t image_data_pin_font_0x35[96] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage pin_font_0x35 = { image_data_pin_font_0x35, 8, 12}; - -static const uint8_t image_data_pin_font_0x36[96] = -{ - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage pin_font_0x36 = { image_data_pin_font_0x36, 8, 12}; - -static const uint8_t image_data_pin_font_0x37[96] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage pin_font_0x37 = { image_data_pin_font_0x37, 8, 12}; - -static const uint8_t image_data_pin_font_0x38[96] = -{ - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage pin_font_0x38 = { image_data_pin_font_0x38, 8, 12}; - -static const uint8_t image_data_pin_font_0x39[96] = -{ - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage pin_font_0x39 = { image_data_pin_font_0x39, 8, 12}; - -static const Character pin_font_array[] = -{ +static const CharacterImage locked_12x10 = {image_font_locked_12x10, 12, 10}; + +static const uint8_t image_data_pin_font_0x31[48] = { + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00}; +static const CharacterImage pin_font_0x31 = {image_data_pin_font_0x31, 4, 12}; + +static const uint8_t image_data_pin_font_0x32[96] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const CharacterImage pin_font_0x32 = {image_data_pin_font_0x32, 8, 12}; + +static const uint8_t image_data_pin_font_0x33[96] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage pin_font_0x33 = {image_data_pin_font_0x33, 8, 12}; + +static const uint8_t image_data_pin_font_0x34[96] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff}; +static const CharacterImage pin_font_0x34 = {image_data_pin_font_0x34, 8, 12}; + +static const uint8_t image_data_pin_font_0x35[96] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage pin_font_0x35 = {image_data_pin_font_0x35, 8, 12}; + +static const uint8_t image_data_pin_font_0x36[96] = { + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage pin_font_0x36 = {image_data_pin_font_0x36, 8, 12}; + +static const uint8_t image_data_pin_font_0x37[96] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage pin_font_0x37 = {image_data_pin_font_0x37, 8, 12}; + +static const uint8_t image_data_pin_font_0x38[96] = { + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage pin_font_0x38 = {image_data_pin_font_0x38, 8, 12}; + +static const uint8_t image_data_pin_font_0x39[96] = { + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage pin_font_0x39 = {image_data_pin_font_0x39, 8, 12}; + +static const Character pin_font_array[] = { /* Character: '1' */ {0x31, &pin_font_0x31}, @@ -271,1439 +203,933 @@ static const Character pin_font_array[] = }; -static const Font pin_font = { sizeof(pin_font_array)/sizeof(pin_font_array[0]), - 14, pin_font_array }; +static const Font pin_font = { + sizeof(pin_font_array) / sizeof(pin_font_array[0]), 14, pin_font_array}; /* --- Title Font ---------------------------------------------------------- */ -static const uint8_t image_data_title_font_0x20[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x20 = { image_data_title_font_0x20, 5, 10}; - -static const uint8_t image_data_title_font_0x21[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x21 = { image_data_title_font_0x21, 3, 10}; - -static const uint8_t image_data_title_font_0x22[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x22 = { image_data_title_font_0x22, 5, 10}; - -static const uint8_t image_data_title_font_0x23[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x23 = { image_data_title_font_0x23, 8, 10}; - -static const uint8_t image_data_title_font_0x24[70] = -{ - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x24 = { image_data_title_font_0x24, 7, 10}; - -static const uint8_t image_data_title_font_0x25[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x25 = { image_data_title_font_0x25, 9, 10}; - -static const uint8_t image_data_title_font_0x26[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x26 = { image_data_title_font_0x26, 8, 10}; - -static const uint8_t image_data_title_font_0x27[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x27 = { image_data_title_font_0x27, 3, 10}; - -static const uint8_t image_data_title_font_0x28[40] = -{ - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x28 = { image_data_title_font_0x28, 4, 10}; - -static const uint8_t image_data_title_font_0x29[40] = -{ - 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x29 = { image_data_title_font_0x29, 4, 10}; - -static const uint8_t image_data_title_font_0x2a[70] = -{ - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x2a = { image_data_title_font_0x2a, 7, 10}; - -static const uint8_t image_data_title_font_0x2b[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x2b = { image_data_title_font_0x2b, 7, 10}; - -static const uint8_t image_data_title_font_0x2c[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage title_font_0x2c = { image_data_title_font_0x2c, 4, 10}; - -static const uint8_t image_data_title_font_0x2d[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x2d = { image_data_title_font_0x2d, 7, 10}; - -static const uint8_t image_data_title_font_0x2e[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x2e = { image_data_title_font_0x2e, 4, 10}; - -static const uint8_t image_data_title_font_0x2f[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x2f = { image_data_title_font_0x2f, 9, 10}; - -static const uint8_t image_data_title_font_0x30[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x30 = { image_data_title_font_0x30, 7, 10}; - -static const uint8_t image_data_title_font_0x31[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x31 = { image_data_title_font_0x31, 4, 10}; - -static const uint8_t image_data_title_font_0x32[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x32 = { image_data_title_font_0x32, 7, 10}; - -static const uint8_t image_data_title_font_0x33[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x33 = { image_data_title_font_0x33, 7, 10}; - -static const uint8_t image_data_title_font_0x34[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x34 = { image_data_title_font_0x34, 7, 10}; - -static const uint8_t image_data_title_font_0x35[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x35 = { image_data_title_font_0x35, 7, 10}; - -static const uint8_t image_data_title_font_0x36[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x36 = { image_data_title_font_0x36, 7, 10}; - -static const uint8_t image_data_title_font_0x37[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x37 = { image_data_title_font_0x37, 7, 10}; - -static const uint8_t image_data_title_font_0x38[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x38 = { image_data_title_font_0x38, 7, 10}; - -static const uint8_t image_data_title_font_0x39[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x39 = { image_data_title_font_0x39, 7, 10}; - -static const uint8_t image_data_title_font_0x3a[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x3a = { image_data_title_font_0x3a, 4, 10}; - -static const uint8_t image_data_title_font_0x3b[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage title_font_0x3b = { image_data_title_font_0x3b, 4, 10}; - -static const uint8_t image_data_title_font_0x3c[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x3c = { image_data_title_font_0x3c, 6, 10}; - -static const uint8_t image_data_title_font_0x3d[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x3d = { image_data_title_font_0x3d, 7, 10}; - -static const uint8_t image_data_title_font_0x3e[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x3e = { image_data_title_font_0x3e, 6, 10}; - -static const uint8_t image_data_title_font_0x3f[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x3f = { image_data_title_font_0x3f, 7, 10}; - -static const uint8_t image_data_title_font_0x40[90] = -{ - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x40 = { image_data_title_font_0x40, 9, 10}; - -static const uint8_t image_data_title_font_0x41[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x41 = { image_data_title_font_0x41, 7, 10}; - -static const uint8_t image_data_title_font_0x42[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x42 = { image_data_title_font_0x42, 7, 10}; - -static const uint8_t image_data_title_font_0x43[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x43 = { image_data_title_font_0x43, 7, 10}; - -static const uint8_t image_data_title_font_0x44[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x44 = { image_data_title_font_0x44, 7, 10}; - -static const uint8_t image_data_title_font_0x45[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x45 = { image_data_title_font_0x45, 7, 10}; - -static const uint8_t image_data_title_font_0x46[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x46 = { image_data_title_font_0x46, 7, 10}; - -static const uint8_t image_data_title_font_0x47[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x47 = { image_data_title_font_0x47, 7, 10}; - -static const uint8_t image_data_title_font_0x48[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x48 = { image_data_title_font_0x48, 7, 10}; - -static const uint8_t image_data_title_font_0x49[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x49 = { image_data_title_font_0x49, 5, 10}; - -static const uint8_t image_data_title_font_0x4a[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4a = { image_data_title_font_0x4a, 7, 10}; - -static const uint8_t image_data_title_font_0x4b[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4b = { image_data_title_font_0x4b, 7, 10}; - -static const uint8_t image_data_title_font_0x4c[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4c = { image_data_title_font_0x4c, 7, 10}; - -static const uint8_t image_data_title_font_0x4d[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4d = { image_data_title_font_0x4d, 9, 10}; - -static const uint8_t image_data_title_font_0x4e[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4e = { image_data_title_font_0x4e, 7, 10}; - -static const uint8_t image_data_title_font_0x4f[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x4f = { image_data_title_font_0x4f, 7, 10}; - -static const uint8_t image_data_title_font_0x50[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x50 = { image_data_title_font_0x50, 7, 10}; - -static const uint8_t image_data_title_font_0x51[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x51 = { image_data_title_font_0x51, 7, 10}; - -static const uint8_t image_data_title_font_0x52[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x52 = { image_data_title_font_0x52, 7, 10}; - -static const uint8_t image_data_title_font_0x53[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x53 = { image_data_title_font_0x53, 7, 10}; - -static const uint8_t image_data_title_font_0x54[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x54 = { image_data_title_font_0x54, 7, 10}; - -static const uint8_t image_data_title_font_0x55[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x55 = { image_data_title_font_0x55, 7, 10}; - -static const uint8_t image_data_title_font_0x56[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x56 = { image_data_title_font_0x56, 7, 10}; - -static const uint8_t image_data_title_font_0x57[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x57 = { image_data_title_font_0x57, 9, 10}; - -static const uint8_t image_data_title_font_0x58[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x58 = { image_data_title_font_0x58, 7, 10}; - -static const uint8_t image_data_title_font_0x59[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x59 = { image_data_title_font_0x59, 7, 10}; - -static const uint8_t image_data_title_font_0x5a[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5a = { image_data_title_font_0x5a, 7, 10}; - -static const uint8_t image_data_title_font_0x5b[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5b = { image_data_title_font_0x5b, 5, 10}; - -static const uint8_t image_data_title_font_0x5c[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5c = { image_data_title_font_0x5c, 9, 10}; - -static const uint8_t image_data_title_font_0x5d[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5d = { image_data_title_font_0x5d, 5, 10}; - -static const uint8_t image_data_title_font_0x5e[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5e = { image_data_title_font_0x5e, 5, 10}; - -static const uint8_t image_data_title_font_0x5f[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x5f = { image_data_title_font_0x5f, 7, 10}; - -static const uint8_t image_data_title_font_0x60[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x60 = { image_data_title_font_0x60, 4, 10}; - -static const uint8_t image_data_title_font_0x61[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x61 = { image_data_title_font_0x61, 7, 10}; - -static const uint8_t image_data_title_font_0x62[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x62 = { image_data_title_font_0x62, 7, 10}; - -static const uint8_t image_data_title_font_0x63[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x63 = { image_data_title_font_0x63, 7, 10}; - -static const uint8_t image_data_title_font_0x64[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x64 = { image_data_title_font_0x64, 7, 10}; - -static const uint8_t image_data_title_font_0x65[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x65 = { image_data_title_font_0x65, 7, 10}; - -static const uint8_t image_data_title_font_0x66[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x66 = { image_data_title_font_0x66, 6, 10}; - -static const uint8_t image_data_title_font_0x67[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage title_font_0x67 = { image_data_title_font_0x67, 7, 10}; - -static const uint8_t image_data_title_font_0x68[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x68 = { image_data_title_font_0x68, 7, 10}; - -static const uint8_t image_data_title_font_0x69[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x69 = { image_data_title_font_0x69, 3, 10}; - -static const uint8_t image_data_title_font_0x6a[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage title_font_0x6a = { image_data_title_font_0x6a, 4, 10}; - -static const uint8_t image_data_title_font_0x6b[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x6b = { image_data_title_font_0x6b, 6, 10}; - -static const uint8_t image_data_title_font_0x6c[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x6c = { image_data_title_font_0x6c, 3, 10}; - -static const uint8_t image_data_title_font_0x6d[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x6d = { image_data_title_font_0x6d, 9, 10}; - -static const uint8_t image_data_title_font_0x6e[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x6e = { image_data_title_font_0x6e, 7, 10}; - -static const uint8_t image_data_title_font_0x6f[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x6f = { image_data_title_font_0x6f, 7, 10}; - -static const uint8_t image_data_title_font_0x70[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x70 = { image_data_title_font_0x70, 7, 10}; - -static const uint8_t image_data_title_font_0x71[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff -}; -static const CharacterImage title_font_0x71 = { image_data_title_font_0x71, 7, 10}; - -static const uint8_t image_data_title_font_0x72[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x72 = { image_data_title_font_0x72, 6, 10}; - -static const uint8_t image_data_title_font_0x73[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x73 = { image_data_title_font_0x73, 7, 10}; - -static const uint8_t image_data_title_font_0x74[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x74 = { image_data_title_font_0x74, 6, 10}; - -static const uint8_t image_data_title_font_0x75[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x75 = { image_data_title_font_0x75, 7, 10}; - -static const uint8_t image_data_title_font_0x76[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x76 = { image_data_title_font_0x76, 7, 10}; - -static const uint8_t image_data_title_font_0x77[90] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x77 = { image_data_title_font_0x77, 9, 10}; - -static const uint8_t image_data_title_font_0x78[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x78 = { image_data_title_font_0x78, 7, 10}; - -static const uint8_t image_data_title_font_0x79[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage title_font_0x79 = { image_data_title_font_0x79, 7, 10}; - -static const uint8_t image_data_title_font_0x7a[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x7a = { image_data_title_font_0x7a, 7, 10}; - -static const uint8_t image_data_title_font_0x7b[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x7b = { image_data_title_font_0x7b, 6, 10}; - -static const uint8_t image_data_title_font_0x7c[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x7c = { image_data_title_font_0x7c, 3, 10}; - -static const uint8_t image_data_title_font_0x7d[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x7d = { image_data_title_font_0x7d, 6, 10}; - -static const uint8_t image_data_title_font_0x7e[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage title_font_0x7e = { image_data_title_font_0x7e, 7, 10}; - - -static const Character title_font_array[] = -{ +static const uint8_t image_data_title_font_0x20[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x20 = {image_data_title_font_0x20, 5, + 10}; + +static const uint8_t image_data_title_font_0x21[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x21 = {image_data_title_font_0x21, 3, + 10}; + +static const uint8_t image_data_title_font_0x22[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x22 = {image_data_title_font_0x22, 5, + 10}; + +static const uint8_t image_data_title_font_0x23[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x23 = {image_data_title_font_0x23, 8, + 10}; + +static const uint8_t image_data_title_font_0x24[70] = { + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x24 = {image_data_title_font_0x24, 7, + 10}; + +static const uint8_t image_data_title_font_0x25[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x25 = {image_data_title_font_0x25, 9, + 10}; + +static const uint8_t image_data_title_font_0x26[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x26 = {image_data_title_font_0x26, 8, + 10}; + +static const uint8_t image_data_title_font_0x27[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x27 = {image_data_title_font_0x27, 3, + 10}; + +static const uint8_t image_data_title_font_0x28[40] = { + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x28 = {image_data_title_font_0x28, 4, + 10}; + +static const uint8_t image_data_title_font_0x29[40] = { + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x29 = {image_data_title_font_0x29, 4, + 10}; + +static const uint8_t image_data_title_font_0x2a[70] = { + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x2a = {image_data_title_font_0x2a, 7, + 10}; + +static const uint8_t image_data_title_font_0x2b[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x2b = {image_data_title_font_0x2b, 7, + 10}; + +static const uint8_t image_data_title_font_0x2c[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage title_font_0x2c = {image_data_title_font_0x2c, 4, + 10}; + +static const uint8_t image_data_title_font_0x2d[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x2d = {image_data_title_font_0x2d, 7, + 10}; + +static const uint8_t image_data_title_font_0x2e[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x2e = {image_data_title_font_0x2e, 4, + 10}; + +static const uint8_t image_data_title_font_0x2f[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x2f = {image_data_title_font_0x2f, 9, + 10}; + +static const uint8_t image_data_title_font_0x30[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x30 = {image_data_title_font_0x30, 7, + 10}; + +static const uint8_t image_data_title_font_0x31[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x31 = {image_data_title_font_0x31, 4, + 10}; + +static const uint8_t image_data_title_font_0x32[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x32 = {image_data_title_font_0x32, 7, + 10}; + +static const uint8_t image_data_title_font_0x33[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x33 = {image_data_title_font_0x33, 7, + 10}; + +static const uint8_t image_data_title_font_0x34[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x34 = {image_data_title_font_0x34, 7, + 10}; + +static const uint8_t image_data_title_font_0x35[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x35 = {image_data_title_font_0x35, 7, + 10}; + +static const uint8_t image_data_title_font_0x36[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x36 = {image_data_title_font_0x36, 7, + 10}; + +static const uint8_t image_data_title_font_0x37[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x37 = {image_data_title_font_0x37, 7, + 10}; + +static const uint8_t image_data_title_font_0x38[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x38 = {image_data_title_font_0x38, 7, + 10}; + +static const uint8_t image_data_title_font_0x39[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x39 = {image_data_title_font_0x39, 7, + 10}; + +static const uint8_t image_data_title_font_0x3a[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x3a = {image_data_title_font_0x3a, 4, + 10}; + +static const uint8_t image_data_title_font_0x3b[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage title_font_0x3b = {image_data_title_font_0x3b, 4, + 10}; + +static const uint8_t image_data_title_font_0x3c[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x3c = {image_data_title_font_0x3c, 6, + 10}; + +static const uint8_t image_data_title_font_0x3d[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x3d = {image_data_title_font_0x3d, 7, + 10}; + +static const uint8_t image_data_title_font_0x3e[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x3e = {image_data_title_font_0x3e, 6, + 10}; + +static const uint8_t image_data_title_font_0x3f[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x3f = {image_data_title_font_0x3f, 7, + 10}; + +static const uint8_t image_data_title_font_0x40[90] = { + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x40 = {image_data_title_font_0x40, 9, + 10}; + +static const uint8_t image_data_title_font_0x41[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x41 = {image_data_title_font_0x41, 7, + 10}; + +static const uint8_t image_data_title_font_0x42[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x42 = {image_data_title_font_0x42, 7, + 10}; + +static const uint8_t image_data_title_font_0x43[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x43 = {image_data_title_font_0x43, 7, + 10}; + +static const uint8_t image_data_title_font_0x44[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x44 = {image_data_title_font_0x44, 7, + 10}; + +static const uint8_t image_data_title_font_0x45[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x45 = {image_data_title_font_0x45, 7, + 10}; + +static const uint8_t image_data_title_font_0x46[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x46 = {image_data_title_font_0x46, 7, + 10}; + +static const uint8_t image_data_title_font_0x47[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x47 = {image_data_title_font_0x47, 7, + 10}; + +static const uint8_t image_data_title_font_0x48[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x48 = {image_data_title_font_0x48, 7, + 10}; + +static const uint8_t image_data_title_font_0x49[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x49 = {image_data_title_font_0x49, 5, + 10}; + +static const uint8_t image_data_title_font_0x4a[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4a = {image_data_title_font_0x4a, 7, + 10}; + +static const uint8_t image_data_title_font_0x4b[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4b = {image_data_title_font_0x4b, 7, + 10}; + +static const uint8_t image_data_title_font_0x4c[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4c = {image_data_title_font_0x4c, 7, + 10}; + +static const uint8_t image_data_title_font_0x4d[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4d = {image_data_title_font_0x4d, 9, + 10}; + +static const uint8_t image_data_title_font_0x4e[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4e = {image_data_title_font_0x4e, 7, + 10}; + +static const uint8_t image_data_title_font_0x4f[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x4f = {image_data_title_font_0x4f, 7, + 10}; + +static const uint8_t image_data_title_font_0x50[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x50 = {image_data_title_font_0x50, 7, + 10}; + +static const uint8_t image_data_title_font_0x51[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x51 = {image_data_title_font_0x51, 7, + 10}; + +static const uint8_t image_data_title_font_0x52[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x52 = {image_data_title_font_0x52, 7, + 10}; + +static const uint8_t image_data_title_font_0x53[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x53 = {image_data_title_font_0x53, 7, + 10}; + +static const uint8_t image_data_title_font_0x54[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x54 = {image_data_title_font_0x54, 7, + 10}; + +static const uint8_t image_data_title_font_0x55[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x55 = {image_data_title_font_0x55, 7, + 10}; + +static const uint8_t image_data_title_font_0x56[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x56 = {image_data_title_font_0x56, 7, + 10}; + +static const uint8_t image_data_title_font_0x57[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x57 = {image_data_title_font_0x57, 9, + 10}; + +static const uint8_t image_data_title_font_0x58[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x58 = {image_data_title_font_0x58, 7, + 10}; + +static const uint8_t image_data_title_font_0x59[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x59 = {image_data_title_font_0x59, 7, + 10}; + +static const uint8_t image_data_title_font_0x5a[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5a = {image_data_title_font_0x5a, 7, + 10}; + +static const uint8_t image_data_title_font_0x5b[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5b = {image_data_title_font_0x5b, 5, + 10}; + +static const uint8_t image_data_title_font_0x5c[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5c = {image_data_title_font_0x5c, 9, + 10}; + +static const uint8_t image_data_title_font_0x5d[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5d = {image_data_title_font_0x5d, 5, + 10}; + +static const uint8_t image_data_title_font_0x5e[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5e = {image_data_title_font_0x5e, 5, + 10}; + +static const uint8_t image_data_title_font_0x5f[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x5f = {image_data_title_font_0x5f, 7, + 10}; + +static const uint8_t image_data_title_font_0x60[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x60 = {image_data_title_font_0x60, 4, + 10}; + +static const uint8_t image_data_title_font_0x61[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x61 = {image_data_title_font_0x61, 7, + 10}; + +static const uint8_t image_data_title_font_0x62[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x62 = {image_data_title_font_0x62, 7, + 10}; + +static const uint8_t image_data_title_font_0x63[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x63 = {image_data_title_font_0x63, 7, + 10}; + +static const uint8_t image_data_title_font_0x64[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x64 = {image_data_title_font_0x64, 7, + 10}; + +static const uint8_t image_data_title_font_0x65[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x65 = {image_data_title_font_0x65, 7, + 10}; + +static const uint8_t image_data_title_font_0x66[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x66 = {image_data_title_font_0x66, 6, + 10}; + +static const uint8_t image_data_title_font_0x67[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage title_font_0x67 = {image_data_title_font_0x67, 7, + 10}; + +static const uint8_t image_data_title_font_0x68[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x68 = {image_data_title_font_0x68, 7, + 10}; + +static const uint8_t image_data_title_font_0x69[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x69 = {image_data_title_font_0x69, 3, + 10}; + +static const uint8_t image_data_title_font_0x6a[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage title_font_0x6a = {image_data_title_font_0x6a, 4, + 10}; + +static const uint8_t image_data_title_font_0x6b[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x6b = {image_data_title_font_0x6b, 6, + 10}; + +static const uint8_t image_data_title_font_0x6c[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x6c = {image_data_title_font_0x6c, 3, + 10}; + +static const uint8_t image_data_title_font_0x6d[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x6d = {image_data_title_font_0x6d, 9, + 10}; + +static const uint8_t image_data_title_font_0x6e[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x6e = {image_data_title_font_0x6e, 7, + 10}; + +static const uint8_t image_data_title_font_0x6f[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x6f = {image_data_title_font_0x6f, 7, + 10}; + +static const uint8_t image_data_title_font_0x70[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x70 = {image_data_title_font_0x70, 7, + 10}; + +static const uint8_t image_data_title_font_0x71[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff}; +static const CharacterImage title_font_0x71 = {image_data_title_font_0x71, 7, + 10}; + +static const uint8_t image_data_title_font_0x72[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x72 = {image_data_title_font_0x72, 6, + 10}; + +static const uint8_t image_data_title_font_0x73[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x73 = {image_data_title_font_0x73, 7, + 10}; + +static const uint8_t image_data_title_font_0x74[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x74 = {image_data_title_font_0x74, 6, + 10}; + +static const uint8_t image_data_title_font_0x75[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x75 = {image_data_title_font_0x75, 7, + 10}; + +static const uint8_t image_data_title_font_0x76[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x76 = {image_data_title_font_0x76, 7, + 10}; + +static const uint8_t image_data_title_font_0x77[90] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x77 = {image_data_title_font_0x77, 9, + 10}; + +static const uint8_t image_data_title_font_0x78[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x78 = {image_data_title_font_0x78, 7, + 10}; + +static const uint8_t image_data_title_font_0x79[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage title_font_0x79 = {image_data_title_font_0x79, 7, + 10}; + +static const uint8_t image_data_title_font_0x7a[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x7a = {image_data_title_font_0x7a, 7, + 10}; + +static const uint8_t image_data_title_font_0x7b[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x7b = {image_data_title_font_0x7b, 6, + 10}; + +static const uint8_t image_data_title_font_0x7c[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x7c = {image_data_title_font_0x7c, 3, + 10}; + +static const uint8_t image_data_title_font_0x7d[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x7d = {image_data_title_font_0x7d, 6, + 10}; + +static const uint8_t image_data_title_font_0x7e[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage title_font_0x7e = {image_data_title_font_0x7e, 7, + 10}; + +static const Character title_font_array[] = { /* SegWit logo */ {0x01, &segwit_12x10}, @@ -2000,1439 +1426,753 @@ static const Character title_font_array[] = }; -static const Font title_font = { sizeof(title_font_array)/sizeof(title_font_array[0]), - 10, title_font_array }; +static const Font title_font = { + sizeof(title_font_array) / sizeof(title_font_array[0]), 10, + title_font_array}; /* --- Body Font ----------------------------------------------------------- */ -static const uint8_t image_data_body_font_0x20[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x20 = { image_data_body_font_0x20, 4, 10}; - -static const uint8_t image_data_body_font_0x21[20] = -{ - 0xff, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0xff, 0xff -}; -static const CharacterImage body_font_0x21 = { image_data_body_font_0x21, 2, 10}; - -static const uint8_t image_data_body_font_0x22[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x22 = { image_data_body_font_0x22, 4, 10}; - -static const uint8_t image_data_body_font_0x23[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x23 = { image_data_body_font_0x23, 7, 10}; - -static const uint8_t image_data_body_font_0x24[60] = -{ - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x24 = { image_data_body_font_0x24, 6, 10}; - -static const uint8_t image_data_body_font_0x25[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x25 = { image_data_body_font_0x25, 8, 10}; - -static const uint8_t image_data_body_font_0x26[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x26 = { image_data_body_font_0x26, 7, 10}; - -static const uint8_t image_data_body_font_0x27[20] = -{ - 0xff, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0xff, 0xff, - 0xff, 0xff, - 0xff, 0xff, - 0xff, 0xff, - 0xff, 0xff, - 0xff, 0xff -}; -static const CharacterImage body_font_0x27 = { image_data_body_font_0x27, 2, 10}; - -static const uint8_t image_data_body_font_0x28[30] = -{ - 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x28 = { image_data_body_font_0x28, 3, 10}; - -static const uint8_t image_data_body_font_0x29[30] = -{ - 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x29 = { image_data_body_font_0x29, 3, 10}; - -static const uint8_t image_data_body_font_0x2a[60] = -{ - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x2a = { image_data_body_font_0x2a, 6, 10}; - -static const uint8_t image_data_body_font_0x2b[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x2b = { image_data_body_font_0x2b, 6, 10}; - -static const uint8_t image_data_body_font_0x2c[30] = -{ - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff -}; -static const CharacterImage body_font_0x2c = { image_data_body_font_0x2c, 3, 10}; - -static const uint8_t image_data_body_font_0x2d[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x2d = { image_data_body_font_0x2d, 6, 10}; - -static const uint8_t image_data_body_font_0x2e[30] = -{ - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x2e = { image_data_body_font_0x2e, 3, 10}; - -static const uint8_t image_data_body_font_0x2f[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x2f = { image_data_body_font_0x2f, 8, 10}; - -static const uint8_t image_data_body_font_0x30[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x30 = { image_data_body_font_0x30, 6, 10}; - -static const uint8_t image_data_body_font_0x31[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x31 = { image_data_body_font_0x31, 3, 10}; - -static const uint8_t image_data_body_font_0x32[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x32 = { image_data_body_font_0x32, 6, 10}; - -static const uint8_t image_data_body_font_0x33[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x33 = { image_data_body_font_0x33, 6, 10}; - -static const uint8_t image_data_body_font_0x34[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x34 = { image_data_body_font_0x34, 6, 10}; - -static const uint8_t image_data_body_font_0x35[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x35 = { image_data_body_font_0x35, 6, 10}; - -static const uint8_t image_data_body_font_0x36[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x36 = { image_data_body_font_0x36, 6, 10}; - -static const uint8_t image_data_body_font_0x37[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x37 = { image_data_body_font_0x37, 6, 10}; - -static const uint8_t image_data_body_font_0x38[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x38 = { image_data_body_font_0x38, 6, 10}; - -static const uint8_t image_data_body_font_0x39[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x39 = { image_data_body_font_0x39, 6, 10}; - -static const uint8_t image_data_body_font_0x3a[30] = -{ - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x3a = { image_data_body_font_0x3a, 3, 10}; - -static const uint8_t image_data_body_font_0x3b[30] = -{ - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff -}; -static const CharacterImage body_font_0x3b = { image_data_body_font_0x3b, 3, 10}; - -static const uint8_t image_data_body_font_0x3c[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x3c = { image_data_body_font_0x3c, 5, 10}; - -static const uint8_t image_data_body_font_0x3d[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x3d = { image_data_body_font_0x3d, 6, 10}; - -static const uint8_t image_data_body_font_0x3e[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x3e = { image_data_body_font_0x3e, 5, 10}; - -static const uint8_t image_data_body_font_0x3f[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x3f = { image_data_body_font_0x3f, 6, 10}; - -static const uint8_t image_data_body_font_0x40[80] = -{ - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, - 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, - 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x40 = { image_data_body_font_0x40, 8, 10}; - -static const uint8_t image_data_body_font_0x41[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x41 = { image_data_body_font_0x41, 6, 10}; - -static const uint8_t image_data_body_font_0x42[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x42 = { image_data_body_font_0x42, 6, 10}; - -static const uint8_t image_data_body_font_0x43[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x43 = { image_data_body_font_0x43, 6, 10}; - -static const uint8_t image_data_body_font_0x44[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x44 = { image_data_body_font_0x44, 6, 10}; - -static const uint8_t image_data_body_font_0x45[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x45 = { image_data_body_font_0x45, 6, 10}; - -static const uint8_t image_data_body_font_0x46[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x46 = { image_data_body_font_0x46, 6, 10}; - -static const uint8_t image_data_body_font_0x47[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x47 = { image_data_body_font_0x47, 6, 10}; - -static const uint8_t image_data_body_font_0x48[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x48 = { image_data_body_font_0x48, 6, 10}; - -static const uint8_t image_data_body_font_0x49[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x49 = { image_data_body_font_0x49, 4, 10}; - -static const uint8_t image_data_body_font_0x4a[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4a = { image_data_body_font_0x4a, 6, 10}; - -static const uint8_t image_data_body_font_0x4b[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4b = { image_data_body_font_0x4b, 6, 10}; - -static const uint8_t image_data_body_font_0x4c[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4c = { image_data_body_font_0x4c, 6, 10}; - -static const uint8_t image_data_body_font_0x4d[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4d = { image_data_body_font_0x4d, 8, 10}; - -static const uint8_t image_data_body_font_0x4e[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4e = { image_data_body_font_0x4e, 6, 10}; - -static const uint8_t image_data_body_font_0x4f[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x4f = { image_data_body_font_0x4f, 6, 10}; - -static const uint8_t image_data_body_font_0x50[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x50 = { image_data_body_font_0x50, 6, 10}; - -static const uint8_t image_data_body_font_0x51[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x51 = { image_data_body_font_0x51, 6, 10}; - -static const uint8_t image_data_body_font_0x52[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x52 = { image_data_body_font_0x52, 6, 10}; - -static const uint8_t image_data_body_font_0x53[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x53 = { image_data_body_font_0x53, 6, 10}; - -static const uint8_t image_data_body_font_0x54[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x54 = { image_data_body_font_0x54, 6, 10}; - -static const uint8_t image_data_body_font_0x55[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x55 = { image_data_body_font_0x55, 6, 10}; - -static const uint8_t image_data_body_font_0x56[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x56 = { image_data_body_font_0x56, 6, 10}; - -static const uint8_t image_data_body_font_0x57[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x57 = { image_data_body_font_0x57, 8, 10}; - -static const uint8_t image_data_body_font_0x58[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x58 = { image_data_body_font_0x58, 6, 10}; - -static const uint8_t image_data_body_font_0x59[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x59 = { image_data_body_font_0x59, 6, 10}; - -static const uint8_t image_data_body_font_0x5a[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5a = { image_data_body_font_0x5a, 6, 10}; - -static const uint8_t image_data_body_font_0x5b[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5b = { image_data_body_font_0x5b, 4, 10}; - -static const uint8_t image_data_body_font_0x5c[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5c = { image_data_body_font_0x5c, 8, 10}; - -static const uint8_t image_data_body_font_0x5d[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5d = { image_data_body_font_0x5d, 4, 10}; - -static const uint8_t image_data_body_font_0x5e[40] = -{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5e = { image_data_body_font_0x5e, 4, 10}; - -static const uint8_t image_data_body_font_0x5f[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x5f = { image_data_body_font_0x5f, 6, 10}; - -static const uint8_t image_data_body_font_0x60[30] = -{ - 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x60 = { image_data_body_font_0x60, 3, 10}; - -static const uint8_t image_data_body_font_0x61[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x61 = { image_data_body_font_0x61, 6, 10}; - -static const uint8_t image_data_body_font_0x62[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x62 = { image_data_body_font_0x62, 6, 10}; - -static const uint8_t image_data_body_font_0x63[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x63 = { image_data_body_font_0x63, 6, 10}; - -static const uint8_t image_data_body_font_0x64[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x64 = { image_data_body_font_0x64, 6, 10}; - -static const uint8_t image_data_body_font_0x65[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x65 = { image_data_body_font_0x65, 6, 10}; - -static const uint8_t image_data_body_font_0x66[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x66 = { image_data_body_font_0x66, 5, 10}; - -static const uint8_t image_data_body_font_0x67[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage body_font_0x67 = { image_data_body_font_0x67, 6, 10}; - -static const uint8_t image_data_body_font_0x68[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x68 = { image_data_body_font_0x68, 6, 10}; - -static const uint8_t image_data_body_font_0x69[20] = -{ - 0xff, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0xff, 0xff -}; -static const CharacterImage body_font_0x69 = { image_data_body_font_0x69, 2, 10}; - -static const uint8_t image_data_body_font_0x6a[30] = -{ - 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff -}; -static const CharacterImage body_font_0x6a = { image_data_body_font_0x6a, 3, 10}; - -static const uint8_t image_data_body_font_0x6b[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x6b = { image_data_body_font_0x6b, 5, 10}; - -static const uint8_t image_data_body_font_0x6c[20] = -{ - 0xff, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0xff, 0xff -}; -static const CharacterImage body_font_0x6c = { image_data_body_font_0x6c, 2, 10}; - -static const uint8_t image_data_body_font_0x6d[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x6d = { image_data_body_font_0x6d, 8, 10}; - -static const uint8_t image_data_body_font_0x6e[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x6e = { image_data_body_font_0x6e, 6, 10}; - -static const uint8_t image_data_body_font_0x6f[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x6f = { image_data_body_font_0x6f, 6, 10}; - -static const uint8_t image_data_body_font_0x70[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x70 = { image_data_body_font_0x70, 6, 10}; - -static const uint8_t image_data_body_font_0x71[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff -}; -static const CharacterImage body_font_0x71 = { image_data_body_font_0x71, 6, 10}; - -static const uint8_t image_data_body_font_0x72[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x72 = { image_data_body_font_0x72, 5, 10}; - -static const uint8_t image_data_body_font_0x73[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x73 = { image_data_body_font_0x73, 6, 10}; - -static const uint8_t image_data_body_font_0x74[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x74 = { image_data_body_font_0x74, 5, 10}; - -static const uint8_t image_data_body_font_0x75[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x75 = { image_data_body_font_0x75, 6, 10}; - -static const uint8_t image_data_body_font_0x76[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x76 = { image_data_body_font_0x76, 6, 10}; - -static const uint8_t image_data_body_font_0x77[80] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x77 = { image_data_body_font_0x77, 8, 10}; - -static const uint8_t image_data_body_font_0x78[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x78 = { image_data_body_font_0x78, 6, 10}; - -static const uint8_t image_data_body_font_0x79[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, 0xff, 0xff -}; -static const CharacterImage body_font_0x79 = { image_data_body_font_0x79, 6, 10}; - -static const uint8_t image_data_body_font_0x7a[60] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x7a = { image_data_body_font_0x7a, 6, 10}; - -static const uint8_t image_data_body_font_0x7b[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x7b = { image_data_body_font_0x7b, 5, 10}; - -static const uint8_t image_data_body_font_0x7c[20] = -{ - 0xff, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0x00, 0xff, - 0xff, 0xff, - 0xff, 0xff -}; -static const CharacterImage body_font_0x7c = { image_data_body_font_0x7c, 2, 10}; - -static const uint8_t image_data_body_font_0x7d[50] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x7d = { image_data_body_font_0x7d, 5, 10}; - -static const uint8_t image_data_body_font_0x7e[70] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; -static const CharacterImage body_font_0x7e = { image_data_body_font_0x7e, 7, 10}; - - -static const Character body_font_array[] = -{ +static const uint8_t image_data_body_font_0x20[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x20 = {image_data_body_font_0x20, 4, 10}; + +static const uint8_t image_data_body_font_0x21[20] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x21 = {image_data_body_font_0x21, 2, 10}; + +static const uint8_t image_data_body_font_0x22[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x22 = {image_data_body_font_0x22, 4, 10}; + +static const uint8_t image_data_body_font_0x23[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x23 = {image_data_body_font_0x23, 7, 10}; + +static const uint8_t image_data_body_font_0x24[60] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x24 = {image_data_body_font_0x24, 6, 10}; + +static const uint8_t image_data_body_font_0x25[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x25 = {image_data_body_font_0x25, 8, 10}; + +static const uint8_t image_data_body_font_0x26[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x26 = {image_data_body_font_0x26, 7, 10}; + +static const uint8_t image_data_body_font_0x27[20] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x27 = {image_data_body_font_0x27, 2, 10}; + +static const uint8_t image_data_body_font_0x28[30] = { + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x28 = {image_data_body_font_0x28, 3, 10}; + +static const uint8_t image_data_body_font_0x29[30] = { + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x29 = {image_data_body_font_0x29, 3, 10}; + +static const uint8_t image_data_body_font_0x2a[60] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x2a = {image_data_body_font_0x2a, 6, 10}; + +static const uint8_t image_data_body_font_0x2b[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x2b = {image_data_body_font_0x2b, 6, 10}; + +static const uint8_t image_data_body_font_0x2c[30] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff}; +static const CharacterImage body_font_0x2c = {image_data_body_font_0x2c, 3, 10}; + +static const uint8_t image_data_body_font_0x2d[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x2d = {image_data_body_font_0x2d, 6, 10}; + +static const uint8_t image_data_body_font_0x2e[30] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x2e = {image_data_body_font_0x2e, 3, 10}; + +static const uint8_t image_data_body_font_0x2f[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x2f = {image_data_body_font_0x2f, 8, 10}; + +static const uint8_t image_data_body_font_0x30[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x30 = {image_data_body_font_0x30, 6, 10}; + +static const uint8_t image_data_body_font_0x31[30] = { + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x31 = {image_data_body_font_0x31, 3, 10}; + +static const uint8_t image_data_body_font_0x32[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x32 = {image_data_body_font_0x32, 6, 10}; + +static const uint8_t image_data_body_font_0x33[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x33 = {image_data_body_font_0x33, 6, 10}; + +static const uint8_t image_data_body_font_0x34[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x34 = {image_data_body_font_0x34, 6, 10}; + +static const uint8_t image_data_body_font_0x35[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x35 = {image_data_body_font_0x35, 6, 10}; + +static const uint8_t image_data_body_font_0x36[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x36 = {image_data_body_font_0x36, 6, 10}; + +static const uint8_t image_data_body_font_0x37[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x37 = {image_data_body_font_0x37, 6, 10}; + +static const uint8_t image_data_body_font_0x38[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x38 = {image_data_body_font_0x38, 6, 10}; + +static const uint8_t image_data_body_font_0x39[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x39 = {image_data_body_font_0x39, 6, 10}; + +static const uint8_t image_data_body_font_0x3a[30] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x3a = {image_data_body_font_0x3a, 3, 10}; + +static const uint8_t image_data_body_font_0x3b[30] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff}; +static const CharacterImage body_font_0x3b = {image_data_body_font_0x3b, 3, 10}; + +static const uint8_t image_data_body_font_0x3c[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x3c = {image_data_body_font_0x3c, 5, 10}; + +static const uint8_t image_data_body_font_0x3d[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x3d = {image_data_body_font_0x3d, 6, 10}; + +static const uint8_t image_data_body_font_0x3e[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x3e = {image_data_body_font_0x3e, 5, 10}; + +static const uint8_t image_data_body_font_0x3f[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x3f = {image_data_body_font_0x3f, 6, 10}; + +static const uint8_t image_data_body_font_0x40[80] = { + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x40 = {image_data_body_font_0x40, 8, 10}; + +static const uint8_t image_data_body_font_0x41[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x41 = {image_data_body_font_0x41, 6, 10}; + +static const uint8_t image_data_body_font_0x42[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x42 = {image_data_body_font_0x42, 6, 10}; + +static const uint8_t image_data_body_font_0x43[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x43 = {image_data_body_font_0x43, 6, 10}; + +static const uint8_t image_data_body_font_0x44[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x44 = {image_data_body_font_0x44, 6, 10}; + +static const uint8_t image_data_body_font_0x45[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x45 = {image_data_body_font_0x45, 6, 10}; + +static const uint8_t image_data_body_font_0x46[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x46 = {image_data_body_font_0x46, 6, 10}; + +static const uint8_t image_data_body_font_0x47[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x47 = {image_data_body_font_0x47, 6, 10}; + +static const uint8_t image_data_body_font_0x48[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x48 = {image_data_body_font_0x48, 6, 10}; + +static const uint8_t image_data_body_font_0x49[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x49 = {image_data_body_font_0x49, 4, 10}; + +static const uint8_t image_data_body_font_0x4a[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4a = {image_data_body_font_0x4a, 6, 10}; + +static const uint8_t image_data_body_font_0x4b[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4b = {image_data_body_font_0x4b, 6, 10}; + +static const uint8_t image_data_body_font_0x4c[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4c = {image_data_body_font_0x4c, 6, 10}; + +static const uint8_t image_data_body_font_0x4d[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4d = {image_data_body_font_0x4d, 8, 10}; + +static const uint8_t image_data_body_font_0x4e[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4e = {image_data_body_font_0x4e, 6, 10}; + +static const uint8_t image_data_body_font_0x4f[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x4f = {image_data_body_font_0x4f, 6, 10}; + +static const uint8_t image_data_body_font_0x50[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x50 = {image_data_body_font_0x50, 6, 10}; + +static const uint8_t image_data_body_font_0x51[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x51 = {image_data_body_font_0x51, 6, 10}; + +static const uint8_t image_data_body_font_0x52[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x52 = {image_data_body_font_0x52, 6, 10}; + +static const uint8_t image_data_body_font_0x53[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x53 = {image_data_body_font_0x53, 6, 10}; + +static const uint8_t image_data_body_font_0x54[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x54 = {image_data_body_font_0x54, 6, 10}; + +static const uint8_t image_data_body_font_0x55[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x55 = {image_data_body_font_0x55, 6, 10}; + +static const uint8_t image_data_body_font_0x56[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x56 = {image_data_body_font_0x56, 6, 10}; + +static const uint8_t image_data_body_font_0x57[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x57 = {image_data_body_font_0x57, 8, 10}; + +static const uint8_t image_data_body_font_0x58[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x58 = {image_data_body_font_0x58, 6, 10}; + +static const uint8_t image_data_body_font_0x59[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x59 = {image_data_body_font_0x59, 6, 10}; + +static const uint8_t image_data_body_font_0x5a[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5a = {image_data_body_font_0x5a, 6, 10}; + +static const uint8_t image_data_body_font_0x5b[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5b = {image_data_body_font_0x5b, 4, 10}; + +static const uint8_t image_data_body_font_0x5c[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5c = {image_data_body_font_0x5c, 8, 10}; + +static const uint8_t image_data_body_font_0x5d[40] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5d = {image_data_body_font_0x5d, 4, 10}; + +static const uint8_t image_data_body_font_0x5e[40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5e = {image_data_body_font_0x5e, 4, 10}; + +static const uint8_t image_data_body_font_0x5f[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x5f = {image_data_body_font_0x5f, 6, 10}; + +static const uint8_t image_data_body_font_0x60[30] = { + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x60 = {image_data_body_font_0x60, 3, 10}; + +static const uint8_t image_data_body_font_0x61[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x61 = {image_data_body_font_0x61, 6, 10}; + +static const uint8_t image_data_body_font_0x62[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x62 = {image_data_body_font_0x62, 6, 10}; + +static const uint8_t image_data_body_font_0x63[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x63 = {image_data_body_font_0x63, 6, 10}; + +static const uint8_t image_data_body_font_0x64[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x64 = {image_data_body_font_0x64, 6, 10}; + +static const uint8_t image_data_body_font_0x65[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x65 = {image_data_body_font_0x65, 6, 10}; + +static const uint8_t image_data_body_font_0x66[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x66 = {image_data_body_font_0x66, 5, 10}; + +static const uint8_t image_data_body_font_0x67[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage body_font_0x67 = {image_data_body_font_0x67, 6, 10}; + +static const uint8_t image_data_body_font_0x68[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x68 = {image_data_body_font_0x68, 6, 10}; + +static const uint8_t image_data_body_font_0x69[20] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x69 = {image_data_body_font_0x69, 2, 10}; + +static const uint8_t image_data_body_font_0x6a[30] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff}; +static const CharacterImage body_font_0x6a = {image_data_body_font_0x6a, 3, 10}; + +static const uint8_t image_data_body_font_0x6b[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x6b = {image_data_body_font_0x6b, 5, 10}; + +static const uint8_t image_data_body_font_0x6c[20] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x6c = {image_data_body_font_0x6c, 2, 10}; + +static const uint8_t image_data_body_font_0x6d[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x6d = {image_data_body_font_0x6d, 8, 10}; + +static const uint8_t image_data_body_font_0x6e[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x6e = {image_data_body_font_0x6e, 6, 10}; + +static const uint8_t image_data_body_font_0x6f[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x6f = {image_data_body_font_0x6f, 6, 10}; + +static const uint8_t image_data_body_font_0x70[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x70 = {image_data_body_font_0x70, 6, 10}; + +static const uint8_t image_data_body_font_0x71[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff}; +static const CharacterImage body_font_0x71 = {image_data_body_font_0x71, 6, 10}; + +static const uint8_t image_data_body_font_0x72[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x72 = {image_data_body_font_0x72, 5, 10}; + +static const uint8_t image_data_body_font_0x73[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x73 = {image_data_body_font_0x73, 6, 10}; + +static const uint8_t image_data_body_font_0x74[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x74 = {image_data_body_font_0x74, 5, 10}; + +static const uint8_t image_data_body_font_0x75[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x75 = {image_data_body_font_0x75, 6, 10}; + +static const uint8_t image_data_body_font_0x76[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x76 = {image_data_body_font_0x76, 6, 10}; + +static const uint8_t image_data_body_font_0x77[80] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x77 = {image_data_body_font_0x77, 8, 10}; + +static const uint8_t image_data_body_font_0x78[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x78 = {image_data_body_font_0x78, 6, 10}; + +static const uint8_t image_data_body_font_0x79[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff}; +static const CharacterImage body_font_0x79 = {image_data_body_font_0x79, 6, 10}; + +static const uint8_t image_data_body_font_0x7a[60] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x7a = {image_data_body_font_0x7a, 6, 10}; + +static const uint8_t image_data_body_font_0x7b[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x7b = {image_data_body_font_0x7b, 5, 10}; + +static const uint8_t image_data_body_font_0x7c[20] = { + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x7c = {image_data_body_font_0x7c, 2, 10}; + +static const uint8_t image_data_body_font_0x7d[50] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x7d = {image_data_body_font_0x7d, 5, 10}; + +static const uint8_t image_data_body_font_0x7e[70] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const CharacterImage body_font_0x7e = {image_data_body_font_0x7e, 7, 10}; + +static const Character body_font_array[] = { /* SegWit logo */ {0x01, &segwit_12x10}, @@ -3729,9 +2469,8 @@ static const Character body_font_array[] = }; -static const Font body_font = { sizeof(body_font_array)/sizeof(body_font_array[0]), - 10, body_font_array }; - +static const Font body_font = { + sizeof(body_font_array) / sizeof(body_font_array[0]), 10, body_font_array}; /* * get_pin_font() - Get pointer to PIN font @@ -3741,10 +2480,7 @@ static const Font body_font = { sizeof(body_font_array)/sizeof(body_font_array[0 * OUTPUT * PIN font */ -const Font *get_pin_font(void) -{ - return &pin_font; -} +const Font *get_pin_font(void) { return &pin_font; } /* * get_title_font() - Get pointer to title font @@ -3754,10 +2490,7 @@ const Font *get_pin_font(void) * OUTPUT * title font */ -const Font *get_title_font(void) -{ - return &title_font; -} +const Font *get_title_font(void) { return &title_font; } /* * get_body_font() - Get pointer to body font @@ -3768,10 +2501,7 @@ const Font *get_title_font(void) * body font * */ -const Font *get_body_font(void) -{ - return &body_font; -} +const Font *get_body_font(void) { return &body_font; } /* * font_get_char() - Get a character from the provided font @@ -3786,17 +2516,14 @@ const Font *get_body_font(void) * pointer to ascii charactor image * */ -const CharacterImage *font_get_char(const Font *font, char c) -{ - for (int i = 0; i < font->length; i++) - { - if(font->characters[ i ].code == c) - { - return font->characters[ i ].image; - } +const CharacterImage *font_get_char(const Font *font, char c) { + for (int i = 0; i < font->length; i++) { + if (font->characters[i].code == c) { + return font->characters[i].image; } + } - return &sadface_9x10; + return &sadface_9x10; } /* @@ -3807,10 +2534,7 @@ const CharacterImage *font_get_char(const Font *font, char c) * OUTPUT * font height */ -uint32_t font_height(const Font *font) -{ - return font->size; -} +uint32_t font_height(const Font *font) { return font->size; } /* * font_width() - Get font width @@ -3820,10 +2544,9 @@ uint32_t font_height(const Font *font) * OUTPUT * font width */ -uint32_t font_width(const Font *font) -{ - /*Return worst case width using the | char as the reference. */ - return font_get_char(font, '|')->width; +uint32_t font_width(const Font *font) { + /*Return worst case width using the | char as the reference. */ + return font_get_char(font, '|')->width; } /* @@ -3835,21 +2558,20 @@ uint32_t font_width(const Font *font) * OUTPUT * calculated string width */ -uint32_t calc_str_width(const Font *font, const char *str) -{ - int width = 0; - - while(str[0] != '\0') - { - width += font_get_char(font, str[0])->width; - str++; - } +uint32_t calc_str_width(const Font *font, const char *str) { + int width = 0; + + while (str[0] != '\0') { + width += font_get_char(font, str[0])->width; + str++; + } - return width; + return width; } /* - * calc_str_line() - Calculates how many lines a string will occupy given a line width + * calc_str_line() - Calculates how many lines a string will occupy given a line + * width * * INPUT * - font: pointer to font structure @@ -3858,53 +2580,47 @@ uint32_t calc_str_width(const Font *font, const char *str) * OUTPUT * line count */ -uint32_t calc_str_line(const Font *font, const char *str, uint16_t line_width) -{ - uint8_t line_count = 1; - uint16_t x_offset = 0; - - while(*str) - { - uint8_t character_width = font_get_char(font, str[0])->width; - uint16_t word_width = character_width; - char *next_character = (char *)str + 1; - - /* Allow line breaks */ - if(*str == '\n') - { - line_count++; - x_offset = 0; - str++; - continue; - } - - /* Calculate next work width */ - if(*str == ' ') - { - while(*next_character && *next_character != ' ' && *next_character != '\n') - { - word_width += font_get_char(font, *next_character)->width; - next_character++; - } - } - - /* New line? */ - if(x_offset + word_width > line_width) - { - line_count++; - x_offset = 0; - } - - /* Remove leading spaces */ - if(x_offset == 0 && *str == ' ') - { - str++; - continue; - } - - x_offset += character_width; - str++; +uint32_t calc_str_line(const Font *font, const char *str, uint16_t line_width) { + uint8_t line_count = 1; + uint16_t x_offset = 0; + + while (*str) { + uint8_t character_width = font_get_char(font, str[0])->width; + uint16_t word_width = character_width; + char *next_character = (char *)str + 1; + + /* Allow line breaks */ + if (*str == '\n') { + line_count++; + x_offset = 0; + str++; + continue; } - return line_count; + /* Calculate next work width */ + if (*str == ' ') { + while (*next_character && *next_character != ' ' && + *next_character != '\n') { + word_width += font_get_char(font, *next_character)->width; + next_character++; + } + } + + /* New line? */ + if (x_offset + word_width > line_width) { + line_count++; + x_offset = 0; + } + + /* Remove leading spaces */ + if (x_offset == 0 && *str == ' ') { + str++; + continue; + } + + x_offset += character_width; + str++; + } + + return line_count; } diff --git a/lib/board/keepkey_board.c b/lib/board/keepkey_board.c index bed17993c..cfc957a65 100644 --- a/lib/board/keepkey_board.c +++ b/lib/board/keepkey_board.c @@ -17,16 +17,15 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include +#include #endif #include "keepkey/board/keepkey_board.h" @@ -36,7 +35,6 @@ #include #include - /* Stack smashing protector (SSP) canary value storage */ uintptr_t __stack_chk_guard; @@ -44,13 +42,9 @@ uintptr_t __stack_chk_guard; /** * \brief System Halt */ -void __attribute__((noreturn)) shutdown(void) -{ - exit(1); -} +void __attribute__((noreturn)) shutdown(void) { exit(1); } #endif - /* * __stack_chk_fail() - Stack smashing protector (SSP) call back funcation * for -fstack-protector-all GCC option @@ -60,22 +54,20 @@ void __attribute__((noreturn)) shutdown(void) * OUTPUT * none */ -__attribute__((noreturn)) void __stack_chk_fail(void) -{ - layout_warning_static("Error Detected. Reboot Device!"); - shutdown(); +__attribute__((noreturn)) void __stack_chk_fail(void) { + layout_warning_static("Error Detected. Reboot Device!"); + shutdown(); } #ifndef EMULATOR /// Non-maskable interrupt handler -void nmi_handler(void) -{ - // Look for the clock instability interrupt. This is a security measure - // that helps prevent clock glitching. - if ((RCC_CIR & RCC_CIR_CSSF) != 0) { - layout_warning_static("Clock instability detected. Reboot Device!"); - shutdown(); - } +void nmi_handler(void) { + // Look for the clock instability interrupt. This is a security measure + // that helps prevent clock glitching. + if ((RCC_CIR & RCC_CIR_CSSF) != 0) { + layout_warning_static("Clock instability detected. Reboot Device!"); + shutdown(); + } } #endif @@ -87,10 +79,9 @@ void nmi_handler(void) * OUTPUT * none */ -void board_reset(void) -{ +void board_reset(void) { #ifndef EMULATOR - scb_reset_system(); + scb_reset_system(); #endif } @@ -102,32 +93,30 @@ void board_reset(void) * OUTPUT * none */ -void kk_board_init(void) -{ - kk_timer_init(); +void kk_board_init(void) { + kk_timer_init(); -// keepkey_leds_init(); - led_func(CLR_GREEN_LED); - led_func(CLR_RED_LED); + // keepkey_leds_init(); + led_func(CLR_GREEN_LED); + led_func(CLR_RED_LED); - kk_keepkey_button_init(); + kk_keepkey_button_init(); #ifndef EMULATOR - svc_enable_interrupts(); // This enables the timer and button interrupts + svc_enable_interrupts(); // This enables the timer and button interrupts #endif - layout_init(display_canvas_init()); + layout_init(display_canvas_init()); } #ifdef EMULATOR /// Reverses (reflects) bits in a 32-bit word. /// http://www.hackersdelight.org/hdcodetxt/crc.c.txt static uint32_t reverse(unsigned x) { - x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555); - x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333); - x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F); - x = (x << 24) | ((x & 0xFF00) << 8) | - ((x >> 8) & 0xFF00) | (x >> 24); - return x; + x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555); + x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333); + x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F); + x = (x << 24) | ((x & 0xFF00) << 8) | ((x >> 8) & 0xFF00) | (x >> 24); + return x; } #endif @@ -138,29 +127,28 @@ static uint32_t reverse(unsigned x) { * OUTPUT * crc32 of data */ -uint32_t calc_crc32(const void *data, int word_len) -{ - uint32_t crc32 = 0; +uint32_t calc_crc32(const void *data, int word_len) { + uint32_t crc32 = 0; #ifndef EMULATOR - crc_reset(); - crc32 = crc_calculate_block((uint32_t*)data, word_len); + crc_reset(); + crc32 = crc_calculate_block((uint32_t *)data, word_len); #else - /// http://www.hackersdelight.org/hdcodetxt/crc.c.txt - crc32 = 0xFFFFFFFF; - for (int i = 0; i < word_len; i++) { - uint32_t byte = ((const char *)data)[i]; // Get next byte. - byte = reverse(byte); // 32-bit reversal. - for (int j = 0; j <= 7; j++) { // Do eight times. - if ((int)(crc32 ^ byte) < 0) - crc32 = (crc32 << 1) ^ 0x04C11DB7; - else crc32 = crc32 << 1; - byte = byte << 1; // Ready next msg bit. - } + /// http://www.hackersdelight.org/hdcodetxt/crc.c.txt + crc32 = 0xFFFFFFFF; + for (int i = 0; i < word_len; i++) { + uint32_t byte = ((const char *)data)[i]; // Get next byte. + byte = reverse(byte); // 32-bit reversal. + for (int j = 0; j <= 7; j++) { // Do eight times. + if ((int)(crc32 ^ byte) < 0) + crc32 = (crc32 << 1) ^ 0x04C11DB7; + else + crc32 = crc32 << 1; + byte = byte << 1; // Ready next msg bit. } - crc32 = reverse(~crc32); + } + crc32 = reverse(~crc32); #endif - return crc32; + return crc32; } - diff --git a/lib/board/keepkey_button.c b/lib/board/keepkey_button.c index 08541e390..b0b453faa 100644 --- a/lib/board/keepkey_button.c +++ b/lib/board/keepkey_button.c @@ -17,13 +17,12 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include #endif #include "keepkey/board/keepkey_button.h" @@ -32,26 +31,24 @@ #include - -static Handler on_press_handler = NULL; -static Handler on_release_handler = NULL; +static Handler on_press_handler = NULL; +static Handler on_release_handler = NULL; static void *on_release_handler_context = NULL; -static void *on_press_handler_context = NULL; +static void *on_press_handler_context = NULL; #ifndef EMULATOR -static const uint16_t BUTTON_PIN = GPIO7; -static const uint32_t BUTTON_PORT = GPIOB; -static const uint32_t BUTTON_EXTI = EXTI7; +static const uint16_t BUTTON_PIN = GPIO7; +static const uint32_t BUTTON_PORT = GPIOB; +static const uint32_t BUTTON_EXTI = EXTI7; #endif -void kk_keepkey_button_init(void) -{ - on_press_handler = NULL; - on_press_handler_context = NULL; +void kk_keepkey_button_init(void) { + on_press_handler = NULL; + on_press_handler_context = NULL; - on_release_handler = NULL; - on_release_handler_context = NULL; + on_release_handler = NULL; + on_release_handler_context = NULL; } /* @@ -63,31 +60,22 @@ void kk_keepkey_button_init(void) * OUTPUT * none */ -void keepkey_button_init(void) -{ - on_press_handler = NULL; - on_press_handler_context = NULL; +void keepkey_button_init(void) { + on_press_handler = NULL; + on_press_handler_context = NULL; - on_release_handler = NULL; - on_release_handler_context = NULL; + on_release_handler = NULL; + on_release_handler_context = NULL; #ifndef EMULATOR - gpio_mode_setup( - BUTTON_PORT, - GPIO_MODE_INPUT, - GPIO_PUPD_NONE, - BUTTON_PIN); + gpio_mode_setup(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, BUTTON_PIN); - /* Configure the EXTI subsystem. */ - exti_select_source( - BUTTON_EXTI, - GPIOB); + /* Configure the EXTI subsystem. */ + exti_select_source(BUTTON_EXTI, GPIOB); - exti_set_trigger( - BUTTON_EXTI, - EXTI_TRIGGER_BOTH); + exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_BOTH); - exti_enable_request(BUTTON_EXTI); + exti_enable_request(BUTTON_EXTI); #endif } @@ -103,10 +91,9 @@ void keepkey_button_init(void) * none * */ -void keepkey_button_set_on_press_handler(Handler handler, void *context) -{ - on_press_handler = handler; - on_press_handler_context = context; +void keepkey_button_set_on_press_handler(Handler handler, void *context) { + on_press_handler = handler; + on_press_handler_context = context; } /* @@ -120,10 +107,9 @@ void keepkey_button_set_on_press_handler(Handler handler, void *context) * none * */ -void keepkey_button_set_on_release_handler(Handler handler, void *context) -{ - on_release_handler = handler; - on_release_handler_context = context; +void keepkey_button_set_on_release_handler(Handler handler, void *context) { + on_release_handler = handler; + on_release_handler_context = context; } /* @@ -134,13 +120,12 @@ void keepkey_button_set_on_release_handler(Handler handler, void *context) * OUTPUT * true/false state of push button up */ -bool keepkey_button_up(void) -{ +bool keepkey_button_up(void) { #ifndef EMULATOR - uint16_t port = gpio_port_read(BUTTON_PORT); - return port & BUTTON_PIN; + uint16_t port = gpio_port_read(BUTTON_PORT); + return port & BUTTON_PIN; #else - return false; + return false; #endif } @@ -152,30 +137,22 @@ bool keepkey_button_up(void) * OUTPUT * true/false state of push button down */ -bool keepkey_button_down(void) -{ - return !keepkey_button_up(); -} +bool keepkey_button_down(void) { return !keepkey_button_up(); } -void buttonisr_usr(void) -{ +void buttonisr_usr(void) { #ifndef EMULATOR - if(gpio_get(BUTTON_PORT, BUTTON_PIN) & BUTTON_PIN) - { - if(on_release_handler) - { - on_release_handler(on_release_handler_context); - } + if (gpio_get(BUTTON_PORT, BUTTON_PIN) & BUTTON_PIN) { + if (on_release_handler) { + on_release_handler(on_release_handler_context); } - else - { - if(on_press_handler) - { - on_press_handler(on_press_handler_context); - } + } else { + if (on_press_handler) { + on_press_handler(on_press_handler_context); } + } - svc_busr_return(); // this MUST be called last to properly clean up and return + svc_busr_return(); // this MUST be called last to properly clean up and + // return #endif } diff --git a/lib/board/keepkey_display.c b/lib/board/keepkey_display.c index 489f73af2..1a0fe38ab 100644 --- a/lib/board/keepkey_display.c +++ b/lib/board/keepkey_display.c @@ -18,8 +18,8 @@ */ #ifndef EMULATOR -# include -# include +#include +#include #endif #include "keepkey/board/keepkey_display.h" @@ -31,18 +31,19 @@ #pragma GCC optimize("-O3") #ifndef EMULATOR -static const Pin nOE_PIN = { GPIOA, GPIO8 }; -static const Pin nWE_PIN = { GPIOA, GPIO9 }; -static const Pin nDC_PIN = { GPIOB, GPIO1 }; +static const Pin nOE_PIN = {GPIOA, GPIO8}; +static const Pin nWE_PIN = {GPIOA, GPIO9}; +static const Pin nDC_PIN = {GPIOB, GPIO1}; -static const Pin nSEL_PIN = { GPIOA, GPIO10 }; -static const Pin nRESET_PIN = { GPIOB, GPIO5 }; +static const Pin nSEL_PIN = {GPIOA, GPIO10}; +static const Pin nRESET_PIN = {GPIOB, GPIO5}; -static const Pin BACKLIGHT_PWR_PIN = { GPIOB, GPIO0 }; +static const Pin BACKLIGHT_PWR_PIN = {GPIOB, GPIO0}; #endif -static uint8_t canvas_buffer[ KEEPKEY_DISPLAY_HEIGHT * KEEPKEY_DISPLAY_WIDTH ]; +static uint8_t canvas_buffer[KEEPKEY_DISPLAY_HEIGHT * KEEPKEY_DISPLAY_WIDTH]; static Canvas canvas; +bool constant_power = false; /* * display_write_reg() - Write data to display register @@ -52,56 +53,55 @@ static Canvas canvas; * OUTPUT * none */ -static void display_write_reg(uint8_t reg) -{ +static void display_write_reg(uint8_t reg) { #ifndef EMULATOR - svc_disable_interrupts(); + svc_disable_interrupts(); - /* Set up the data */ - GPIO_BSRR(GPIOA) = 0x000000FF & (uint32_t)reg; + /* Set up the data */ + GPIO_BSRR(GPIOA) = 0x000000FF & (uint32_t)reg; - /* Set nOLED_SEL low, nMEM_OE high, and nMEM_WE high. */ - CLEAR_PIN(nSEL_PIN); - SET_PIN(nOE_PIN); - SET_PIN(nWE_PIN); + /* Set nOLED_SEL low, nMEM_OE high, and nMEM_WE high. */ + CLEAR_PIN(nSEL_PIN); + SET_PIN(nOE_PIN); + SET_PIN(nWE_PIN); - __asm__("nop"); - __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - /* Set nDC low */ - CLEAR_PIN(nDC_PIN); + /* Set nDC low */ + CLEAR_PIN(nDC_PIN); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - /* Set nMEM_WE low */ - CLEAR_PIN(nWE_PIN); + /* Set nMEM_WE low */ + CLEAR_PIN(nWE_PIN); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - /* Set nMEM_WE high */ - SET_PIN(nWE_PIN); + /* Set nMEM_WE high */ + SET_PIN(nWE_PIN); - __asm__("nop"); - __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - /* Set nOLED_SEL high */ - SET_PIN(nSEL_PIN); - GPIO_BSRR(GPIOA) = 0x00FF0000; + /* Set nOLED_SEL high */ + SET_PIN(nSEL_PIN); + GPIO_BSRR(GPIOA) = 0x00FF0000; - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - svc_enable_interrupts(); + svc_enable_interrupts(); #endif } @@ -114,16 +114,15 @@ static void display_write_reg(uint8_t reg) * OUTPUT * none */ -static void display_reset(void) -{ +static void display_reset(void) { #ifndef EMULATOR - CLEAR_PIN(nRESET_PIN); + CLEAR_PIN(nRESET_PIN); - delay_ms(10); + delay_ms(10); - SET_PIN(nRESET_PIN); + SET_PIN(nRESET_PIN); - delay_ms(50); + delay_ms(50); #endif } @@ -133,19 +132,18 @@ static void display_reset(void) * INPUT - none * OUTPUT - none */ -static void display_reset_io(void) -{ +static void display_reset_io(void) { #ifndef EMULATOR - svc_disable_interrupts(); - SET_PIN(nRESET_PIN); - CLEAR_PIN(BACKLIGHT_PWR_PIN); - SET_PIN(nWE_PIN); - SET_PIN(nOE_PIN); - SET_PIN(nDC_PIN); - SET_PIN(nSEL_PIN); - - GPIO_BSRR(GPIOA) = 0x00FF0000; - svc_enable_interrupts(); + svc_disable_interrupts(); + SET_PIN(nRESET_PIN); + CLEAR_PIN(BACKLIGHT_PWR_PIN); + SET_PIN(nWE_PIN); + SET_PIN(nOE_PIN); + SET_PIN(nDC_PIN); + SET_PIN(nSEL_PIN); + + GPIO_BSRR(GPIOA) = 0x00FF0000; + svc_enable_interrupts(); #endif } @@ -157,37 +155,26 @@ static void display_reset_io(void) * OUTPUT * none */ -static void display_configure_io(void) -{ +static void display_configure_io(void) { #ifndef EMULATOR - /* Set up port A */ - gpio_mode_setup( - GPIOA, - GPIO_MODE_OUTPUT, - GPIO_PUPD_NONE, - GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO6 | GPIO7 | GPIO8 | GPIO9 | GPIO10); - - gpio_set_output_options( - GPIOA, - GPIO_OTYPE_PP, - GPIO_OSPEED_100MHZ, - GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO6 | GPIO7 | GPIO8 | GPIO9 | GPIO10); - - /* Set up port B */ - gpio_mode_setup( - GPIOB, - GPIO_MODE_OUTPUT, - GPIO_PUPD_NONE, - GPIO0 | GPIO1 | GPIO5); - - gpio_set_output_options( - GPIOB, - GPIO_OTYPE_PP, - GPIO_OSPEED_100MHZ, - GPIO0 | GPIO1 | GPIO5); - - /* Set to defaults */ - display_reset_io(); + /* Set up port A */ + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO6 | + GPIO7 | GPIO8 | GPIO9 | GPIO10); + + gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, + GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | + GPIO6 | GPIO7 | GPIO8 | GPIO9 | GPIO10); + + /* Set up port B */ + gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, + GPIO0 | GPIO1 | GPIO5); + + gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, + GPIO0 | GPIO1 | GPIO5); + + /* Set to defaults */ + display_reset_io(); #endif } @@ -199,10 +186,9 @@ static void display_configure_io(void) * OUTPUT * none */ -static void display_prepare_gram_write(void) -{ +static void display_prepare_gram_write(void) { #ifndef EMULATOR - display_write_reg((uint8_t)0x5C); + display_write_reg((uint8_t)0x5C); #endif } @@ -214,60 +200,58 @@ static void display_prepare_gram_write(void) * OUTPUT * none */ -static void display_write_ram(uint8_t val) -{ +static void display_write_ram(uint8_t val) { #ifndef EMULATOR - svc_disable_interrupts(); + svc_disable_interrupts(); + + /* Set up the data */ + GPIO_BSRR(GPIOA) = 0x000000FF & (uint32_t)val; - /* Set up the data */ - GPIO_BSRR(GPIOA) = 0x000000FF & (uint32_t)val; + /* Set nOLED_SEL low, nMEM_OE high, and nMEM_WE high. */ + CLEAR_PIN(nSEL_PIN); + SET_PIN(nOE_PIN); + SET_PIN(nWE_PIN); - /* Set nOLED_SEL low, nMEM_OE high, and nMEM_WE high. */ - CLEAR_PIN(nSEL_PIN); - SET_PIN(nOE_PIN); - SET_PIN(nWE_PIN); + __asm__("nop"); + __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + /* Set nDC high */ + SET_PIN(nDC_PIN); - /* Set nDC high */ - SET_PIN(nDC_PIN); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + /* Set nMEM_WE low */ + CLEAR_PIN(nWE_PIN); - /* Set nMEM_WE low */ - CLEAR_PIN(nWE_PIN); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + /* Set nMEM_WE high */ + SET_PIN(nWE_PIN); - /* Set nMEM_WE high */ - SET_PIN(nWE_PIN); + __asm__("nop"); + __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + /* Set nOLED_SEL high */ + SET_PIN(nSEL_PIN); + GPIO_BSRR(GPIOA) = 0x00FF0000; - /* Set nOLED_SEL high */ - SET_PIN(nSEL_PIN); - GPIO_BSRR(GPIOA) = 0x00FF0000; + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); + __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); - __asm__("nop"); + svc_enable_interrupts(); - svc_enable_interrupts(); - #endif } - /* * display_canvas_init() - Display canvas initialization * @@ -276,15 +260,14 @@ static void display_write_ram(uint8_t val) * OUTPUT * pointer to canvas */ -Canvas *display_canvas_init(void) -{ - /* Prepare the canvas */ - canvas.buffer = canvas_buffer; - canvas.width = KEEPKEY_DISPLAY_WIDTH; - canvas.height = KEEPKEY_DISPLAY_HEIGHT; - canvas.dirty = false; - - return &canvas; +Canvas *display_canvas_init(void) { + /* Prepare the canvas */ + canvas.buffer = canvas_buffer; + canvas.width = KEEPKEY_DISPLAY_WIDTH; + canvas.height = KEEPKEY_DISPLAY_HEIGHT; + canvas.dirty = false; + + return &canvas; } /* @@ -295,15 +278,10 @@ Canvas *display_canvas_init(void) * OUTPUT * pointer to canvas */ -Canvas *display_canvas(void) -{ - return &canvas; -} +Canvas *display_canvas(void) { return &canvas; } void (*DumpDisplay)(const uint8_t *buf) = 0; -void display_set_dump_callback(DumpDisplayCallback d) { - DumpDisplay = d; -} +void display_set_dump_callback(DumpDisplayCallback d) { DumpDisplay = d; } /* * display_refresh() - Refresh display @@ -324,6 +302,14 @@ void display_refresh(void) return; } + if (constant_power) { + for (int y = 0; y < 64; y++) { + for (int x = 0; x < 128; x++) { + canvas.buffer[y * 256 + x] = 255 - canvas.buffer[y * 256 + x + 128]; + } + } + } + display_prepare_gram_write(); int num_writes = canvas.width * canvas.height; @@ -331,19 +317,17 @@ void display_refresh(void) int i; #ifdef INVERT_DISPLAY - for(i = num_writes; i > 0; i -= 2) - { - uint8_t v = (0xF0 & canvas.buffer[ i ]) | (canvas.buffer[ i - 1 ] >> 4); + for (i = num_writes; i > 0; i -= 2) { + uint8_t v = (0xF0 & canvas.buffer[i]) | (canvas.buffer[i - 1] >> 4); #else - for(i = 0; i < num_writes; i += 2) - { - uint8_t v = (0xF0 & canvas.buffer[ i ]) | (canvas.buffer[ i + 1 ] >> 4); + for (i = 0; i < num_writes; i += 2) { + uint8_t v = (0xF0 & canvas.buffer[i]) | (canvas.buffer[i + 1] >> 4); #endif - display_write_ram(v); - } + display_write_ram(v); + } - canvas.dirty = false; + canvas.dirty = false; } /* @@ -354,10 +338,7 @@ void display_refresh(void) * OUTPUT * none */ -void display_turn_on(void) -{ - display_write_reg((uint8_t)0xAF); -} +void display_turn_on(void) { display_write_reg((uint8_t)0xAF); } /* * display_turn_off() - Turn off display @@ -372,7 +353,10 @@ void display_turn_off(void) display_write_reg((uint8_t)0xAE); } - +void display_constant_power(bool enabled) +{ + constant_power = enabled; +} /* * display_hw_init(void) - Display hardware initialization @@ -382,118 +366,115 @@ void display_turn_off(void) * OUTPUT * none */ -void display_hw_init(void) -{ +void display_hw_init(void) { #ifndef EMULATOR - display_configure_io(); + display_configure_io(); - CLEAR_PIN(BACKLIGHT_PWR_PIN); + CLEAR_PIN(BACKLIGHT_PWR_PIN); - display_reset(); + display_reset(); - display_write_reg((uint8_t)0xFD); - display_write_ram((uint8_t)0x12); + display_write_reg((uint8_t)0xFD); + display_write_ram((uint8_t)0x12); - display_turn_off(); + display_turn_off(); - /* Divide DIVSET by 2 */ - display_write_reg((uint8_t)0xB3); - display_write_ram((uint8_t)0x91); + /* Divide DIVSET by 2 */ + display_write_reg((uint8_t)0xB3); + display_write_ram((uint8_t)0x91); - display_write_reg((uint8_t)0xCA); - display_write_ram((uint8_t)0x3F); + display_write_reg((uint8_t)0xCA); + display_write_ram((uint8_t)0x3F); - display_write_reg((uint8_t)0xA2); - display_write_ram((uint8_t)0x00); + display_write_reg((uint8_t)0xA2); + display_write_ram((uint8_t)0x00); - display_write_reg((uint8_t)0xA1); - display_write_ram((uint8_t)0x00); + display_write_reg((uint8_t)0xA1); + display_write_ram((uint8_t)0x00); + uint8_t row_start = START_ROW; + uint8_t row_end = row_start + 64 - 1; - uint8_t row_start = START_ROW; - uint8_t row_end = row_start + 64 - 1; - - /* Width is in units of 4 pixels/column (2 bytes at 4 bits/pixel) */ - int width = (256 / 4); - uint8_t col_start = START_COL; - uint8_t col_end = col_start + width - 1; - - display_write_reg((uint8_t)0x75); - display_write_ram(row_start); - display_write_ram(row_end); - display_write_reg((uint8_t)0x15); - display_write_ram(col_start); - display_write_ram(col_end); - - /* Horizontal address increment */ - /* Disable colum address re-map */ - /* Disable nibble re-map */ - /* Scan from COM0 to COM[n-1] */ - /* Disable dual COM mode */ - display_write_reg((uint8_t)0xA0); - display_write_ram((uint8_t)0x14); - display_write_ram((uint8_t)0x11); - - /* GPIO0: pin HiZ, Input disabled */ - /* GPIO1: pin HiZ, Input disabled */ - display_write_reg((uint8_t)0xB5); - display_write_ram((uint8_t)0x00); + /* Width is in units of 4 pixels/column (2 bytes at 4 bits/pixel) */ + int width = (256 / 4); + uint8_t col_start = START_COL; + uint8_t col_end = col_start + width - 1; - /* Enable internal Vdd regulator */ - display_write_reg((uint8_t)0xAB); - display_write_ram((uint8_t)0x01); + display_write_reg((uint8_t)0x75); + display_write_ram(row_start); + display_write_ram(row_end); + display_write_reg((uint8_t)0x15); + display_write_ram(col_start); + display_write_ram(col_end); - display_write_reg((uint8_t)0xB4); - display_write_ram((uint8_t)0xA0); - display_write_ram((uint8_t)0xFD); + /* Horizontal address increment */ + /* Disable colum address re-map */ + /* Disable nibble re-map */ + /* Scan from COM0 to COM[n-1] */ + /* Disable dual COM mode */ + display_write_reg((uint8_t)0xA0); + display_write_ram((uint8_t)0x14); + display_write_ram((uint8_t)0x11); - display_set_brightness(DEFAULT_DISPLAY_BRIGHTNESS); + /* GPIO0: pin HiZ, Input disabled */ + /* GPIO1: pin HiZ, Input disabled */ + display_write_reg((uint8_t)0xB5); + display_write_ram((uint8_t)0x00); - display_write_reg((uint8_t)0xC7); - display_write_ram((uint8_t)0x0F); + /* Enable internal Vdd regulator */ + display_write_reg((uint8_t)0xAB); + display_write_ram((uint8_t)0x01); - display_write_reg((uint8_t)0xB9); + display_write_reg((uint8_t)0xB4); + display_write_ram((uint8_t)0xA0); + display_write_ram((uint8_t)0xFD); - display_write_reg((uint8_t)0xB1); - display_write_ram((uint8_t)0xE2); + display_set_brightness(DEFAULT_DISPLAY_BRIGHTNESS); - display_write_reg((uint8_t)0xD1); - display_write_ram((uint8_t)0x82); - display_write_ram((uint8_t)0x20); + display_write_reg((uint8_t)0xC7); + display_write_ram((uint8_t)0x0F); - display_write_reg((uint8_t)0xBB); - display_write_ram((uint8_t)0x1F); + display_write_reg((uint8_t)0xB9); - display_write_reg((uint8_t)0xB6); - display_write_ram((uint8_t)0x08); + display_write_reg((uint8_t)0xB1); + display_write_ram((uint8_t)0xE2); - display_write_reg((uint8_t)0xBE); - display_write_ram((uint8_t)0x07); + display_write_reg((uint8_t)0xD1); + display_write_ram((uint8_t)0x82); + display_write_ram((uint8_t)0x20); - display_write_reg((uint8_t)0xA6); + display_write_reg((uint8_t)0xBB); + display_write_ram((uint8_t)0x1F); - delay_ms(10); + display_write_reg((uint8_t)0xB6); + display_write_ram((uint8_t)0x08); - /* Set the screen to display-writing mode */ - display_prepare_gram_write(); + display_write_reg((uint8_t)0xBE); + display_write_ram((uint8_t)0x07); - delay_ms(10); + display_write_reg((uint8_t)0xA6); - /* Make the display blank */ - int end = 64 * 256; - int i; + delay_ms(10); - for(i = 0; i < end; i += 2) - { - display_write_ram((uint8_t)0x00); - } + /* Set the screen to display-writing mode */ + display_prepare_gram_write(); + + delay_ms(10); - /* Turn on 12V */ - SET_PIN(BACKLIGHT_PWR_PIN); + /* Make the display blank */ + int end = 64 * 256; + int i; - delay_ms(100); + for (i = 0; i < end; i += 2) { + display_write_ram((uint8_t)0x00); + } + + /* Turn on 12V */ + SET_PIN(BACKLIGHT_PWR_PIN); + + delay_ms(100); - display_turn_on(); + display_turn_on(); #endif } @@ -505,23 +486,21 @@ void display_hw_init(void) * OUTPUT * none */ -void display_set_brightness(int percentage) -{ +void display_set_brightness(int percentage) { #ifndef EMULATOR - int v = percentage; + int v = percentage; - /* Clip to be 0 <= value <= 100 */ - v = (v >= 0) ? v : 0; - v = (v > 100) ? 100 : v; + /* Clip to be 0 <= value <= 100 */ + v = (v >= 0) ? v : 0; + v = (v > 100) ? 100 : v; - v = (0xFF * v) / 100; + v = (0xFF * v) / 100; - uint8_t reg_value = (uint8_t)v; + uint8_t reg_value = (uint8_t)v; - display_write_reg((uint8_t)0xC1); - display_write_ram(reg_value); + display_write_reg((uint8_t)0xC1); + display_write_ram(reg_value); #endif } #pragma GCC pop_options - diff --git a/lib/board/keepkey_flash.c b/lib/board/keepkey_flash.c index 7cc07025b..c38df243b 100644 --- a/lib/board/keepkey_flash.c +++ b/lib/board/keepkey_flash.c @@ -17,13 +17,12 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include +#include +#include #else -# include -# include +#include +#include #endif #include "keepkey/board/check_bootloader.h" @@ -42,28 +41,25 @@ uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; /* - * flash_write_helper() - Helper function to locate starting address of + * flash_write_helper() - Helper function to locate starting address of * the functional group - * + * * INPUT * - group: functional group * OUTPUT * starting address of functional group */ -intptr_t flash_write_helper(Allocation group) -{ - intptr_t start = 0; - const FlashSector* s = flash_sector_map; - while(s->use != FLASH_INVALID) - { - if(s->use == group) - { - start = s->start; - break; - } - ++s; +intptr_t flash_write_helper(Allocation group) { + intptr_t start = 0; + const FlashSector *s = flash_sector_map; + while (s->use != FLASH_INVALID) { + if (s->use == group) { + start = s->start; + break; } - return (intptr_t)FLASH_PTR(start); + ++s; + } + return (intptr_t)FLASH_PTR(start); } /* @@ -74,41 +70,40 @@ intptr_t flash_write_helper(Allocation group) * OUTPUT * true/false flash operation status */ -bool flash_chk_status(void) -{ +bool flash_chk_status(void) { #ifndef EMULATOR - if(FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { - /* Flash error detected */ - return(false); - }else { - /* Flash operation successful */ - return(true); - } + if (FLASH_SR & + (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { + /* Flash error detected */ + return (false); + } else { + /* Flash operation successful */ + return (true); + } #else - return true; + return true; #endif } /* - * flash_erase_word() - allows unpriv code to erase certain sectors, word size at a time. - * DO NOT USE THIS IN PRIV MODE, WILL NOT ERASE BOOTSTRAP OR BOOTLOADER SECTORS + * flash_erase_word() - allows unpriv code to erase certain sectors, word size + * at a time. DO NOT USE THIS IN PRIV MODE, WILL NOT ERASE BOOTSTRAP OR + * BOOTLOADER SECTORS * * INPUT * - group: functional group * OUTPUT * none */ -void flash_erase_word(Allocation group) -{ +void flash_erase_word(Allocation group) { #ifndef EMULATOR - const FlashSector* s = flash_sector_map; - while(s->use != FLASH_INVALID) - { - if(s->use == group) { - svc_flash_erase_sector((uint32_t)s->sector); - } - ++s; + const FlashSector *s = flash_sector_map; + while (s->use != FLASH_INVALID) { + if (s->use == group) { + svc_flash_erase_sector((uint32_t)s->sector); } + ++s; + } #endif } @@ -119,63 +114,63 @@ void flash_erase_word(Allocation group) * - group: functional group * - offset: flash address offset * - len: length of source data - * - data: pointer to source data + * - data: pointer to source data * OUTPUT: * true/false status of write */ -bool flash_write_word(Allocation group, uint32_t offset, uint32_t len, const uint8_t *data) -{ +bool flash_write_word(Allocation group, uint32_t offset, uint32_t len, + const uint8_t *data) { #ifndef EMULATOR - bool retval = true; - uint32_t start = flash_write_helper(group); - uint32_t data_word[1]; - uint32_t i, align_cnt = 0; + bool retval = true; + uint32_t start = flash_write_helper(group); + uint32_t data_word[1]; + uint32_t i, align_cnt = 0; - start += offset ; + start += offset; - /* Byte writes for flash start address not long-word aligned */ - if(start % sizeof(uint32_t)) { - align_cnt = sizeof(uint32_t) - start % sizeof(uint32_t); - if (svc_flash_pgm_blk(start, (uint32_t)data, align_cnt) == false) { - retval = false; - goto fww_exit; - } - /* Update new start address/data & len */ - start += align_cnt; - data += align_cnt; - len -= align_cnt; + /* Byte writes for flash start address not long-word aligned */ + if (start % sizeof(uint32_t)) { + align_cnt = sizeof(uint32_t) - start % sizeof(uint32_t); + if (svc_flash_pgm_blk(start, (uint32_t)data, align_cnt) == false) { + retval = false; + goto fww_exit; } + /* Update new start address/data & len */ + start += align_cnt; + data += align_cnt; + len -= align_cnt; + } - /* Long word writes */ - for(i = 0 ; i < len/sizeof(uint32_t); i++) - { - memcpy(data_word, data, sizeof(uint32_t)); - if (svc_flash_pgm_word(start, *data_word) == false) { - retval = false; - goto fww_exit; - } - start += sizeof(uint32_t); - data += sizeof(uint32_t); + /* Long word writes */ + for (i = 0; i < len / sizeof(uint32_t); i++) { + memcpy(data_word, data, sizeof(uint32_t)); + if (svc_flash_pgm_word(start, *data_word) == false) { + retval = false; + goto fww_exit; } + start += sizeof(uint32_t); + data += sizeof(uint32_t); + } - /* Byte write for last remaining bytes < longword */ - if(len % sizeof(uint32_t)) { - if (svc_flash_pgm_blk(start, (uint32_t)data, len % sizeof(uint32_t)) == false) { - retval = false; - } + /* Byte write for last remaining bytes < longword */ + if (len % sizeof(uint32_t)) { + if (svc_flash_pgm_blk(start, (uint32_t)data, len % sizeof(uint32_t)) == + false) { + retval = false; } + } fww_exit: - return(retval); + return (retval); #else - memcpy((void*)(flash_write_helper(group) + offset), data, len); - return true; + memcpy((void *)(flash_write_helper(group) + offset), data, len); + return true; #endif } /* * flash_write() - Flash write in byte size * - * INPUT : + * INPUT : * - group: functional group * - offset: flash address offset * - len: length of source data @@ -183,39 +178,38 @@ bool flash_write_word(Allocation group, uint32_t offset, uint32_t len, const uin * OUTPUT: * true/false status of write */ -bool flash_write(Allocation group, uint32_t offset, uint32_t len, const uint8_t *data) -{ +bool flash_write(Allocation group, uint32_t offset, uint32_t len, + const uint8_t *data) { #ifndef EMULATOR - bool retval = true; - uint32_t start = flash_write_helper(group); - if (svc_flash_pgm_blk(start+offset, (uint32_t)data, len) == false) { - retval = false; - } - return(retval); + bool retval = true; + uint32_t start = flash_write_helper(group); + if (svc_flash_pgm_blk(start + offset, (uint32_t)data, len) == false) { + retval = false; + } + return (retval); #else - memcpy((void*)(flash_write_helper(group) + offset), data, len); - return true; + memcpy((void *)(flash_write_helper(group) + offset), data, len); + return true; #endif } /* * is_mfg_mode() - Is device in manufacture mode * - * INPUT - + * INPUT - * none * OUTPUT - * none */ -bool is_mfg_mode(void) -{ +bool is_mfg_mode(void) { #if defined(EMULATOR) || defined(DEBUG_ON) - return false; + return false; #else - if (*(uint32_t *)OTP_MFG_ADDR == OTP_MFG_SIG) { - return false; - } + if (*(uint32_t *)OTP_MFG_ADDR == OTP_MFG_SIG) { + return false; + } - return true; + return true; #endif } @@ -224,68 +218,73 @@ bool is_mfg_mode(void) * * INPUT - * none - * OUTPUT - + * OUTPUT - * none */ -bool set_mfg_mode_off(void) -{ - bool ret_val = false; - uint32_t tvar; +bool set_mfg_mode_off(void) { + bool ret_val = false; + uint32_t tvar; #ifndef EMULATOR - /* check OTP lock state before updating */ - if(*(uint8_t *)OTP_BLK_LOCK(OTP_MFG_ADDR) == 0xFF) - { - tvar = OTP_MFG_SIG; /* set manufactur'ed signature */ - svc_flash_pgm_blk(OTP_MFG_ADDR, (uint32_t)((uint8_t *)&tvar), OTP_MFG_SIG_LEN); - tvar = 0x00; /* set OTP lock */ - if (svc_flash_pgm_blk(OTP_BLK_LOCK(OTP_MFG_ADDR), (uint32_t)((uint8_t *)&tvar), 1)) { - ret_val = true; - } + /* check OTP lock state before updating */ + if (*(uint8_t *)OTP_BLK_LOCK(OTP_MFG_ADDR) == 0xFF) { + tvar = OTP_MFG_SIG; /* set manufactur'ed signature */ + svc_flash_pgm_blk(OTP_MFG_ADDR, (uint32_t)((uint8_t *)&tvar), + OTP_MFG_SIG_LEN); + tvar = 0x00; /* set OTP lock */ + if (svc_flash_pgm_blk(OTP_BLK_LOCK(OTP_MFG_ADDR), + (uint32_t)((uint8_t *)&tvar), 1)) { + ret_val = true; } + } #endif - return(ret_val); + return (ret_val); } const char *flash_getModel(void) { #ifndef EMULATOR - if (*((uint8_t*)OTP_MODEL_ADDR) == 0xFF) - return NULL; - return (char*)OTP_MODEL_ADDR; +#ifdef DEBUG_ON + return "K1-14AM"; // return a model number for debugger builds +#endif + + if (*((uint8_t *)OTP_MODEL_ADDR) == 0xFF) return NULL; + + return (char *)OTP_MODEL_ADDR; #else - // TODO: actually make this settable in the emulator - return "K1-14AM"; + // TODO: actually make this settable in the emulator + return "K1-14AM"; #endif } bool flash_setModel(const char (*model)[MODEL_STR_SIZE]) { #ifndef EMULATOR - // Check OTP lock state before updating - if (*(uint8_t*)OTP_BLK_LOCK(OTP_MODEL_ADDR) != 0xFF) - return false; + // Check OTP lock state before updating + if (*(uint8_t *)OTP_BLK_LOCK(OTP_MODEL_ADDR) != 0xFF) return false; - svc_flash_pgm_blk(OTP_MODEL_ADDR, (uint32_t)((uint8_t*)model), sizeof(*model)); - uint8_t lock = 0x00; - bool ret = svc_flash_pgm_blk(OTP_BLK_LOCK(OTP_MODEL_ADDR), (uint32_t)&lock, sizeof(lock)); - return ret; + svc_flash_pgm_blk(OTP_MODEL_ADDR, (uint32_t)((uint8_t *)model), + sizeof(*model)); + uint8_t lock = 0x00; + bool ret = svc_flash_pgm_blk(OTP_BLK_LOCK(OTP_MODEL_ADDR), (uint32_t)&lock, + sizeof(lock)); + return ret; #else - return true; + return true; #endif } const char *flash_programModel(void) { - const char *ret = flash_getModel(); - if (ret) - return ret; + const char *ret = flash_getModel(); + if (ret) return ret; - switch (get_bootloaderKind()) { + switch (get_bootloaderKind()) { case BLK_v1_1_0: case BLK_v2_0_0: - return "No Model"; + case BLK_v2_1_0: + return "No Model"; case BLK_UNKNOWN: - return "Unknown"; + return "Unknown"; case BLK_v1_0_0: case BLK_v1_0_1: case BLK_v1_0_2: @@ -293,26 +292,24 @@ const char *flash_programModel(void) { case BLK_v1_0_3_sig: case BLK_v1_0_3_elf: { #define MODEL_ENTRY_KK(STRING, ENUM) \ - static const char model[MODEL_STR_SIZE] = (STRING); + static const char model[MODEL_STR_SIZE] = (STRING); #include "keepkey/board/models.def" - if (!is_mfg_mode()) - (void)flash_setModel(&model); - return model; + if (!is_mfg_mode()) (void)flash_setModel(&model); + return model; } case BLK_v1_0_4: { #define MODEL_ENTRY_SALT(STRING, ENUM) \ - static const char model[MODEL_STR_SIZE] = (STRING); + static const char model[MODEL_STR_SIZE] = (STRING); #include "keepkey/board/models.def" - if (!is_mfg_mode()) - (void)flash_setModel(&model); - return model; - } + if (!is_mfg_mode()) (void)flash_setModel(&model); + return model; } + } #ifdef DEBUG_ON - __builtin_unreachable(); + __builtin_unreachable(); #else - return "Unknown"; + return "Unknown"; #endif } @@ -341,7 +338,6 @@ void flash_collectHWEntropy(bool privileged) { #endif } -void flash_readHWEntropy(uint8_t *buff, size_t size) -{ - memcpy(buff, HW_ENTROPY_DATA, MIN(sizeof(HW_ENTROPY_DATA), size)); +void flash_readHWEntropy(uint8_t *buff, size_t size) { + memcpy(buff, HW_ENTROPY_DATA, MIN(sizeof(HW_ENTROPY_DATA), size)); } diff --git a/lib/board/keepkey_leds.c b/lib/board/keepkey_leds.c index 0c42fded8..c7c21ee86 100644 --- a/lib/board/keepkey_leds.c +++ b/lib/board/keepkey_leds.c @@ -17,19 +17,16 @@ * along with this library. If not, see . */ - #include #include "keepkey/board/keepkey_leds.h" #include "keepkey/board/pin.h" - #ifndef EMULATOR -static const Pin GREEN_LED = { GPIOC, GPIO14 }; -static const Pin RED_LED = { GPIOC, GPIO15 }; +static const Pin GREEN_LED = {GPIOC, GPIO14}; +static const Pin RED_LED = {GPIOC, GPIO15}; #endif - /* * keepkey_leds_init() - Initialize gpios for LEDs * @@ -38,14 +35,13 @@ static const Pin RED_LED = { GPIOC, GPIO15 }; * OUTPUT * none */ -void keepkey_leds_init(void) -{ +void keepkey_leds_init(void) { #ifndef EMULATOR - pin_init_output(&GREEN_LED, PUSH_PULL_MODE, NO_PULL_MODE); - pin_init_output(&RED_LED, PUSH_PULL_MODE, NO_PULL_MODE); + pin_init_output(&GREEN_LED, PUSH_PULL_MODE, NO_PULL_MODE); + pin_init_output(&RED_LED, PUSH_PULL_MODE, NO_PULL_MODE); - led_func(CLR_GREEN_LED); - led_func(CLR_RED_LED); + led_func(CLR_GREEN_LED); + led_func(CLR_RED_LED); #endif } @@ -57,38 +53,36 @@ void keepkey_leds_init(void) * OUTPUT * none */ -void led_func(LedAction act) -{ +void led_func(LedAction act) { #ifndef EMULATOR - switch(act) - { - case CLR_GREEN_LED: - SET_PIN(GREEN_LED); - break; + switch (act) { + case CLR_GREEN_LED: + SET_PIN(GREEN_LED); + break; - case SET_GREEN_LED: - CLEAR_PIN(GREEN_LED); - break; + case SET_GREEN_LED: + CLEAR_PIN(GREEN_LED); + break; - case TGL_GREEN_LED: - TOGGLE_PIN(GREEN_LED); - break; + case TGL_GREEN_LED: + TOGGLE_PIN(GREEN_LED); + break; - case CLR_RED_LED: - SET_PIN(RED_LED); - break; + case CLR_RED_LED: + SET_PIN(RED_LED); + break; - case SET_RED_LED: - CLEAR_PIN(RED_LED); - break; + case SET_RED_LED: + CLEAR_PIN(RED_LED); + break; - case TGL_RED_LED: - TOGGLE_PIN(RED_LED); - break; + case TGL_RED_LED: + TOGGLE_PIN(RED_LED); + break; - default: - /* No action */ - break; - } + default: + /* No action */ + break; + } #endif } diff --git a/lib/board/keepkey_usart.c b/lib/board/keepkey_usart.c index 31f014f9c..0bf0332b2 100644 --- a/lib/board/keepkey_usart.c +++ b/lib/board/keepkey_usart.c @@ -17,11 +17,10 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include -# include +#include +#include +#include #endif #include "keepkey/board/timer.h" @@ -30,7 +29,6 @@ #include #include - /* * put_console_char() - Display a character on serial debug port * @@ -40,29 +38,25 @@ * true/false status */ #ifdef USART_DEBUG_ON -static bool put_console_char(int8_t c) -{ +static bool put_console_char(int8_t c) { #ifndef EMULATOR - int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ - bool ret_stat = false; - - do - { - /* check Tx register ready transmissiion */ - if(USART_SR(USART3_BASE) & USART_SR_TXE) - { - USART_DR(USART3_BASE) = c; - ret_stat = true; - break; - } - - delay_ms(1); /* 1 ms sampling */ + int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ + bool ret_stat = false; + + do { + /* check Tx register ready transmissiion */ + if (USART_SR(USART3_BASE) & USART_SR_TXE) { + USART_DR(USART3_BASE) = c; + ret_stat = true; + break; } - while(--timeout_cnt); - return(ret_stat); + delay_ms(1); /* 1 ms sampling */ + } while (--timeout_cnt); + + return (ret_stat); #else - return false; + return false; #endif } @@ -74,34 +68,29 @@ static bool put_console_char(int8_t c) * OUTPUT * true/false update status */ -static bool get_console_input(char *read_char) -{ +static bool get_console_input(char *read_char) { #ifndef EMULATOR - int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ - bool ret_stat = false; - - do - { - /* check Rx register ready for read*/ - if(USART_SR(USART3_BASE) & USART_SR_RXNE) - { - /* data received */ - *read_char = USART_DR(USART3_BASE); - ret_stat = true; - break; - } - - delay_ms(1); /* 1 ms sampling */ + int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ + bool ret_stat = false; + + do { + /* check Rx register ready for read*/ + if (USART_SR(USART3_BASE) & USART_SR_RXNE) { + /* data received */ + *read_char = USART_DR(USART3_BASE); + ret_stat = true; + break; } - while(--timeout_cnt); - return (ret_stat); + delay_ms(1); /* 1 ms sampling */ + } while (--timeout_cnt); + + return (ret_stat); #else - return false; + return false; #endif } - /* * display_debug_string() - Dump string to debug console * @@ -110,13 +99,10 @@ static bool get_console_input(char *read_char) * OUTPUT * none */ -static void display_debug_string(char *str) -{ - do - { - put_console_char(*str); - } - while(*(str++)); +static void display_debug_string(char *str) { + do { + put_console_char(*str); + } while (*(str++)); } /* @@ -127,46 +113,45 @@ static void display_debug_string(char *str) * OUTPUT * none */ -void usart_init(void) -{ +void usart_init(void) { #ifndef EMULATOR - /* Setup PB10 for USART-TX */ - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10); - gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO10); + /* Setup PB10 for USART-TX */ + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10); + gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO10); - /* Setup PB11 for USART-RX */ - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11); - gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO11); + /* Setup PB11 for USART-RX */ + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11); + gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO11); - /* Set PB10 and PB11 to USART3 alternate aunction */ - gpio_set_af(GPIOB, 7, GPIO10); - gpio_set_af(GPIOB, 7, GPIO11); + /* Set PB10 and PB11 to USART3 alternate aunction */ + gpio_set_af(GPIOB, 7, GPIO10); + gpio_set_af(GPIOB, 7, GPIO11); - /*enable USART3 clock source */ - rcc_periph_clock_enable(RCC_USART3); + /*enable USART3 clock source */ + rcc_periph_clock_enable(RCC_USART3); - /* disable USART3 before you are allow to write to USART3 registers */ - usart_disable(USART3_BASE) ; + /* disable USART3 before you are allow to write to USART3 registers */ + usart_disable(USART3_BASE); - /* set Word Length */ - usart_set_databits(USART3_BASE, 8); + /* set Word Length */ + usart_set_databits(USART3_BASE, 8); - /* Set Transmit/Receive mode */ - usart_set_mode(USART3_BASE, USART_CR1_RE | USART_CR1_TE); + /* Set Transmit/Receive mode */ + usart_set_mode(USART3_BASE, USART_CR1_RE | USART_CR1_TE); - usart_set_stopbits(USART3_BASE, USART_CR2_STOPBITS_1); + usart_set_stopbits(USART3_BASE, USART_CR2_STOPBITS_1); - /* disable parity */ - usart_set_parity(USART3_BASE, 0); /* USART_CR1_PCE */ + /* disable parity */ + usart_set_parity(USART3_BASE, 0); /* USART_CR1_PCE */ - usart_set_flow_control(USART3_BASE, 0); + usart_set_flow_control(USART3_BASE, 0); - usart_set_baudrate(USART3_BASE, 115200); + usart_set_baudrate(USART3_BASE, 115200); - /* enable USART */ - usart_enable(USART3_BASE); + /* enable USART */ + usart_enable(USART3_BASE); - /* Note : RDR= Read data, TDR=Transmit data */ + /* Note : RDR= Read data, TDR=Transmit data */ #endif } @@ -179,24 +164,21 @@ void usart_init(void) * none */ #ifndef EMULATOR -void dbg_print(const char *out_str, ...) -{ - char str[LARGE_DEBUG_BUF]; - va_list arg; - - va_start(arg, out_str); - vsnprintf(str, LARGE_DEBUG_BUF, out_str, arg); - - if(strlen(str) + 1 <= LARGE_DEBUG_BUF) - { - display_debug_string(str); - } - else - { - snprintf(str, LARGE_DEBUG_BUF, "error: Debug string(%d) exceeds buffer size(%d)\n\r", - strlen(str) + 1, LARGE_DEBUG_BUF); - display_debug_string(str); - } +void dbg_print(const char *out_str, ...) { + char str[LARGE_DEBUG_BUF]; + va_list arg; + + va_start(arg, out_str); + vsnprintf(str, LARGE_DEBUG_BUF, out_str, arg); + + if (strlen(str) + 1 <= LARGE_DEBUG_BUF) { + display_debug_string(str); + } else { + snprintf(str, LARGE_DEBUG_BUF, + "error: Debug string(%d) exceeds buffer size(%d)\n\r", + strlen(str) + 1, LARGE_DEBUG_BUF); + display_debug_string(str); + } } #endif @@ -208,64 +190,58 @@ void dbg_print(const char *out_str, ...) * OUTPUT * none */ -void dbg_trigger(uint32_t color) -{ +void dbg_trigger(uint32_t color) { #ifndef EMULATOR - switch(color) - { - case 1: - led_func(CLR_RED_LED); - led_func(SET_RED_LED); - break; - - case 2: - led_func(CLR_GREEN_LED); - led_func(SET_GREEN_LED); - } + switch (color) { + case 1: + led_func(CLR_RED_LED); + led_func(SET_RED_LED); + break; + + case 2: + led_func(CLR_GREEN_LED); + led_func(SET_GREEN_LED); + } #else - switch (color) - { - case 1: - printf("dbg trigger 1\n"); - break; - case 2: - printf("dbg trigger 2\n"); - break; - } + switch (color) { + case 1: + printf("dbg trigger 1\n"); + break; + case 2: + printf("dbg trigger 2\n"); + break; + } #endif } /* * read_console() - Read debug console port for user input - * + * * INPUT * none * OUTPUT * character read from console */ -char read_console(void) -{ +char read_console(void) { #ifndef EMULATOR - char char_read = 0, str_dbg[SMALL_DEBUG_BUF]; - - while(1) - { - if(get_console_input(&char_read)) - { - /* print for debug only */ - snprintf(str_dbg, SMALL_DEBUG_BUF, "%c\n\r", char_read); - display_debug_string(str_dbg); - } + char char_read = 0, str_dbg[SMALL_DEBUG_BUF]; + + while (1) { + if (get_console_input(&char_read)) { + /* print for debug only */ + snprintf(str_dbg, SMALL_DEBUG_BUF, "%c\n\r", char_read); + display_debug_string(str_dbg); } + } - return(char_read); + return (char_read); #else - return '\0'; + return '\0'; #endif } -#else // USART_DEBUG_ON +#else // USART_DEBUG_ON #ifndef EMULATOR -void dbg_print(const char *pStr, ...) {(void)pStr;} +void dbg_print(const char *pStr, ...) { (void)pStr; } #endif void usart_init(void) {} #endif diff --git a/lib/board/layout.c b/lib/board/layout.c index 0fae5e14f..00cc11466 100644 --- a/lib/board/layout.c +++ b/lib/board/layout.c @@ -34,13 +34,15 @@ #include #include -static AnimationQueue active_queue = { NULL, 0 }; -static AnimationQueue free_queue = { NULL, 0 }; -static Animation animations[ MAX_ANIMATIONS ]; +static AnimationQueue active_queue = {NULL, 0}; +static AnimationQueue free_queue = {NULL, 0}; +static Animation animations[MAX_ANIMATIONS]; static Canvas *canvas = NULL; static volatile bool animate_flag = false; static leaving_handler_t leaving_handler; +extern bool constant_power; + /* * layout_home_helper() - Splash home screen helper * @@ -49,23 +51,19 @@ static leaving_handler_t leaving_handler; * OUTPUT * none */ -static void layout_home_helper(bool reversed) -{ - layout_clear(); +static void layout_home_helper(bool reversed) { + layout_clear(); - const VariantAnimation *logo; - logo = variant_getLogo(reversed); + const VariantAnimation *logo; + logo = variant_getLogo(reversed); - layout_add_animation( - &layout_animate_images, - (void *)logo, - get_image_animation_duration(logo)); + layout_add_animation(&layout_animate_images, (void *)logo, + get_image_animation_duration(logo)); - while(is_animating()) - { - animate(); - display_refresh(); - } + while (is_animating()) { + animate(); + display_refresh(); + } } /* @@ -76,14 +74,14 @@ static void layout_home_helper(bool reversed) * OUTPUT * none */ -static void layout_animate_callback(void *context) -{ - (void)context; - animate_flag = true; +static void layout_animate_callback(void *context) { + (void)context; + animate_flag = true; } /* - * layout_remove_animation() - Remove animation node that contains the callback function from the queue + * layout_remove_animation() - Remove animation node that contains the callback + * function from the queue * * INPUT * - callback: animation callback function to remove node for @@ -91,14 +89,12 @@ static void layout_animate_callback(void *context) * none */ #if defined(AGGRO_UNDEFINED_FN) -static void layout_remove_animation(AnimateCallback callback) -{ - Animation *animation = animation_queue_get(&active_queue, callback); +static void layout_remove_animation(AnimateCallback callback) { + Animation *animation = animation_queue_get(&active_queue, callback); - if(animation != NULL) - { - animation_queue_push(&free_queue, animation); - } + if (animation != NULL) { + animation_queue_push(&free_queue, animation); + } } #endif @@ -110,9 +106,8 @@ static void layout_remove_animation(AnimateCallback callback) * OUTPUT * node pointed to by head pointer */ -static Animation *animation_queue_peek(AnimationQueue *queue) -{ - return queue->head; +static Animation *animation_queue_peek(AnimationQueue *queue) { + return queue->head; } /* @@ -123,22 +118,17 @@ static Animation *animation_queue_peek(AnimationQueue *queue) * OUTPUT * none */ -static void animation_queue_push(AnimationQueue *queue, Animation *node) -{ - if(queue->head != NULL) - { - node->next = queue->head; - } - else - { - node->next = NULL; - } +static void animation_queue_push(AnimationQueue *queue, Animation *node) { + if (queue->head != NULL) { + node->next = queue->head; + } else { + node->next = NULL; + } - queue->head = node; - queue->size += 1; + queue->head = node; + queue->size += 1; } - /* * animation_queue_pop() - Pop a node from animation queue * @@ -147,17 +137,15 @@ static void animation_queue_push(AnimationQueue *queue, Animation *node) * OUTPUT * pointer to a node from the queue */ -static Animation *animation_queue_pop(AnimationQueue *queue) -{ - Animation *animation = queue->head; +static Animation *animation_queue_pop(AnimationQueue *queue) { + Animation *animation = queue->head; - if(animation != NULL) - { - queue->head = animation->next; - queue->size -= 1; - } + if (animation != NULL) { + queue->head = animation->next; + queue->size -= 1; + } - return(animation); + return (animation); } /* @@ -169,47 +157,39 @@ static Animation *animation_queue_pop(AnimationQueue *queue) * OUTPUT * pointer to Animation node */ -static Animation *animation_queue_get(AnimationQueue *queue, AnimateCallback callback) -{ - Animation *current = queue->head; - Animation *result = NULL; - - if(current != NULL) - { - if(current->animate_callback == callback) - { - result = current; - queue->head = current->next; - } - else - { - Animation *previous = current; - current = current->next; - - while((current != NULL) && (result == NULL)) - { - // Found the node! - if(current->animate_callback == callback) - { - result = current; - previous->next = current->next; - result->next = NULL; - } - - previous = current; - current = current->next; - } +static Animation *animation_queue_get(AnimationQueue *queue, + AnimateCallback callback) { + Animation *current = queue->head; + Animation *result = NULL; + + if (current != NULL) { + if (current->animate_callback == callback) { + result = current; + queue->head = current->next; + } else { + Animation *previous = current; + current = current->next; + + while ((current != NULL) && (result == NULL)) { + // Found the node! + if (current->animate_callback == callback) { + result = current; + previous->next = current->next; + result->next = NULL; } - } - if(result != NULL) - { - queue->size -= 1; + previous = current; + current = current->next; + } } + } - return(result); -} + if (result != NULL) { + queue->size -= 1; + } + return (result); +} /* * layout_init() - Initialize layout subsystem @@ -219,19 +199,18 @@ static Animation *animation_queue_get(AnimationQueue *queue, AnimateCallback cal * OUTPUT * none */ -void layout_init(Canvas *new_canvas) -{ - canvas = new_canvas; +void layout_init(Canvas *new_canvas) { + canvas = new_canvas; - int i; + int i; - for(i = 0; i < MAX_ANIMATIONS; i++) - { - animation_queue_push(&free_queue, &animations[ i ]); - } + for (i = 0; i < MAX_ANIMATIONS; i++) { + animation_queue_push(&free_queue, &animations[i]); + } - // Start the animation timer. - post_periodic(&layout_animate_callback, NULL, ANIMATION_PERIOD, ANIMATION_PERIOD); + // Start the animation timer. + post_periodic(&layout_animate_callback, NULL, ANIMATION_PERIOD, + ANIMATION_PERIOD); } /* @@ -242,10 +221,7 @@ void layout_init(Canvas *new_canvas) * OUTPUT * pointer to canvas */ -Canvas *layout_get_canvas(void) -{ - return canvas; -} +Canvas *layout_get_canvas(void) { return canvas; } /* * call_leaving_handler() - Call leaving handler @@ -255,22 +231,18 @@ Canvas *layout_get_canvas(void) * OUTPUT * none */ -void call_leaving_handler(void) -{ - if(leaving_handler) - { - (*leaving_handler)(); - } +void call_leaving_handler(void) { + if (leaving_handler) { + (*leaving_handler)(); + } } void kk_strupr(char *str) { - for ( ; *str; str++) - *str = toupper(*str); + for (; *str; str++) *str = toupper(*str); } void kk_strlwr(char *str) { - for ( ; *str; str++) - *str = tolower(*str); + for (; *str; str++) *str = tolower(*str); } /* @@ -284,7 +256,47 @@ void kk_strlwr(char *str) { * none */ void layout_standard_notification(const char *str1, const char *str2, - NotificationType type) + NotificationType type) { + call_leaving_handler(); + layout_clear(); + + DrawableParams sp; + const Font *title_font = get_title_font(); + const Font *body_font = get_body_font(); + const uint32_t body_line_count = calc_str_line(body_font, str2, BODY_WIDTH); + + /* Determine vertical alignment and body width */ + sp.y = TOP_MARGIN; + + if (body_line_count == ONE_LINE) { + sp.y = TOP_MARGIN_FOR_ONE_LINE; + } else if (body_line_count == TWO_LINES) { + sp.y = TOP_MARGIN_FOR_TWO_LINES; + } + + /* Format Title */ + char upper_str1[TITLE_CHAR_MAX]; + strlcpy(upper_str1, str1, TITLE_CHAR_MAX); + kk_strupr(upper_str1); + + /* Title */ + sp.x = LEFT_MARGIN; + sp.color = TITLE_COLOR; + draw_string(canvas, title_font, upper_str1, &sp, TITLE_WIDTH, + font_height(title_font)); + + /* Body */ + sp.y += font_height(body_font) + BODY_TOP_MARGIN; + sp.x = LEFT_MARGIN; + sp.color = BODY_COLOR; + draw_string(canvas, body_font, str2, &sp, BODY_WIDTH, + font_height(body_font) + BODY_FONT_LINE_PADDING); + + layout_notification_icon(type, &sp); +} + +void layout_constant_power_notification(const char *str1, const char *str2, + NotificationType type) { call_leaving_handler(); layout_clear(); @@ -312,13 +324,13 @@ void layout_standard_notification(const char *str1, const char *str2, kk_strupr(upper_str1); /* Title */ - sp.x = LEFT_MARGIN; + sp.x = 128 + LEFT_MARGIN; sp.color = TITLE_COLOR; draw_string(canvas, title_font, upper_str1, &sp, TITLE_WIDTH, font_height(title_font)); /* Body */ sp.y += font_height(body_font) + BODY_TOP_MARGIN; - sp.x = LEFT_MARGIN; + sp.x = 128 + LEFT_MARGIN; sp.color = BODY_COLOR; draw_string(canvas, body_font, str2, &sp, BODY_WIDTH, font_height(body_font) + BODY_FONT_LINE_PADDING); @@ -335,49 +347,44 @@ void layout_standard_notification(const char *str1, const char *str2, * OUTPUT * none */ -void layout_notification_icon(NotificationType type, DrawableParams *sp) -{ - - switch(type) - { - - case NOTIFICATION_REQUEST: - case NOTIFICATION_REQUEST_NO_ANIMATION: - draw_bitmap_mono_rle(canvas, get_confirm_icon_frame(), false); - break; - - case NOTIFICATION_CONFIRM_ANIMATION: { - const VariantAnimation *anim = get_confirming_animation(); - - layout_add_animation( - &layout_animate_images, - (void *)anim, - get_image_animation_duration(anim)); - break; - } - - case NOTIFICATION_CONFIRMED: - draw_bitmap_mono_rle(canvas, get_confirmed_frame(), false); - break; - - case NOTIFICATION_UNPLUG: - sp->x = 208; - sp->y = 21; - draw_bitmap_mono_rle(canvas, get_unplug_frame(), false); - break; - - case NOTIFICATION_LOGO: { - const Image *image = variant_keepkey.logo->frames[variant_keepkey.logo->count - 1].image; - const AnimationFrame frame = { 190, 9, 0, 100, image }; - draw_bitmap_mono_rle(canvas, &frame, false); - break; - } +void layout_notification_icon(NotificationType type, DrawableParams *sp) { + switch (type) { + case NOTIFICATION_REQUEST: + case NOTIFICATION_REQUEST_NO_ANIMATION: + draw_bitmap_mono_rle(canvas, get_confirm_icon_frame(), false); + break; + + case NOTIFICATION_CONFIRM_ANIMATION: { + const VariantAnimation *anim = get_confirming_animation(); + + layout_add_animation(&layout_animate_images, (void *)anim, + get_image_animation_duration(anim)); + break; + } - case NOTIFICATION_INFO: - default: - /* no action requires */ - break; + case NOTIFICATION_CONFIRMED: + draw_bitmap_mono_rle(canvas, get_confirmed_frame(), false); + break; + + case NOTIFICATION_UNPLUG: + sp->x = 208; + sp->y = 21; + draw_bitmap_mono_rle(canvas, get_unplug_frame(), false); + break; + + case NOTIFICATION_LOGO: { + const Image *image = + variant_keepkey.logo->frames[variant_keepkey.logo->count - 1].image; + const AnimationFrame frame = {190, 9, 0, 100, image}; + draw_bitmap_mono_rle(canvas, &frame, false); + break; } + + case NOTIFICATION_INFO: + default: + /* no action requires */ + break; + } } /* @@ -388,49 +395,48 @@ void layout_notification_icon(NotificationType type, DrawableParams *sp) * OUTPUT * none */ -void layout_warning(const char *str) -{ - call_leaving_handler(); - layout_clear(); +void layout_warning(const char *str) { + call_leaving_handler(); + layout_clear(); - const Font *font = get_body_font(); + const Font *font = get_body_font(); - /* Title */ - DrawableParams sp; - sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, str)) / 2; - sp.y = 50; - sp.color = TITLE_COLOR; - draw_string(canvas, font, str, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); + /* Title */ + DrawableParams sp; + sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, str)) / 2; + sp.y = 50; + sp.color = TITLE_COLOR; + draw_string(canvas, font, str, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); - const VariantAnimation *warning = get_warning_animation(); - layout_add_animation(&layout_animate_images, (void *)warning, 0); + const VariantAnimation *warning = get_warning_animation(); + layout_add_animation(&layout_animate_images, (void *)warning, 0); } /* - * layout_warning_static() - Display warning message on display without animation + * layout_warning_static() - Display warning message on display without + * animation * * INPUT * - prompt: string to display * OUTPUT * none */ -void layout_warning_static(const char *str) -{ - call_leaving_handler(); - layout_clear(); +void layout_warning_static(const char *str) { + call_leaving_handler(); + layout_clear(); - const Font *font = get_body_font(); + const Font *font = get_body_font(); - /* Title */ - DrawableParams sp; - sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, str)) / 2; - sp.y = 50; - sp.color = TITLE_COLOR; - draw_string(canvas, font, str, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); + /* Title */ + DrawableParams sp; + sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, str)) / 2; + sp.y = 50; + sp.color = TITLE_COLOR; + draw_string(canvas, font, str, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); - draw_bitmap_mono_rle(canvas, get_warning_frame(), false); + draw_bitmap_mono_rle(canvas, get_warning_frame(), false); - display_refresh(); + display_refresh(); } /* @@ -441,26 +447,26 @@ void layout_warning_static(const char *str) * OUTPUT * none */ -void layout_simple_message(const char *str) -{ - call_leaving_handler(); - layout_clear(); +void layout_simple_message(const char *str) { + call_leaving_handler(); + layout_clear(); - const Font *font = get_title_font(); + const Font *font = get_title_font(); - /* Format Message */ - char upper_str[TITLE_CHAR_MAX]; - strlcpy(upper_str, str, TITLE_CHAR_MAX); - kk_strupr(upper_str); + /* Format Message */ + char upper_str[TITLE_CHAR_MAX]; + strlcpy(upper_str, str, TITLE_CHAR_MAX); + kk_strupr(upper_str); - /* Draw Message */ - DrawableParams sp; - sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, upper_str)) / 2; - sp.y = (KEEPKEY_DISPLAY_HEIGHT / 2) - (font_height(font) / 2); - sp.color = TITLE_COLOR; - draw_string(canvas, font, upper_str, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); + /* Draw Message */ + DrawableParams sp; + sp.x = (KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, upper_str)) / 2; + sp.y = (KEEPKEY_DISPLAY_HEIGHT / 2) - (font_height(font) / 2); + sp.color = TITLE_COLOR; + draw_string(canvas, font, upper_str, &sp, KEEPKEY_DISPLAY_WIDTH, + font_height(font)); - display_refresh(); + display_refresh(); } /* @@ -473,25 +479,26 @@ void layout_simple_message(const char *str) * OUTPUT * none */ -void layout_version(int32_t major, int32_t minor, int32_t patch) -{ - char version_info[SMALL_STR_BUF]; +void layout_version(int32_t major, int32_t minor, int32_t patch) { + char version_info[SMALL_STR_BUF]; - call_leaving_handler(); + call_leaving_handler(); - const Font *font = get_body_font(); + const Font *font = get_body_font(); - snprintf(version_info, SMALL_STR_BUF, "v%lu.%lu.%lu", (unsigned long)major, - (unsigned long)minor, (unsigned long)patch); + snprintf(version_info, SMALL_STR_BUF, "v%lu.%lu.%lu", (unsigned long)major, + (unsigned long)minor, (unsigned long)patch); - /* Draw version information */ - DrawableParams sp; - sp.x = KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, version_info) - BODY_FONT_LINE_PADDING; - sp.y = KEEPKEY_DISPLAY_HEIGHT - font_height(font) - BODY_FONT_LINE_PADDING; - sp.color = 0x22; - draw_string(canvas, font, version_info, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); + /* Draw version information */ + DrawableParams sp; + sp.x = KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, version_info) - + BODY_FONT_LINE_PADDING; + sp.y = KEEPKEY_DISPLAY_HEIGHT - font_height(font) - BODY_FONT_LINE_PADDING; + sp.color = 0x22; + draw_string(canvas, font, version_info, &sp, KEEPKEY_DISPLAY_WIDTH, + font_height(font)); - display_refresh(); + display_refresh(); } /* @@ -502,10 +509,7 @@ void layout_version(int32_t major, int32_t minor, int32_t patch) * OUTPUT * none */ -void layout_home(void) -{ - layout_home_helper(false); -} +void layout_home(void) { layout_home_helper(false); } /* * layout_home_reversed() - Splash home screen in reverse @@ -515,10 +519,7 @@ void layout_home(void) * OUTPUT * none */ -void layout_home_reversed(void) -{ - layout_home_helper(true); -} +void layout_home_reversed(void) { layout_home_helper(true); } /* * animate() - Attempt to animate if there are animations in the queue @@ -528,35 +529,30 @@ void layout_home_reversed(void) * OUTPUT * none */ -void animate(void) -{ - if(animate_flag) - { - Animation *animation = animation_queue_peek(&active_queue); +void animate(void) { + if (animate_flag) { + Animation *animation = animation_queue_peek(&active_queue); - while(animation != NULL) - { - Animation *next = animation->next; + while (animation != NULL) { + Animation *next = animation->next; - animation->elapsed += ANIMATION_PERIOD; + animation->elapsed += ANIMATION_PERIOD; - animation->animate_callback( - animation->data, - animation->duration, - animation->elapsed); + animation->animate_callback(animation->data, animation->duration, + animation->elapsed); - if((animation->duration > 0) && (animation->elapsed >= animation->duration)) - { - animation_queue_push( - &free_queue, - animation_queue_get(&active_queue, animation->animate_callback)); - } + if ((animation->duration > 0) && + (animation->elapsed >= animation->duration)) { + animation_queue_push( + &free_queue, + animation_queue_get(&active_queue, animation->animate_callback)); + } - animation = next; - } - - animate_flag = false; + animation = next; } + + animate_flag = false; + } } /* @@ -567,16 +563,12 @@ void animate(void) * OUTPUT * true/false whether there are animations in the queue */ -bool is_animating(void) -{ - if(animation_queue_peek(&active_queue) == NULL) - { - return false; - } - else - { - return animate_flag; - } +bool is_animating(void) { + if (animation_queue_peek(&active_queue) == NULL) { + return false; + } else { + return animate_flag; + } } /* @@ -590,29 +582,33 @@ bool is_animating(void) * OUTPUT * none */ -void layout_animate_images(void *data, uint32_t duration, uint32_t elapsed) -{ - const VariantAnimation *animation = (const VariantAnimation *)data; +void layout_animate_images(void *data, uint32_t duration, uint32_t elapsed) { + const VariantAnimation *animation = (const VariantAnimation *)data; - bool looping = duration == 0; - int frameNum = get_image_animation_frame(animation, elapsed, looping); + bool looping = duration == 0; + int frameNum = get_image_animation_frame(animation, elapsed, looping); - if(frameNum != -1 && frameNum < animation->count) - { - draw_bitmap_mono_rle(canvas, &animation->frames[(frameNum+animation->count-1)%animation->count], true); - draw_bitmap_mono_rle(canvas, &animation->frames[frameNum], false); - } + if (frameNum != -1 && frameNum < animation->count) { + draw_bitmap_mono_rle( + canvas, + &animation + ->frames[(frameNum + animation->count - 1) % animation->count], + true); + draw_bitmap_mono_rle(canvas, &animation->frames[frameNum], false); + } } #if DEBUG_LINK void layout_debuglink_watermark(void) { - const Font *font = get_body_font(); - const char *watermark = "DEBUG_LINK"; - DrawableParams sp; - sp.x = KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, watermark) - BODY_FONT_LINE_PADDING; - sp.y = KEEPKEY_DISPLAY_HEIGHT - 1 * font_height(font); - sp.color = 0x22; - draw_string(canvas, font, watermark, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); + const Font *font = get_body_font(); + const char *watermark = "DEBUG_LINK"; + DrawableParams sp; + sp.x = KEEPKEY_DISPLAY_WIDTH - calc_str_width(font, watermark) - + BODY_FONT_LINE_PADDING; + sp.y = KEEPKEY_DISPLAY_HEIGHT - 1 * font_height(font); + sp.color = 0x22; + draw_string(canvas, font, watermark, &sp, KEEPKEY_DISPLAY_WIDTH, + font_height(font)); } #endif @@ -624,14 +620,13 @@ void layout_debuglink_watermark(void) { * OUTPUT * none */ -void layout_clear(void) -{ - layout_clear_animations(); +void layout_clear(void) { + layout_clear_animations(); - layout_clear_static(); + layout_clear_static(); #if DEBUG_LINK - layout_debuglink_watermark(); + layout_debuglink_watermark(); #endif } @@ -648,14 +643,9 @@ void layout_clear_static(void) if (!canvas) return; - BoxDrawableParams bp; - bp.width = canvas->width; - bp.height = canvas->height; - bp.base.x = 0; - bp.base.y = 0; - bp.base.color = 0x00; + display_constant_power(false); - draw_box(canvas, &bp); + memset(canvas->buffer, 0, canvas->width * canvas->height); } /* @@ -666,10 +656,7 @@ void layout_clear_static(void) * OUTPUT * none */ -void force_animation_start(void) -{ - animate_flag = true; -} +void force_animation_start(void) { animate_flag = true; } /* * animating_progress_handler() - Animate storage update progress @@ -679,72 +666,72 @@ void force_animation_start(void) * OUTPUT * none */ -void animating_progress_handler(const char *desc, int permil) -{ - if (!canvas) - return; - - call_leaving_handler(); - layout_clear(); - - permil = permil >= 1000 ? 1000 : permil; - permil = permil <= 0 ? 0 : permil; - - const Font *font = get_body_font(); - - /* Draw Message */ - const uint32_t body_line_count = calc_str_line(font, desc, BODY_WIDTH); - DrawableParams sp; - sp.x = LEFT_MARGIN; - sp.y = (KEEPKEY_DISPLAY_HEIGHT / 2) - (body_line_count * font_height(font) / 2); - sp.color = TITLE_COLOR; - draw_string(canvas, font, desc, &sp, KEEPKEY_DISPLAY_WIDTH, font_height(font)); - - uint32_t width = 256 - 2 * LEFT_MARGIN; - uint32_t finished_width = (width * permil) / 1000; - uint32_t height = 6; - uint32_t x = LEFT_MARGIN; - uint32_t y = 48; - - // Outline - BoxDrawableParams bp; - bp.width = width; - bp.height = height; - bp.base.x = x; - bp.base.y = y; - bp.base.color = 0xcc; +void animating_progress_handler(const char *desc, int permil) { + if (!canvas) return; + + call_leaving_handler(); + layout_clear(); + + permil = permil >= 1000 ? 1000 : permil; + permil = permil <= 0 ? 0 : permil; + + const Font *font = get_body_font(); + + /* Draw Message */ + const uint32_t body_line_count = calc_str_line(font, desc, BODY_WIDTH); + DrawableParams sp; + sp.x = LEFT_MARGIN; + sp.y = + (KEEPKEY_DISPLAY_HEIGHT / 2) - (body_line_count * font_height(font) / 2); + sp.color = TITLE_COLOR; + draw_string(canvas, font, desc, &sp, KEEPKEY_DISPLAY_WIDTH, + font_height(font)); + + uint32_t width = 256 - 2 * LEFT_MARGIN; + uint32_t finished_width = (width * permil) / 1000; + uint32_t height = 6; + uint32_t x = LEFT_MARGIN; + uint32_t y = 48; + + // Outline + BoxDrawableParams bp; + bp.width = width; + bp.height = height; + bp.base.x = x; + bp.base.y = y; + bp.base.color = 0xcc; + draw_box(canvas, &bp); + + // Finished + bp.width = finished_width >= 1 ? finished_width - 1 : 0; + bp.height = height - 2; + bp.base.x = x + 1; + bp.base.y = y + 1; + bp.base.color = 0xff; + if (finished_width > 1) { draw_box(canvas, &bp); + } + + // Not Finished + uint32_t remaining = width - finished_width; + bp.width = remaining >= 2 ? remaining - 2 : 0; + bp.height = height - 2; + bp.base.x = x + finished_width + 1; + bp.base.y = y + 1; + bp.base.color = 0x00; + if (width > finished_width + 2) { + draw_box(canvas, &bp); + } - // Finished - bp.width = finished_width >= 1 ? finished_width - 1 : 0; - bp.height = height - 2; - bp.base.x = x + 1; - bp.base.y = y + 1; - bp.base.color = 0xff; - if (finished_width > 1) { - draw_box(canvas, &bp); - } - - // Not Finished - uint32_t remaining = width - finished_width; - bp.width = remaining >= 2 ? remaining - 2 : 0; - bp.height = height - 2; - bp.base.x = x + finished_width + 1; - bp.base.y = y + 1; - bp.base.color = 0x00; - if (width > finished_width + 2) { - draw_box(canvas, &bp); - } - - display_refresh(); + display_refresh(); } void layoutProgress(const char *desc, int permil) { - animating_progress_handler(desc, permil); + animating_progress_handler(desc, permil); } void layoutProgressSwipe(const char *desc, int permil) { - animating_progress_handler(desc, permil); + animating_progress_handler(desc, permil); } /* @@ -757,20 +744,19 @@ void layoutProgressSwipe(const char *desc, int permil) { * OUTPUT * none */ -void layout_add_animation(AnimateCallback callback, void *data, uint32_t duration) -{ - Animation *animation = animation_queue_get(&active_queue, callback); +void layout_add_animation(AnimateCallback callback, void *data, + uint32_t duration) { + Animation *animation = animation_queue_get(&active_queue, callback); - if(animation == NULL) - { - animation = animation_queue_pop(&free_queue); - } + if (animation == NULL) { + animation = animation_queue_pop(&free_queue); + } - animation->data = data; - animation->duration = duration; - animation->elapsed = 0; - animation->animate_callback = callback; - animation_queue_push(&active_queue, animation); + animation->data = data; + animation->duration = duration; + animation->elapsed = 0; + animation->animate_callback = callback; + animation_queue_push(&active_queue, animation); } /* @@ -781,15 +767,13 @@ void layout_add_animation(AnimateCallback callback, void *data, uint32_t duratio * OUTPUT * none */ -void layout_clear_animations(void) -{ - Animation *animation = animation_queue_pop(&active_queue); +void layout_clear_animations(void) { + Animation *animation = animation_queue_pop(&active_queue); - while(animation != NULL) - { - animation_queue_push(&free_queue, animation); - animation = animation_queue_pop(&active_queue); - } + while (animation != NULL) { + animation_queue_push(&free_queue, animation); + animation = animation_queue_pop(&active_queue); + } } /* @@ -800,7 +784,6 @@ void layout_clear_animations(void) * OUTPUT * none */ -void set_leaving_handler(leaving_handler_t leaving_func) -{ - leaving_handler = leaving_func; +void set_leaving_handler(leaving_handler_t leaving_func) { + leaving_handler = leaving_func; } diff --git a/lib/board/memcmp_s.c b/lib/board/memcmp_s.c index 7c2587b6a..336762383 100644 --- a/lib/board/memcmp_s.c +++ b/lib/board/memcmp_s.c @@ -19,72 +19,68 @@ /// compiler to assume the underlying fuction might have changed them. int memcmp_cst(void *lhs, void *rhs, size_t len); #else -# warning "memcmp_s is not guaranteed to be constant-time on this architecture" -# define memcmp_cst(lhs, rhs, len) memcmp((lhs), (rhs), (len)) +#warning "memcmp_s is not guaranteed to be constant-time on this architecture" +#define memcmp_cst(lhs, rhs, len) memcmp((lhs), (rhs), (len)) #endif void asc_fill(char *permute, size_t len); #ifdef EMULATOR -void asc_fill(char *permute, size_t len) -{ - for (size_t i = 0; i != len; i++) { - permute[i] = i; - } +void asc_fill(char *permute, size_t len) { + for (size_t i = 0; i != len; i++) { + permute[i] = i; + } } #endif -int memcmp_s(const void *lhs, const void *rhs, size_t len) -{ - if (len < 32 || len > 255) { - // Setting the floor on length to 32 is a simple way to guarantee that - // all the decoy buffers we end up will never compare equal with either - // lhs/rhs, since the chances of randomly generating the same 32 byte - // sequence twice is astronomically small... you're just as likely to - // guess Satoshi's private keys. - assert(false && "unsupported memcmp_s length"); - abort(); - } +int memcmp_s(const void *lhs, const void *rhs, size_t len) { + if (len < 32 || len > 255) { + // Setting the floor on length to 32 is a simple way to guarantee that + // all the decoy buffers we end up will never compare equal with either + // lhs/rhs, since the chances of randomly generating the same 32 byte + // sequence twice is astronomically small... you're just as likely to + // guess Satoshi's private keys. + assert(false && "unsupported memcmp_s length"); + abort(); + } - static uint8_t decoys[DECOY_COUNT][255]; - random_buffer(&decoys[0][0], sizeof(decoys)); + static uint8_t decoys[DECOY_COUNT][255]; + random_buffer(&decoys[0][0], sizeof(decoys)); - static void *permuted[DECOY_COUNT + 2]; - for (size_t i = 0; i != DECOY_COUNT; i++) { - permuted[i] = &decoys[i]; - } - permuted[DECOY_COUNT] = (void*)lhs; - permuted[DECOY_COUNT + 1] = (void*)rhs; + static void *permuted[DECOY_COUNT + 2]; + for (size_t i = 0; i != DECOY_COUNT; i++) { + permuted[i] = &decoys[i]; + } + permuted[DECOY_COUNT] = (void *)lhs; + permuted[DECOY_COUNT + 1] = (void *)rhs; - static uint8_t permute[DECOY_COUNT + 2]; - asc_fill((char*)permute, DECOY_COUNT + 2); - random_permute_char((char*)permute, DECOY_COUNT + 2); + static uint8_t permute[DECOY_COUNT + 2]; + asc_fill((char *)permute, DECOY_COUNT + 2); + random_permute_char((char *)permute, DECOY_COUNT + 2); - // Compare every pair of buffers once, and count how many match. We should - // get exactly one match from the comparison of lhs with rhs, assuming they - // matched to begin with. Use the permutation array as a random indirection - // so that an attacker measuring power draw can't know which pair of arrays - // we're actually comparing at any given moment. + // Compare every pair of buffers once, and count how many match. We should + // get exactly one match from the comparison of lhs with rhs, assuming they + // matched to begin with. Use the permutation array as a random indirection + // so that an attacker measuring power draw can't know which pair of arrays + // we're actually comparing at any given moment. - // d d d d l r - // d 1 1 1 1 1 - // d 1 1 1 1 - // d 1 1 1 - // d 1 1 - // l 0 + // d d d d l r + // d 1 1 1 1 1 + // d 1 1 1 1 + // d 1 1 1 + // d 1 1 + // l 0 - int diffs = 0; - for (size_t y = 0; y != DECOY_COUNT + 2 - 1; y++) { - for (size_t x = y + 1; x != DECOY_COUNT + 2; x++) { - diffs += !!memcmp_cst(permuted[permute[x]], - permuted[permute[y]], - len); - } + int diffs = 0; + for (size_t y = 0; y != DECOY_COUNT + 2 - 1; y++) { + for (size_t x = y + 1; x != DECOY_COUNT + 2; x++) { + diffs += !!memcmp_cst(permuted[permute[x]], permuted[permute[y]], len); } + } - memzero(&decoys[0][0], sizeof(decoys)); - memzero(permuted, sizeof(permuted)); - memzero(permute, sizeof(permute)); + memzero(&decoys[0][0], sizeof(decoys)); + memzero(permuted, sizeof(permuted)); + memzero(permute, sizeof(permute)); - return diffs != (DECOY_COUNT + 2 - 1) * (DECOY_COUNT + 2) / 2 - 1; + return diffs != (DECOY_COUNT + 2 - 1) * (DECOY_COUNT + 2) / 2 - 1; } diff --git a/lib/board/memory.c b/lib/board/memory.c index 0a33c9630..321d2de7a 100644 --- a/lib/board/memory.c +++ b/lib/board/memory.c @@ -17,22 +17,19 @@ * along with this library. If not, see . */ - - #ifndef EMULATOR -# include -# include -# include -# include -# include "keepkey/board/mpudefs.h" +#include +#include +#include +#include +#include "keepkey/board/mpudefs.h" #else -# include +#include #endif #include "trezor/crypto/sha2.h" #include "trezor/crypto/sha3.h" - #include "keepkey/board/keepkey_board.h" #include "keepkey/board/memory.h" #include "keepkey/board/keepkey_flash.h" @@ -45,80 +42,90 @@ uint8_t *emulator_flash_base = NULL; #endif +void mpu_config(int priv_level) { + // Entry: + // priv_level is SIG_OK for KK signed firmware (currently not used, + // for future priv level use) + // Exit: + // Memory protection is set and enabled based on priv level + // + // CAUTION: It is possible to disable access to critical resources even in + // privileged mode. This can potentially birck device -void mpu_config(int priv_level) -{ - // Entry: - // priv_level is SIG_OK for KK signed firmware (currently not used, for future priv level use) - // Exit: - // Memory protection is set and enabled based on priv level - // - // CAUTION: It is possible to disable access to critical resources even in privileged mode. This - // can potentially birck device - - // Disable MPU - (void) priv_level; + // Disable MPU + (void)priv_level; #ifndef EMULATOR - MPU_CTRL = 0; - - // Note: later entries overwrite previous ones - // Flash (0x08000000 - 0x080FFFFF, 1 MiB, read-only) - MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRW_URO; - - // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) - MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - - // SRAM (0x2001F800 - 0x2001FFFF, bootloader protected ram, priv read-write only, execute never, disable high subregion) - MPU_RBAR = BLPROTECT_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_DIS_SUB_8 | MPU_RASR_SIZE_2KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; - - // Peripherals are not accessible by default, allow unpriv access (0x40020000 - 0x40023FFF, read-write, execute never) - MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - - // by default, the flash controller regs are accessible in unpriv mode, apply protection - // (0x40023C00 - 0x40023FFF, privileged read-write, unpriv no, execute never) - MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; - -#ifdef USART_DEBUG_ON - // USART3 is open to unprivileged access for usart debug versions only - // (0x40004800 - 0x40004BFF) - MPU_RBAR = 0x40004800 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + MPU_CTRL = 0; + + // Note: later entries overwrite previous ones + // Flash (0x08000000 - 0x080FFFFF, 1 MiB, read-only) + MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | + MPU_RASR_ATTR_AP_PRW_URO; + + // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // SRAM (0x2001F800 - 0x2001FFFF, bootloader protected ram, priv read-write + // only, execute never, disable high subregion) + MPU_RBAR = BLPROTECT_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_DIS_SUB_8 | + MPU_RASR_SIZE_2KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; + + // Peripherals are not accessible by default, allow unpriv access (0x40020000 + // - 0x40023FFF, read-write, execute never) + MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // by default, the flash controller regs are accessible in unpriv mode, apply + // protection (0x40023C00 - 0x40023FFF, privileged read-write, unpriv no, + // execute never) + MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; + +#ifdef USART_DEBUG_ON + // USART3 is open to unprivileged access for usart debug versions only + // (0x40004800 - 0x40004BFF) + MPU_RBAR = 0x40004800 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; #else - // If using release firmware, use this region to protect the sysconfig registers - // (0x40013800 - 0x40013BFF, read-only, execute never) - MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRO_UNO | MPU_RASR_ATTR_XN; + // If using release firmware, use this region to protect the sysconfig + // registers (0x40013800 - 0x40013BFF, read-only, execute never) + MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRO_UNO | MPU_RASR_ATTR_XN; #endif - // Allow access to the block from the USB FS periph up through the RNG to capture these two periphs in one region - // (0x50000000 - 0x50080000) - MPU_RBAR = 0x50060800 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - - // OTP and unique ids is open to unprivileged access - // (0x1FFF7800 - 0x1FFF7C00) - MPU_RBAR = 0x1FFF7800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Allow access to the block from the USB FS periph up through the RNG to + // capture these two periphs in one region (0x50000000 - 0x50080000) + MPU_RBAR = 0x50060800 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Enable MPU and use the default system memory privileges as the background execution of the system memory map. - MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA; + // OTP and unique ids is open to unprivileged access + // (0x1FFF7800 - 0x1FFF7C00) + MPU_RBAR = 0x1FFF7800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Enable memory fault handler - SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + // Enable MPU and use the default system memory privileges as the background + // execution of the system memory map. + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA; - __asm__ volatile("dsb"); - __asm__ volatile("isb"); -#endif //EMULATOR + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +#endif // EMULATOR } - /* * memory_protect() - Set option bytes for memory protection * @@ -127,61 +134,63 @@ void mpu_config(int priv_level) * OUTPUT * none */ -void memory_protect(void) -{ +void memory_protect(void) { #ifndef EMULATOR - /* set RDP level 2 WRP for sectors 0,5,6 */ - if((((*OPTION_BYTES_1) & 0xFFFF) == OPTION_RDP) && (((*OPTION_BYTES_2) & 0xFFFF) == OPTION_WRP)) - { - return; // already set up correctly - bail out - } - - flash_unlock_option_bytes(); - /* WRP + RDP */ - -#if !defined(DEBUG_ON) // safety check to make sure mem protect disabled in debug builds - flash_program_option_bytes((uint32_t)OPTION_WRP << 16 | OPTION_RDP); //RDP BLevel 2 (Irreversible) + /* set RDP level 2 WRP for sectors 0,5,6 + */ + if ((((*OPTION_BYTES_1) & 0xFFFF) == OPTION_RDP) && + (((*OPTION_BYTES_2) & 0xFFFF) == OPTION_WRP)) { + return; // already set up correctly - bail out + } + + flash_unlock_option_bytes(); + /* WRP + RDP */ + +#if !defined(DEBUG_ON) // safety check to make sure mem protect disabled in + // debug builds + flash_program_option_bytes((uint32_t)OPTION_WRP << 16 | + OPTION_RDP); // RDP BLevel 2 (Irreversible) #endif - flash_lock_option_bytes(); + flash_lock_option_bytes(); #else - printf("memory protect ON\n"); + printf("memory protect ON\n"); #endif } void memory_unlock(void) { #ifndef EMULATOR - // This exercises a bug in the STM32F2 that allows writing to read-only - // sectors of flash. - flash_unlock_option_bytes(); - + // This exercises a bug in the STM32F2 that allows writing to read-only + // sectors of flash. + flash_unlock_option_bytes(); + #ifdef DEBUG_ON - // 0xFFFAAEC: remove wp from all sectors, no RDP (unless previously set to level 2 which is irreversible), - // disable configurable resets. Low order two bits are don't care. - flash_program_option_bytes(0x0FFFAAEC); + // 0xFFFAAEC: remove wp from all sectors, no RDP (unless previously set to + // level 2 which is irreversible), disable configurable resets. Low order two + // bits are don't care. + flash_program_option_bytes(0x0FFFAAEC); #else - // Even though level 2 is described as sticky, this chip has a proven bug related to this register so - // to be sure rewrite the level two value for RDP for non-debug builds. - flash_program_option_bytes(0x0FFFCCEC); + // Even though level 2 is described as sticky, this chip has a proven bug + // related to this register so to be sure rewrite the level two value for RDP + // for non-debug builds. + flash_program_option_bytes(0x0FFFCCEC); #endif - flash_lock_option_bytes(); + flash_lock_option_bytes(); #endif } -int memory_bootloader_hash(uint8_t *hash, bool cached) -{ - static uint8_t cached_hash[SHA256_DIGEST_LENGTH]; +int memory_bootloader_hash(uint8_t *hash, bool cached) { + static uint8_t cached_hash[SHA256_DIGEST_LENGTH]; - if(cached_hash[0] == '\0' || !cached) - { - sha256_Raw((const uint8_t *)FLASH_BOOT_START, FLASH_BOOT_LEN, cached_hash); - sha256_Raw(cached_hash, SHA256_DIGEST_LENGTH, cached_hash); - } + if (cached_hash[0] == '\0' || !cached) { + sha256_Raw((const uint8_t *)FLASH_BOOT_START, FLASH_BOOT_LEN, cached_hash); + sha256_Raw(cached_hash, SHA256_DIGEST_LENGTH, cached_hash); + } - memcpy(hash, cached_hash, SHA256_DIGEST_LENGTH); + memcpy(hash, cached_hash, SHA256_DIGEST_LENGTH); - return SHA256_DIGEST_LENGTH; + return SHA256_DIGEST_LENGTH; } /* @@ -192,28 +201,24 @@ int memory_bootloader_hash(uint8_t *hash, bool cached) * OUTPUT * none */ -int memory_firmware_hash(uint8_t *hash) -{ +int memory_firmware_hash(uint8_t *hash) { #ifndef EMULATOR - SHA256_CTX ctx; - uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); - - if(codelen <= FLASH_APP_LEN) - { - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)META_MAGIC_STR, META_MAGIC_SIZE); - sha256_Update(&ctx, (const uint8_t *)FLASH_META_CODELEN, - FLASH_META_DESC_LEN - META_MAGIC_SIZE); - sha256_Update(&ctx, (const uint8_t *)FLASH_APP_START, codelen); - sha256_Final(&ctx, hash); - return SHA256_DIGEST_LENGTH; - } - else - { - return 0; - } -#else + SHA256_CTX ctx; + uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); + + if (codelen <= FLASH_APP_LEN) { + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)META_MAGIC_STR, META_MAGIC_SIZE); + sha256_Update(&ctx, (const uint8_t *)FLASH_META_CODELEN, + FLASH_META_DESC_LEN - META_MAGIC_SIZE); + sha256_Update(&ctx, (const uint8_t *)FLASH_APP_START, codelen); + sha256_Final(&ctx, hash); + return SHA256_DIGEST_LENGTH; + } else { return 0; + } +#else + return 0; #endif } @@ -222,17 +227,16 @@ int memory_firmware_hash(uint8_t *hash) * * INPUT * - hash: buffer to be filled with hash - * - storage_location: current storage location (changes due to wear leveling) - * OUTPUT - * none + * - storage_location: current storage location (changes due to wear + * leveling) OUTPUT none */ -int memory_storage_hash(uint8_t *hash, Allocation storage_location) -{ - const uint8_t *storage_location_start; - storage_location_start = (const uint8_t *)flash_write_helper(storage_location); +int memory_storage_hash(uint8_t *hash, Allocation storage_location) { + const uint8_t *storage_location_start; + storage_location_start = + (const uint8_t *)flash_write_helper(storage_location); - sha256_Raw(storage_location_start, STORAGE_SECTOR_LEN, hash); - return SHA256_DIGEST_LENGTH; + sha256_Raw(storage_location_start, STORAGE_SECTOR_LEN, hash); + return SHA256_DIGEST_LENGTH; } /* @@ -244,113 +248,105 @@ int memory_storage_hash(uint8_t *hash, Allocation storage_location) * status * */ -bool find_active_storage(Allocation *storage_location) -{ - bool ret_stat = false; - Allocation storage_location_use; - size_t storage_location_start; - - /* Find 1st storage sector with valid data */ - for(storage_location_use = FLASH_STORAGE1; storage_location_use <= FLASH_STORAGE3; - storage_location_use++) - { - storage_location_start = flash_write_helper(storage_location_use); - - if(memcmp((void *)storage_location_start, STORAGE_MAGIC_STR, STORAGE_MAGIC_LEN) == 0) - { - /* Found valid data. Load data and exit */ - *storage_location = storage_location_use; - ret_stat = true; - break; - } +bool find_active_storage(Allocation *storage_location) { + bool ret_stat = false; + Allocation storage_location_use; + size_t storage_location_start; + + /* Find 1st storage sector with valid data */ + for (storage_location_use = FLASH_STORAGE1; + storage_location_use <= FLASH_STORAGE3; storage_location_use++) { + storage_location_start = flash_write_helper(storage_location_use); + + if (memcmp((void *)storage_location_start, STORAGE_MAGIC_STR, + STORAGE_MAGIC_LEN) == 0) { + /* Found valid data. Load data and exit */ + *storage_location = storage_location_use; + ret_stat = true; + break; } + } - return(ret_stat); + return (ret_stat); } Allocation next_storage(Allocation active) { - switch (active) { + switch (active) { case FLASH_STORAGE1: - return FLASH_STORAGE2; + return FLASH_STORAGE2; case FLASH_STORAGE2: - return FLASH_STORAGE3; + return FLASH_STORAGE3; case FLASH_STORAGE3: - return FLASH_STORAGE1; + return FLASH_STORAGE1; default: - assert(false && "Unsupported storage sector provided"); - return FLASH_STORAGE1; - } + assert(false && "Unsupported storage sector provided"); + return FLASH_STORAGE1; + } } /// Write the marker that allows the firmware to boot. /// \returns true iff successful -bool storage_protect_off(void) -{ - Allocation active; - if (!find_active_storage(&active)) - return false; - - Allocation marker_sector = next_storage(active); - flash_erase_word(marker_sector); - bool ret = flash_write(marker_sector, 0, sizeof(STORAGE_PROTECT_OFF_MAGIC), - (const uint8_t *)STORAGE_PROTECT_OFF_MAGIC); - return ret; +bool storage_protect_off(void) { + Allocation active; + if (!find_active_storage(&active)) return false; + + Allocation marker_sector = next_storage(active); + flash_erase_word(marker_sector); + bool ret = flash_write(marker_sector, 0, sizeof(STORAGE_PROTECT_OFF_MAGIC), + (const uint8_t *)STORAGE_PROTECT_OFF_MAGIC); + return ret; } /// Clear the marker that allows the firmware to boot. /// \returns true iff successful -bool storage_protect_on(void) -{ - _Static_assert(sizeof(STORAGE_PROTECT_ON_MAGIC) == sizeof(STORAGE_PROTECT_OFF_MAGIC), - "Storage protection markers must be the same length"); - - Allocation active; - if (!find_active_storage(&active)) - return false; - - Allocation marker_sector = next_storage(active); - flash_erase_word(marker_sector); - bool ret = flash_write(marker_sector, 0, sizeof(STORAGE_PROTECT_ON_MAGIC), - (const uint8_t*)STORAGE_PROTECT_ON_MAGIC); - return ret; +bool storage_protect_on(void) { + _Static_assert( + sizeof(STORAGE_PROTECT_ON_MAGIC) == sizeof(STORAGE_PROTECT_OFF_MAGIC), + "Storage protection markers must be the same length"); + + Allocation active; + if (!find_active_storage(&active)) return false; + + Allocation marker_sector = next_storage(active); + flash_erase_word(marker_sector); + bool ret = flash_write(marker_sector, 0, sizeof(STORAGE_PROTECT_ON_MAGIC), + (const uint8_t *)STORAGE_PROTECT_ON_MAGIC); + return ret; } static const char *sector_start(Allocation a) { - const FlashSector *sector = flash_sector_map; - while (sector->use != FLASH_INVALID) { - if (sector->use == a) { - return (const char *)sector->start; - } - sector++; + const FlashSector *sector = flash_sector_map; + while (sector->use != FLASH_INVALID) { + if (sector->use == a) { + return (const char *)sector->start; } - return NULL; + sector++; + } + return NULL; } -uint32_t storage_protect_status(void) -{ - Allocation active; - if (!find_active_storage(&active)) - return STORAGE_PROTECT_DISABLED; +uint32_t storage_protect_status(void) { + Allocation active; + if (!find_active_storage(&active)) return STORAGE_PROTECT_DISABLED; - Allocation marker_sector = next_storage(active); + Allocation marker_sector = next_storage(active); - const char *start = sector_start(marker_sector); - if (!start) - return STORAGE_PROTECT_ENABLED; + const char *start = sector_start(marker_sector); + if (!start) return STORAGE_PROTECT_ENABLED; - return memcmp(STORAGE_PROTECT_OFF_MAGIC, start, sizeof(STORAGE_PROTECT_OFF_MAGIC)) - ? STORAGE_PROTECT_ENABLED : STORAGE_PROTECT_DISABLED; + return memcmp(STORAGE_PROTECT_OFF_MAGIC, start, + sizeof(STORAGE_PROTECT_OFF_MAGIC)) + ? STORAGE_PROTECT_ENABLED + : STORAGE_PROTECT_DISABLED; } void storage_protect_wipe(uint32_t storage_protect_status) { - // Don't move this check into the caller. It was done this way to play - // nicely with storage_protect_status() / fi_defense_delay(), so that we're - // protected from fault injection during this branch: - if (STORAGE_PROTECT_DISABLED == storage_protect_status) - return; - - flash_erase_word(FLASH_STORAGE1); - flash_erase_word(FLASH_STORAGE2); - flash_erase_word(FLASH_STORAGE3); + // Don't move this check into the caller. It was done this way to play + // nicely with storage_protect_status() / fi_defense_delay(), so that we're + // protected from fault injection during this branch: + if (STORAGE_PROTECT_DISABLED == storage_protect_status) return; + + flash_erase_word(FLASH_STORAGE1); + flash_erase_word(FLASH_STORAGE2); + flash_erase_word(FLASH_STORAGE3); } - diff --git a/lib/board/messages.c b/lib/board/messages.c index 8fc6064ee..16da635d1 100644 --- a/lib/board/messages.c +++ b/lib/board/messages.c @@ -37,9 +37,9 @@ static msg_failure_t msg_failure; static msg_debug_link_get_state_t msg_debug_link_get_state; #endif -/* Allow mapped messages to reset message stack. This variable by itself doesn't - * do much but messages down the line can use it to determine for to gracefully - * exit from a message should the message stack been reset +/* Allow mapped messages to reset message stack. This variable by itself + * doesn't do much but messages down the line can use it to determine for to + * gracefully exit from a message should the message stack been reset */ bool reset_msg_stack = false; @@ -54,18 +54,16 @@ bool reset_msg_stack = false; * entry if found */ static const MessagesMap_t *message_map_entry(MessageMapType type, - MessageType msg_id, - MessageMapDirection dir) -{ - const MessagesMap_t *m = MessagesMap; - - if (map_size > msg_id && m[msg_id].msg_id == msg_id && - m[msg_id].type == type && m[msg_id].dir == dir) - { - return &m[msg_id]; - } + MessageType msg_id, + MessageMapDirection dir) { + const MessagesMap_t *m = MessagesMap; + + if (map_size > msg_id && m[msg_id].msg_id == msg_id && + m[msg_id].type == type && m[msg_id].dir == dir) { + return &m[msg_id]; + } - return NULL; + return NULL; } /* @@ -79,19 +77,17 @@ static const MessagesMap_t *message_map_entry(MessageMapType type, * protocol buffer */ const pb_field_t *message_fields(MessageMapType type, MessageType msg_id, - MessageMapDirection dir) -{ - assert(MessagesMap != NULL); + MessageMapDirection dir) { + assert(MessagesMap != NULL); - const MessagesMap_t *m = MessagesMap; + const MessagesMap_t *m = MessagesMap; - if(map_size > msg_id && m[msg_id].msg_id == msg_id && m[msg_id].type == type && - m[msg_id].dir == dir) - { - return m[msg_id].fields; - } + if (map_size > msg_id && m[msg_id].msg_id == msg_id && + m[msg_id].type == type && m[msg_id].dir == dir) { + return m[msg_id].fields; + } - return NULL; + return NULL; } /* @@ -105,15 +101,15 @@ const pb_field_t *message_fields(MessageMapType type, MessageType msg_id, * OUTPUT * true/false whether protocol buffers were parsed successfully */ -static bool pb_parse(const MessagesMap_t *entry, uint8_t *msg, uint32_t msg_size, - uint8_t *buf) -{ - pb_istream_t stream = pb_istream_from_buffer(msg, msg_size); - return pb_decode(&stream, entry->fields, buf); +static bool pb_parse(const MessagesMap_t *entry, uint8_t *msg, + uint32_t msg_size, uint8_t *buf) { + pb_istream_t stream = pb_istream_from_buffer(msg, msg_size); + return pb_decode(&stream, entry->fields, buf); } /* - * dispatch() - Process received message and jump to corresponding process function + * dispatch() - Process received message and jump to corresponding process + * function * * INPUT * - entry: pointer to message entry @@ -123,23 +119,23 @@ static bool pb_parse(const MessagesMap_t *entry, uint8_t *msg, uint32_t msg_size * none * */ -static void dispatch(const MessagesMap_t *entry, uint8_t *msg, uint32_t msg_size) -{ - static uint8_t decode_buffer[MAX_DECODE_SIZE] __attribute__((aligned(4))); - memset(decode_buffer, 0, sizeof(decode_buffer)); - - if (!pb_parse(entry, msg, msg_size, decode_buffer)) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, - "Could not parse protocol buffer message"); - return; - } - - if (!entry->process_func) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unexpected message"); - return; - } - - entry->process_func(decode_buffer); +static void dispatch(const MessagesMap_t *entry, uint8_t *msg, + uint32_t msg_size) { + static uint8_t decode_buffer[MAX_DECODE_SIZE] __attribute__((aligned(4))); + memset(decode_buffer, 0, sizeof(decode_buffer)); + + if (!pb_parse(entry, msg, msg_size, decode_buffer)) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, + "Could not parse protocol buffer message"); + return; + } + + if (!entry->process_func) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unexpected message"); + return; + } + + entry->process_func(decode_buffer); } /* @@ -154,160 +150,156 @@ static void dispatch(const MessagesMap_t *entry, uint8_t *msg, uint32_t msg_size * OUTPUT * none */ -static void raw_dispatch(const MessagesMap_t *entry, const uint8_t *msg, uint32_t msg_size, - uint32_t frame_length) -{ - static RawMessage raw_msg; - raw_msg.buffer = msg; - raw_msg.length = msg_size; - - if(entry->process_func) - { - ((raw_msg_handler_t)(void*)entry->process_func)(&raw_msg, frame_length); - } +static void raw_dispatch(const MessagesMap_t *entry, const uint8_t *msg, + uint32_t msg_size, uint32_t frame_length) { + static RawMessage raw_msg; + raw_msg.buffer = msg; + raw_msg.length = msg_size; + + if (entry->process_func) { + ((raw_msg_handler_t)(void *)entry->process_func)(&raw_msg, frame_length); + } } #if !defined(__has_builtin) -# define __has_builtin(X) 0 +#define __has_builtin(X) 0 #endif #if __has_builtin(__builtin_add_overflow) -# define check_uadd_overflow(A, B, R) \ - ({ \ - typeof(A) __a = (A); \ - typeof(B) __b = (B); \ - typeof(R) __r = (R); \ - (void)(&__a == &__b && "types must match"); \ - (void)(&__a == __r && "types must match"); \ - _Static_assert(0 < (typeof(A))-1, "types must be unsigned"); \ - __builtin_add_overflow((A), (B), (R)); \ - }) +#define check_uadd_overflow(A, B, R) \ + ({ \ + typeof(A) __a = (A); \ + typeof(B) __b = (B); \ + typeof(R) __r = (R); \ + (void)(&__a == &__b && "types must match"); \ + (void)(&__a == __r && "types must match"); \ + _Static_assert(0 < (typeof(A)) - 1, "types must be unsigned"); \ + __builtin_add_overflow((A), (B), (R)); \ + }) #else -# define check_uadd_overflow(A, B, R) \ - ({ \ - typeof(A) __a = (A); \ - typeof(B) __b = (B); \ - typeof(R) __r = (R); \ - (void)(&__a == &__b); \ - (void)(&__a == __r); \ - (void)(&__a == &__b && "types must match"); \ - (void)(&__a == __r && "types must match"); \ - _Static_assert(0 < (typeof(A))-1, "types must be unsigned"); \ - *__r = __a + __b; \ - *__r < __a; \ - }) +#define check_uadd_overflow(A, B, R) \ + ({ \ + typeof(A) __a = (A); \ + typeof(B) __b = (B); \ + typeof(R) __r = (R); \ + (void)(&__a == &__b); \ + (void)(&__a == __r); \ + (void)(&__a == &__b && "types must match"); \ + (void)(&__a == __r && "types must match"); \ + _Static_assert(0 < (typeof(A)) - 1, "types must be unsigned"); \ + *__r = __a + __b; \ + *__r < __a; \ + }) #endif /// Common helper that handles USB messages from host -void usb_rx_helper(const uint8_t *buf, size_t length, MessageMapType type) -{ - static bool firstFrame = true; - - static uint16_t msgId; - static uint32_t msgSize; - static uint8_t msg[MAX_FRAME_SIZE]; - static size_t cursor; //< Index into msg where the current frame is to be written. - static const MessagesMap_t *entry; - - if (firstFrame) { - msgId = 0xffff; - msgSize = 0; - memset(msg, 0, sizeof(msg)); - cursor = 0; - entry = NULL; - } +void usb_rx_helper(const uint8_t *buf, size_t length, MessageMapType type) { + static bool firstFrame = true; - assert(buf != NULL); + static uint16_t msgId; + static uint32_t msgSize; + static uint8_t msg[MAX_FRAME_SIZE]; + static size_t + cursor; //< Index into msg where the current frame is to be written. + static const MessagesMap_t *entry; - if (length < 1 + 2 + 2 + 4) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Buffer too small"); - goto reset; - } + if (firstFrame) { + msgId = 0xffff; + msgSize = 0; + memset(msg, 0, sizeof(msg)); + cursor = 0; + entry = NULL; + } - if (buf[0] != '?') { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed packet"); - goto reset; - } + assert(buf != NULL); - if (firstFrame && (buf[1] != '#' || buf[2] != '#')) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed packet"); - goto reset; - } + if (length < 1 + 2 + 2 + 4) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Buffer too small"); + goto reset; + } - // Details of the chunk being copied out of the current frame. - const uint8_t *frame; - size_t frameSize; + if (buf[0] != '?') { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed packet"); + goto reset; + } - if (firstFrame) { - // Reset the buffer that we're writing fragments into. - memset(msg, 0, sizeof(msg)); + if (firstFrame && (buf[1] != '#' || buf[2] != '#')) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed packet"); + goto reset; + } - // Then fish out the id / size, which are big-endian uint16 / - // uint32's respectively. - msgId = buf[4] | ((uint16_t)buf[3]) << 8; - msgSize = buf[8] | - ((uint32_t)buf[7]) << 8 | - ((uint32_t)buf[6]) << 16 | - ((uint32_t)buf[5]) << 24; + // Details of the chunk being copied out of the current frame. + const uint8_t *frame; + size_t frameSize; - // Determine callback handler and message map type. - entry = message_map_entry(type, msgId, IN_MSG); + if (firstFrame) { + // Reset the buffer that we're writing fragments into. + memset(msg, 0, sizeof(msg)); - // And reset the cursor. - cursor = 0; + // Then fish out the id / size, which are big-endian uint16 / + // uint32's respectively. + msgId = buf[4] | ((uint16_t)buf[3]) << 8; + msgSize = buf[8] | ((uint32_t)buf[7]) << 8 | ((uint32_t)buf[6]) << 16 | + ((uint32_t)buf[5]) << 24; - // Then take note of the fragment boundaries. - frame = &buf[9]; - frameSize = MIN(length - 9, msgSize); - } else { - // Otherwise it's a continuation/fragment. - frame = &buf[1]; - frameSize = length - 1; - } + // Determine callback handler and message map type. + entry = message_map_entry(type, msgId, IN_MSG); - // If the msgId wasn't in our map, bail. - if (!entry) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unknown message"); - goto reset; - } + // And reset the cursor. + cursor = 0; - if (entry->dispatch == RAW) { - /* Call dispatch for every segment since we are not buffering and parsing, and - * assume the raw dispatched callbacks will handle their own state and - * buffering internally - */ - raw_dispatch(entry, frame, frameSize, msgSize); - firstFrame = false; - return; - } + // Then take note of the fragment boundaries. + frame = &buf[9]; + frameSize = MIN(length - 9, msgSize); + } else { + // Otherwise it's a continuation/fragment. + frame = &buf[1]; + frameSize = length - 1; + } + + // If the msgId wasn't in our map, bail. + if (!entry) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unknown message"); + goto reset; + } + + if (entry->dispatch == RAW) { + /* Call dispatch for every segment since we are not buffering and parsing, + * and assume the raw dispatched callbacks will handle their own state and + * buffering internally + */ + raw_dispatch(entry, frame, frameSize, msgSize); + firstFrame = false; + return; + } - size_t end; - if (check_uadd_overflow(cursor, frameSize, &end) || sizeof(msg) < end) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed message"); - goto reset; - } + size_t end; + if (check_uadd_overflow(cursor, frameSize, &end) || sizeof(msg) < end) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed message"); + goto reset; + } - // Copy content to frame buffer. - memcpy(&msg[cursor], frame, frameSize); + // Copy content to frame buffer. + memcpy(&msg[cursor], frame, frameSize); - // Advance the cursor. - cursor = end; + // Advance the cursor. + cursor = end; - // Only parse and message map if all segments have been buffered. - bool last_segment = cursor >= msgSize; - if (!last_segment) { - firstFrame = false; - return; - } + // Only parse and message map if all segments have been buffered. + bool last_segment = cursor >= msgSize; + if (!last_segment) { + firstFrame = false; + return; + } - dispatch(entry, msg, msgSize); + dispatch(entry, msg, msgSize); reset: - msgId = 0xffff; - msgSize = 0; - memset(msg, 0, sizeof(msg)); - cursor = 0; - firstFrame = true; - entry = NULL; + msgId = 0xffff; + msgSize = 0; + memset(msg, 0, sizeof(msg)); + cursor = 0; + firstFrame = true; + entry = NULL; } /* Tiny messages */ @@ -328,93 +320,91 @@ _Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), #endif static void msg_read_tiny(const uint8_t *msg, size_t len) { - if (len != 64) - return; + if (len != 64) return; - uint8_t buf[64]; - memcpy(buf, msg, sizeof(buf)); + uint8_t buf[64]; + memcpy(buf, msg, sizeof(buf)); - if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed tiny packet"); - return; - } + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, + "Malformed tiny packet"); + return; + } - uint16_t msgId = buf[4] | ((uint16_t)buf[3]) << 8; - uint32_t msgSize = buf[8] | - ((uint32_t)buf[7]) << 8 | - ((uint32_t)buf[6]) << 16 | - ((uint32_t)buf[5]) << 24; + uint16_t msgId = buf[4] | ((uint16_t)buf[3]) << 8; + uint32_t msgSize = buf[8] | ((uint32_t)buf[7]) << 8 | + ((uint32_t)buf[6]) << 16 | ((uint32_t)buf[5]) << 24; - if (msgSize > 64 - 9) { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Malformed tiny packet"); - return; - } + if (msgSize > 64 - 9) { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, + "Malformed tiny packet"); + return; + } - const pb_field_t *fields = NULL; - pb_istream_t stream = pb_istream_from_buffer(buf + 9, msgSize); + const pb_field_t *fields = NULL; + pb_istream_t stream = pb_istream_from_buffer(buf + 9, msgSize); - switch (msgId) { + switch (msgId) { case MessageType_MessageType_PinMatrixAck: - fields = PinMatrixAck_fields; - break; + fields = PinMatrixAck_fields; + break; case MessageType_MessageType_ButtonAck: - fields = ButtonAck_fields; - break; + fields = ButtonAck_fields; + break; case MessageType_MessageType_PassphraseAck: - fields = PassphraseAck_fields; - break; + fields = PassphraseAck_fields; + break; case MessageType_MessageType_Cancel: - fields = Cancel_fields; - break; + fields = Cancel_fields; + break; case MessageType_MessageType_Initialize: - fields = Initialize_fields; - break; + fields = Initialize_fields; + break; #if DEBUG_LINK case MessageType_MessageType_DebugLinkDecision: - fields = DebugLinkDecision_fields; - break; + fields = DebugLinkDecision_fields; + break; case MessageType_MessageType_DebugLinkGetState: - fields = DebugLinkGetState_fields; - break; + fields = DebugLinkGetState_fields; + break; #endif - } + } - if (fields) { - bool status = pb_decode(&stream, fields, msg_tiny); - if (status) { - msg_tiny_id = msgId; - } else { - (*msg_failure)(FailureType_Failure_SyntaxError, "Malformed tiny packet"); - msg_tiny_id = 0xffff; - } + if (fields) { + bool status = pb_decode(&stream, fields, msg_tiny); + if (status) { + msg_tiny_id = msgId; } else { - (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unknown message"); - msg_tiny_id = 0xffff; + (*msg_failure)(FailureType_Failure_SyntaxError, "Malformed tiny packet"); + msg_tiny_id = 0xffff; } + } else { + (*msg_failure)(FailureType_Failure_UnexpectedMessage, "Unknown message"); + msg_tiny_id = 0xffff; + } } -void handle_usb_rx(const void *msg, size_t len) -{ - if (msg_tiny_flag) { - msg_read_tiny(msg, len); - } else { - usb_rx_helper(msg, len, NORMAL_MSG); - } +void handle_usb_rx(const void *msg, size_t len) { + if (msg_tiny_flag) { + msg_read_tiny(msg, len); + } else { + usb_rx_helper(msg, len, NORMAL_MSG); + } } #if DEBUG_LINK -void handle_debug_usb_rx(const void *msg, size_t len) -{ - if (msg_tiny_flag) { - msg_read_tiny(msg, len); - } else { - usb_rx_helper(msg, len, DEBUG_MSG); - } +void handle_debug_usb_rx(const void *msg, size_t len) { + if (msg_tiny_flag) { + msg_read_tiny(msg, len); + } else { + usb_rx_helper(msg, len, DEBUG_MSG); + } } #endif /* - * tiny_msg_poll_and_buffer() - Poll usb port to check for tiny message from host + * tiny_msg_poll_and_buffer() - Poll usb port to check for tiny message from + * host * * INPUT * - block: flag to continually poll usb until tiny message is received @@ -423,29 +413,25 @@ void handle_debug_usb_rx(const void *msg, size_t len) * message type * */ -static MessageType tiny_msg_poll_and_buffer(bool block, uint8_t *buf) -{ - msg_tiny_id = MSG_TINY_TYPE_ERROR; - msg_tiny_flag = true; - - while(msg_tiny_id == MSG_TINY_TYPE_ERROR) - { - usbPoll(); - - if(!block) - { - break; - } - } +static MessageType tiny_msg_poll_and_buffer(bool block, uint8_t *buf) { + msg_tiny_id = MSG_TINY_TYPE_ERROR; + msg_tiny_flag = true; - msg_tiny_flag = false; + while (msg_tiny_id == MSG_TINY_TYPE_ERROR) { + usbPoll(); - if(msg_tiny_id != MSG_TINY_TYPE_ERROR) - { - memcpy(buf, msg_tiny, sizeof(msg_tiny)); + if (!block) { + break; } + } - return msg_tiny_id; + msg_tiny_flag = false; + + if (msg_tiny_id != MSG_TINY_TYPE_ERROR) { + memcpy(buf, msg_tiny, sizeof(msg_tiny)); + } + + return msg_tiny_id; } /* @@ -457,11 +443,10 @@ static MessageType tiny_msg_poll_and_buffer(bool block, uint8_t *buf) * OUTPUT * */ -void msg_map_init(const void *map, const size_t size) -{ - assert(map != NULL); - MessagesMap = map; - map_size = size; +void msg_map_init(const void *map, const size_t size) { + assert(map != NULL); + MessagesMap = map; + map_size = size; } /* @@ -472,13 +457,13 @@ void msg_map_init(const void *map, const size_t size) * OUTPUT * none */ -void set_msg_failure_handler(msg_failure_t failure_func) -{ - msg_failure = failure_func; +void set_msg_failure_handler(msg_failure_t failure_func) { + msg_failure = failure_func; } /* - * set_msg_debug_link_get_state_handler() - Setup usb message debug link get state handler + * set_msg_debug_link_get_state_handler() - Setup usb message debug link get + * state handler * * INPUT * - debug_link_get_state_func: message initialization handler @@ -486,10 +471,9 @@ void set_msg_failure_handler(msg_failure_t failure_func) * none */ #if DEBUG_LINK -void set_msg_debug_link_get_state_handler(msg_debug_link_get_state_t - debug_link_get_state_func) -{ - msg_debug_link_get_state = debug_link_get_state_func; +void set_msg_debug_link_get_state_handler( + msg_debug_link_get_state_t debug_link_get_state_func) { + msg_debug_link_get_state = debug_link_get_state_func; } #endif @@ -502,16 +486,15 @@ void set_msg_debug_link_get_state_handler(msg_debug_link_get_state_t * OUTPUT * none */ -void call_msg_failure_handler(FailureType code, const char *text) -{ - if(msg_failure) - { - (*msg_failure)(code, text); - } +void call_msg_failure_handler(FailureType code, const char *text) { + if (msg_failure) { + (*msg_failure)(code, text); + } } /* - * call_msg_debug_link_get_state_handler() - Call message debug link get state handler + * call_msg_debug_link_get_state_handler() - Call message debug link get state + * handler * * INPUT * none @@ -519,12 +502,10 @@ void call_msg_failure_handler(FailureType code, const char *text) * none */ #if DEBUG_LINK -void call_msg_debug_link_get_state_handler(DebugLinkGetState *msg) -{ - if(msg_debug_link_get_state) - { - (*msg_debug_link_get_state)(msg); - } +void call_msg_debug_link_get_state_handler(DebugLinkGetState *msg) { + if (msg_debug_link_get_state) { + (*msg_debug_link_get_state)(msg); + } } #endif @@ -536,11 +517,10 @@ void call_msg_debug_link_get_state_handler(DebugLinkGetState *msg) * OUTPUT * none */ -void msg_init(void) -{ - usb_set_rx_callback(handle_usb_rx); +void msg_init(void) { + usb_set_rx_callback(handle_usb_rx); #if DEBUG_LINK - usb_set_debug_rx_callback(handle_debug_usb_rx); + usb_set_debug_rx_callback(handle_debug_usb_rx); #endif } @@ -553,9 +533,8 @@ void msg_init(void) * message tiny type * */ -MessageType wait_for_tiny_msg(uint8_t *buf) -{ - return tiny_msg_poll_and_buffer(true, buf); +MessageType wait_for_tiny_msg(uint8_t *buf) { + return tiny_msg_poll_and_buffer(true, buf); } /* @@ -567,9 +546,8 @@ MessageType wait_for_tiny_msg(uint8_t *buf) * message tiny type * */ -MessageType check_for_tiny_msg(uint8_t *buf) -{ - return tiny_msg_poll_and_buffer(false, buf); +MessageType check_for_tiny_msg(uint8_t *buf) { + return tiny_msg_poll_and_buffer(false, buf); } /* @@ -581,31 +559,29 @@ MessageType check_for_tiny_msg(uint8_t *buf) * OUTPUT * bytes that were skipped */ -uint32_t parse_pb_varint(RawMessage *msg, uint8_t varint_count) -{ - uint32_t skip; - uint8_t i; - uint64_t pb_varint; - pb_istream_t stream; - - /* - * Parse varints - */ - stream = pb_istream_from_buffer((uint8_t*)msg->buffer, msg->length); - skip = stream.bytes_left; - for(i = 0; i < varint_count; ++i) - { - pb_decode_varint(&stream, &pb_varint); - } - skip = skip - stream.bytes_left; - - /* - * Increment skip over message - */ - msg->length -= skip; - msg->buffer = (uint8_t *)(msg->buffer + skip); - - return skip; +uint32_t parse_pb_varint(RawMessage *msg, uint8_t varint_count) { + uint32_t skip; + uint8_t i; + uint64_t pb_varint; + pb_istream_t stream; + + /* + * Parse varints + */ + stream = pb_istream_from_buffer((uint8_t *)msg->buffer, msg->length); + skip = stream.bytes_left; + for (i = 0; i < varint_count; ++i) { + pb_decode_varint(&stream, &pb_varint); + } + skip = skip - stream.bytes_left; + + /* + * Increment skip over message + */ + msg->length -= skip; + msg->buffer = (uint8_t *)(msg->buffer + skip); + + return skip; } /* @@ -619,12 +595,11 @@ uint32_t parse_pb_varint(RawMessage *msg, uint8_t varint_count) * OUTPUT * bytes written to buffer */ -int encode_pb(const void *source_ptr, const pb_field_t *fields, uint8_t *buffer, uint32_t len ) -{ - pb_ostream_t os = pb_ostream_from_buffer(buffer, len); +int encode_pb(const void *source_ptr, const pb_field_t *fields, uint8_t *buffer, + uint32_t len) { + pb_ostream_t os = pb_ostream_from_buffer(buffer, len); - if (!pb_encode(&os, fields, source_ptr)) - return 0; + if (!pb_encode(&os, fields, source_ptr)) return 0; - return os.bytes_written; + return os.bytes_written; } diff --git a/lib/board/mmhusr.c b/lib/board/mmhusr.c index 64e33046c..794074d92 100644 --- a/lib/board/mmhusr.c +++ b/lib/board/mmhusr.c @@ -18,13 +18,13 @@ */ #ifndef EMULATOR -# include -# include -# include +#include +#include +#include #else -# include -# include -# include +#include +#include +#include #endif #include "keepkey/board/supervise.h" @@ -40,17 +40,22 @@ void mmhisr(void) { #ifndef EMULATOR #ifdef DEBUG_ON - static char errval[MAX_ERRMSG]; - uint32_t mmfar = (uint32_t)_param_1; - uint32_t pc = (uint32_t)_param_2; - snprintf(errval, MAX_ERRMSG, "addr: 0x%08" PRIx32 " pc: 0x%08" PRIx32, mmfar, pc); - layout_standard_notification("Memory Fault Detected", errval, NOTIFICATION_UNPLUG); + static char errval[MAX_ERRMSG]; + uint32_t mmfar = (uint32_t)_param_1; + uint32_t pc = (uint32_t)_param_2; + snprintf(errval, MAX_ERRMSG, "addr: 0x%08" PRIx32 " pc: 0x%08" PRIx32, mmfar, + pc); + layout_standard_notification("Memory Fault Detected", errval, + NOTIFICATION_UNPLUG); #else - layout_standard_notification("Memory Fault Detected", "Please unplug your device!", NOTIFICATION_UNPLUG); + layout_standard_notification("Memory Fault Detected", + "Please unplug your device!", + NOTIFICATION_UNPLUG); #endif - display_refresh(); - for (;;) {} + display_refresh(); + for (;;) { + } #else - abort(); + abort(); #endif } diff --git a/lib/board/pin.c b/lib/board/pin.c index 12504a890..e6cd0776b 100644 --- a/lib/board/pin.c +++ b/lib/board/pin.c @@ -17,57 +17,56 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include +#include +#include #endif #include "keepkey/board/pin.h" - /* * pin_init_output() - Initialize GPIO for LED * * INPUT - * - pin: pointer pin assignment - * - output_mode: pin output state - * - pull_mode: input mode + * - pin: pointer pin assignment + * - output_mode: pin output state + * - pull_mode: input mode * OUTPUT - * none + * none */ -void pin_init_output(const Pin *pin, OutputMode output_mode, PullMode pull_mode) -{ +void pin_init_output(const Pin *pin, OutputMode output_mode, + PullMode pull_mode) { #ifndef EMULATOR - uint8_t output_mode_setpoint; - uint8_t pull_mode_setpoint; + uint8_t output_mode_setpoint; + uint8_t pull_mode_setpoint; - switch( output_mode ) { - case OPEN_DRAIN_MODE: - output_mode_setpoint = GPIO_OTYPE_OD; - break; - case PUSH_PULL_MODE: - default: - output_mode_setpoint = GPIO_OTYPE_PP; - break; - } + switch (output_mode) { + case OPEN_DRAIN_MODE: + output_mode_setpoint = GPIO_OTYPE_OD; + break; + case PUSH_PULL_MODE: + default: + output_mode_setpoint = GPIO_OTYPE_PP; + break; + } - switch( pull_mode ) { - case PULL_UP_MODE: - pull_mode_setpoint = GPIO_PUPD_PULLUP; - break; - case PULL_DOWN_MODE: - pull_mode_setpoint = GPIO_PUPD_PULLDOWN; - break; + switch (pull_mode) { + case PULL_UP_MODE: + pull_mode_setpoint = GPIO_PUPD_PULLUP; + break; + case PULL_DOWN_MODE: + pull_mode_setpoint = GPIO_PUPD_PULLDOWN; + break; - case NO_PULL_MODE: - default: - pull_mode_setpoint = GPIO_PUPD_NONE; - break; - } + case NO_PULL_MODE: + default: + pull_mode_setpoint = GPIO_PUPD_NONE; + break; + } - /* Set up port A */ - gpio_mode_setup( pin->port, GPIO_MODE_OUTPUT, pull_mode_setpoint, pin->pin ); - gpio_set_output_options( pin->port, output_mode_setpoint, GPIO_OSPEED_100MHZ, pin->pin ); + /* Set up port A */ + gpio_mode_setup(pin->port, GPIO_MODE_OUTPUT, pull_mode_setpoint, pin->pin); + gpio_set_output_options(pin->port, output_mode_setpoint, GPIO_OSPEED_100MHZ, + pin->pin); #endif } diff --git a/lib/board/resources.c b/lib/board/resources.c index 78edf3a7f..b21bf8f4a 100644 --- a/lib/board/resources.c +++ b/lib/board/resources.c @@ -17,405 +17,1641 @@ * along with this library. If not, see . */ - #include "keepkey/board/resources.h" #include - /* --- Confirm Icon Animation ---------------------------------------------- */ -static const uint8_t confirm_icon_data[240] = -{ - 0x04, 0x00, 0xfc, 0x0a, 0x55, 0xa3, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0xa3, 0x55, 0x0a, 0x0b, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x07, 0x00, 0xfe, 0x45, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x45, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x8b, 0x06, 0xff, 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, 0xff, 0xd5, 0x06, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x3f, 0x02, 0x00, 0xff, 0x3f, 0x06, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x3f, 0xff, 0x55, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x45, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x45, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0xa3, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0xa3, 0x55, 0x0a, 0x08, 0x00 -}; -static const Image confirm_icon_image = {22, 18, sizeof(confirm_icon_data), confirm_icon_data}; -const AnimationFrame confirm_icon_frame = {233, 4, 20, 100, &confirm_icon_image}; +static const uint8_t confirm_icon_data[240] = { + 0x04, 0x00, 0xfc, 0x0a, 0x55, 0xa3, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0xa3, + 0x55, 0x0a, 0x0b, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, + 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x07, 0x00, + 0xfe, 0x45, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x45, + 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x8b, 0x06, 0xff, 0xfe, + 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, + 0xff, 0xd5, 0x06, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, + 0xff, 0x3f, 0x02, 0x00, 0xff, 0x3f, 0x06, 0xff, 0xff, 0xa3, 0x04, 0x00, + 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, + 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, + 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, + 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf1, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, + 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, + 0x08, 0x3f, 0xff, 0x55, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, + 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, + 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x45, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x45, + 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, + 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x0b, 0x00, 0xfc, 0x0a, + 0x55, 0xa3, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0xa3, 0x55, 0x0a, 0x08, 0x00}; +static const Image confirm_icon_image = {22, 18, sizeof(confirm_icon_data), + confirm_icon_data}; +const AnimationFrame confirm_icon_frame = {233, 4, 20, 100, + &confirm_icon_image}; /* --- Confirming Animation ------------------------------------------------ */ -static const uint8_t confirming_1_data[240] = -{ - 0x32, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x49, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x6c, 0x06, 0xff, 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x56, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, 0xff, 0xd5, 0x06, 0xff, 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, 0x08, 0x22, 0xff, 0x59, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, 0x10, 0xff, 0xff, 0x56, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x32, 0x00 -}; -static const Image confirming_1_image = {22, 22, sizeof(confirming_1_data), confirming_1_data}; - -static const uint8_t confirming_2_data[240] = -{ - 0x32, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x49, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x6c, 0x06, 0xff, 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x56, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, 0xff, 0xd5, 0x06, 0xff, 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, 0x08, 0x22, 0xff, 0x59, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, 0x10, 0xff, 0xff, 0x56, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x32, 0x00 -}; -static const Image confirming_2_image = {22, 22, sizeof(confirming_2_data), confirming_2_data}; - -static const uint8_t confirming_3_data[248] = -{ - 0x32, 0x00, 0xf6, 0x05, 0x56, 0x97, 0xd5, 0xfa, 0x0f, 0xd5, 0x97, 0x56, 0x05, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0xff, 0x0f, 0x03, 0xff, 0xfe, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x05, 0xff, 0xff, 0x0f, 0x04, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0xfe, 0xfa, 0x0f, 0x05, 0xff, 0xfe, 0xd5, 0x49, 0x05, 0x00, 0xfe, 0x05, 0xa3, 0x06, 0xff, 0xfe, 0x6c, 0x05, 0x06, 0xff, 0xfe, 0xa3, 0x05, 0x04, 0x00, 0xff, 0x56, 0x06, 0xff, 0xfc, 0xd5, 0x05, 0x00, 0xd5, 0x06, 0xff, 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x12, 0x04, 0x00, 0xfe, 0x12, 0xe3, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, 0x08, 0x33, 0xff, 0x59, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, 0x10, 0xff, 0xff, 0x56, 0x04, 0x00, 0xfe, 0x05, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x05, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x05, 0x56, 0x97, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0x97, 0x56, 0x05, 0x32, 0x00 -}; -static const Image confirming_3_image = {22, 22, sizeof(confirming_3_data), confirming_3_data}; - -static const uint8_t confirming_4_data[251] = -{ - 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x97, 0xd5, 0xf1, 0x02, 0x0e, 0xfd, 0x97, 0x55, 0x0a, 0x0b, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x02, 0x0e, 0x02, 0xff, 0xfe, 0xa3, 0x41, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x02, 0x0e, 0x03, 0xff, 0xfe, 0xd5, 0x55, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x02, 0x0e, 0x04, 0xff, 0xfe, 0xd5, 0x41, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfd, 0x6b, 0x0a, 0x0e, 0x05, 0xff, 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x04, 0x00, 0xd5, 0x06, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x41, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0e, 0x04, 0x00, 0xfe, 0x0e, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x55, 0x0a, 0x32, 0x00 -}; -static const Image confirming_4_image = {22, 22, sizeof(confirming_4_data), confirming_4_data}; - -static const uint8_t confirming_5_data[252] = -{ - 0x32, 0x00, 0xfb, 0x0a, 0x57, 0x97, 0xd5, 0xfa, 0x02, 0x0e, 0xfd, 0x0a, 0x33, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x03, 0x0e, 0xfd, 0xff, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x03, 0x0e, 0x02, 0xff, 0xfe, 0xd5, 0x57, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x02, 0x0e, 0xff, 0x97, 0x03, 0xff, 0xfe, 0xd5, 0x49, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfd, 0x70, 0x0a, 0x0e, 0x05, 0xff, 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x05, 0x00, 0x0e, 0x06, 0xff, 0xff, 0x57, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x20, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x0e, 0x04, 0x00, 0xfe, 0x0e, 0xe3, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x57, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x57, 0x08, 0x33, 0xff, 0x57, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x57, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, 0x57, 0x97, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0x97, 0x57, 0x0a, 0x32, 0x00 -}; -static const Image confirming_5_image = {22, 22, sizeof(confirming_5_data), confirming_5_data}; - -static const uint8_t confirming_6_data[249] = -{ - 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x99, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x0a, 0x05, 0x0c, 0x00, 0xfe, 0x45, 0xa6, 0x04, 0xff, 0x04, 0x10, 0xfe, 0xa6, 0x45, 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x04, 0x10, 0xfd, 0xff, 0xe0, 0x55, 0x07, 0x00, 0xfe, 0x45, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x02, 0x10, 0x03, 0xff, 0xfe, 0xe0, 0x45, 0x05, 0x00, 0xfe, 0x0a, 0xa6, 0x06, 0xff, 0xfe, 0x6b, 0x0a, 0x02, 0x10, 0x04, 0xff, 0xfe, 0xa6, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xe0, 0x05, 0x00, 0x0e, 0x06, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x3d, 0x02, 0x00, 0xff, 0x05, 0x06, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xa6, 0x05, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x3d, 0xff, 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa6, 0x0e, 0xff, 0xfe, 0xa6, 0x0a, 0x05, 0x00, 0xfe, 0x45, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x45, 0x07, 0x00, 0xfe, 0x55, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x45, 0xa6, 0x08, 0xff, 0xfe, 0xa6, 0x45, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x99, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0x99, 0x55, 0x0a, 0x32, 0x00 -}; -static const Image confirming_6_image = {22, 22, sizeof(confirming_6_data), confirming_6_data}; - -static const uint8_t confirming_7_data[249] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x55, 0x8c, 0xc2, 0xf1, 0x10, 0x0d, 0x0a, 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xa4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x41, 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0xe0, 0x55, 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xff, 0xfa, 0x04, 0x10, 0x02, 0xff, 0xfe, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x0a, 0xa4, 0x06, 0xff, 0xfe, 0x8c, 0x0a, 0x02, 0x10, 0xff, 0xa4, 0x03, 0xff, 0xfe, 0xa4, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfb, 0xe0, 0x05, 0x00, 0x0d, 0x10, 0x05, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x8c, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x05, 0x06, 0xff, 0xff, 0x8c, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa4, 0x04, 0x00, 0xff, 0xa4, 0x05, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, 0x5e, 0x06, 0x00, 0xff, 0x5e, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0x8c, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x5e, 0x03, 0xff, 0xff, 0x8c, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa4, 0x0e, 0xff, 0xfe, 0xa4, 0x0a, 0x05, 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa4, 0x08, 0xff, 0xfe, 0xa4, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x8c, 0xc2, 0x02, 0xf1, 0xfc, 0xc2, 0x8c, 0x55, 0x0a, 0x32, 0x00 -}; -static const Image confirming_7_image = {22, 22, sizeof(confirming_7_data), confirming_7_data}; - -static const uint8_t confirming_8_data[249] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x55, 0xa3, 0xc2, 0xf7, 0x0e, 0x0c, 0x09, 0x04, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, 0x09, 0x00, 0xfe, 0x59, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x59, 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x04, 0x10, 0xfd, 0xff, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x09, 0x03, 0x10, 0x03, 0xff, 0xfe, 0xa3, 0x09, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfa, 0xe0, 0x09, 0x00, 0x0e, 0x10, 0x59, 0x04, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xfe, 0x04, 0x10, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x59, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x59, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, 0x59, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x59, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x55, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x55, 0x09, 0x32, 0x00 -}; -static const Image confirming_8_image = {22, 22, sizeof(confirming_8_data), confirming_8_data}; - -static const uint8_t confirming_9_data[249] = -{ - 0x32, 0x00, 0xfb, 0x0b, 0x57, 0x97, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x0b, 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, 0x09, 0x00, 0xfe, 0x57, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, 0x05, 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, 0xfe, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, 0x6c, 0x05, 0x04, 0x10, 0x02, 0xff, 0xfe, 0xa3, 0x0b, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xe0, 0x05, 0x00, 0x0e, 0x02, 0x10, 0x04, 0xff, 0xff, 0x57, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xfe, 0x05, 0x10, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x13, 0x04, 0x00, 0xfe, 0x13, 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x57, 0x08, 0x33, 0xff, 0x57, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x0b, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0b, 0x05, 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, 0x57, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x0b, 0x57, 0x97, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0x97, 0x57, 0x0b, 0x32, 0x00 -}; -static const Image confirming_9_image = {22, 22, sizeof(confirming_9_data), confirming_9_data}; - -static const uint8_t confirming_10_data[249] = -{ - 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x99, 0xc7, 0xee, 0x02, 0x0e, 0xfe, 0x0a, 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x05, 0x09, 0x00, 0xfe, 0x55, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, 0x05, 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, 0xfe, 0x0e, 0x22, 0x05, 0x00, 0xfe, 0x0a, 0xb1, 0x06, 0xff, 0xfe, 0x6b, 0x0a, 0x05, 0x10, 0xfd, 0xee, 0xb1, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xdf, 0x05, 0x00, 0x0e, 0x03, 0x10, 0x03, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x05, 0x02, 0x10, 0x04, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x0a, 0x05, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xfe, 0xee, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xee, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x0a, 0x05, 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, 0xdf, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, 0x08, 0xff, 0xfe, 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x99, 0xc7, 0x02, 0xee, 0xfc, 0xc7, 0x99, 0x55, 0x0a, 0x32, 0x00 -}; -static const Image confirming_10_image = {22, 22, sizeof(confirming_10_data), confirming_10_data}; - -static const uint8_t confirming_11_data[246] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x55, 0x99, 0xc7, 0xee, 0x10, 0x0d, 0x09, 0x04, 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x09, 0x04, 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xb1, 0x06, 0xff, 0xfe, 0x6b, 0x09, 0x06, 0x10, 0x02, 0x09, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xe0, 0x09, 0x00, 0x0d, 0x04, 0x10, 0xfd, 0xee, 0xff, 0x55, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x03, 0x10, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xfe, 0x09, 0xee, 0x04, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xfe, 0xee, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xee, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x09, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, 0x08, 0xff, 0xfe, 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x55, 0x99, 0xc7, 0x02, 0xee, 0xfc, 0xc7, 0x99, 0x55, 0x09, 0x32, 0x00 -}; -static const Image confirming_11_image = {22, 22, sizeof(confirming_11_data), confirming_11_data}; - -static const uint8_t confirming_12_data[244] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x09, 0x04, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x09, 0x04, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x8a, 0x09, 0x06, 0x10, 0xff, 0x09, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x09, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x04, 0x10, 0x02, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xfe, 0x09, 0x10, 0x04, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xe3, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x5e, 0x06, 0x00, 0xff, 0x5e, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x5e, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x55, 0x09, 0x32, 0x00 -}; -static const Image confirming_12_image = {22, 22, sizeof(confirming_12_data), confirming_12_data}; - -static const uint8_t confirming_13_data[245] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x55, 0x97, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x6b, 0x08, 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x05, 0x10, 0xfe, 0x22, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x08, 0x02, 0x10, 0xff, 0xa3, 0x02, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0xe3, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0x97, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0x97, 0x55, 0x08, 0x32, 0x00 -}; -static const Image confirming_13_image = {22, 22, sizeof(confirming_13_data), confirming_13_data}; - -static const uint8_t confirming_14_data[241] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x8a, 0x08, 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x04, 0x10, 0xfe, 0x8a, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0x10, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x55, 0x08, 0x32, 0x00 -}; -static const Image confirming_14_image = {22, 22, sizeof(confirming_14_data), confirming_14_data}; - -static const uint8_t confirming_15_data[240] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x45, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, 0x07, 0x00, 0xfe, 0x45, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x7a, 0x08, 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x45, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0x03, 0x10, 0xfd, 0xa3, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x59, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x27, 0xff, 0x59, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x45, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x45, 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x55, 0x08, 0x32, 0x00 -}; -static const Image confirming_15_image = {22, 22, sizeof(confirming_15_data), confirming_15_data}; - -static const uint8_t confirming_16_data[236] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x03, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x57, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x08, 0x22, 0xff, 0x57, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x57, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, 0x57, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x57, 0x0a, 0x32, 0x00 -}; -static const Image confirming_16_image = {22, 22, sizeof(confirming_16_data), confirming_16_data}; - -static const uint8_t confirming_17_data[234] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x55, 0x99, 0xc7, 0xfa, 0x10, 0x0d, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xb1, 0x06, 0xff, 0xfe, 0x6b, 0x08, 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x08, 0x05, 0x10, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, 0x08, 0xff, 0xfe, 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0x99, 0xc7, 0x02, 0xfa, 0xfc, 0xc7, 0x99, 0x55, 0x08, 0x32, 0x00 -}; -static const Image confirming_17_image = {22, 22, sizeof(confirming_17_data), confirming_17_data}; - -static const uint8_t confirming_18_data[241] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x4e, 0xa3, 0xd5, 0xfa, 0x0e, 0x0c, 0x08, 0x03, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x03, 0x09, 0x00, 0xfe, 0x4e, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x08, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x4e, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x4e, 0x06, 0x00, 0xff, 0x08, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xfb, 0xc2, 0xff, 0xa3, 0x41, 0x0e, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x4e, 0x08, 0x41, 0xff, 0x4e, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x4e, 0x10, 0xff, 0xff, 0x4e, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x4e, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x4e, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x4e, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x4e, 0x08, 0x32, 0x00 -}; -static const Image confirming_18_image = {22, 22, sizeof(confirming_18_data), confirming_18_data}; - -static const uint8_t confirming_19_data[242] = -{ - 0x32, 0x00, 0xf7, 0x08, 0x57, 0xa3, 0xc2, 0xf7, 0x0e, 0x0c, 0x08, 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x7a, 0x08, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xdf, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0x22, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x08, 0x41, 0xff, 0x57, 0x02, 0xff, 0xfe, 0xc2, 0x22, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, 0xdf, 0x41, 0x07, 0x00, 0xfe, 0x57, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x57, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x57, 0x08, 0x32, 0x00 -}; -static const Image confirming_19_image = {22, 22, sizeof(confirming_19_data), confirming_19_data}; - -static const uint8_t confirming_20_data[243] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x57, 0xa3, 0xd5, 0xfa, 0x0e, 0x0c, 0x09, 0x04, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x7a, 0x09, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x09, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x04, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xbc, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x08, 0x41, 0xfe, 0x57, 0xa3, 0x02, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x57, 0x0f, 0xff, 0xfe, 0xfa, 0x22, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x57, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x57, 0x09, 0x32, 0x00 -}; -static const Image confirming_20_image = {22, 22, sizeof(confirming_20_data), confirming_20_data}; - -static const uint8_t confirming_21_data[242] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x51, 0xa3, 0xd5, 0xea, 0x0e, 0x0c, 0x0a, 0x03, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x03, 0x09, 0x00, 0xfe, 0x51, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x03, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x51, 0x06, 0xff, 0xfc, 0xd5, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x51, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x51, 0x08, 0x41, 0xff, 0x22, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x51, 0x0e, 0xff, 0xfd, 0x51, 0x10, 0x03, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x03, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x51, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x51, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x51, 0xa3, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xa3, 0x51, 0x0a, 0x32, 0x00 -}; -static const Image confirming_21_image = {22, 22, sizeof(confirming_21_data), confirming_21_data}; - -static const uint8_t confirming_22_data[245] = -{ - 0x32, 0x00, 0xfb, 0x0b, 0x55, 0xa3, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x07, 0x03, 0x0c, 0x00, 0xfe, 0x45, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x03, 0x09, 0x00, 0xfe, 0x55, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, 0x07, 0x07, 0x00, 0xfe, 0x45, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, 0xfe, 0x0e, 0x03, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x3f, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0b, 0x05, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x07, 0x3f, 0xfe, 0x22, 0x07, 0x03, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x55, 0x0d, 0xff, 0x03, 0x10, 0xff, 0x03, 0x04, 0x00, 0xfe, 0x0b, 0xa3, 0x0d, 0xff, 0xfe, 0x78, 0x0b, 0x06, 0x00, 0xfe, 0x45, 0xdf, 0x0c, 0xff, 0xfe, 0xdf, 0x3f, 0x07, 0x00, 0xfe, 0x55, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x55, 0x09, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x0b, 0x00, 0xfc, 0x0b, 0x55, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x55, 0x0b, 0x32, 0x00 -}; -static const Image confirming_22_image = {22, 22, sizeof(confirming_22_data), confirming_22_data}; - -static const uint8_t confirming_23_data[238] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x57, 0xa3, 0xc2, 0xf7, 0x10, 0x0d, 0x09, 0x06, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x02, 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xff, 0xf7, 0x06, 0x10, 0xfe, 0x0d, 0x02, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x09, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xdf, 0x06, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x06, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x02, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x06, 0x05, 0x10, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x07, 0x41, 0xfe, 0x02, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x57, 0x0c, 0xff, 0x04, 0x10, 0xff, 0x06, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0c, 0xff, 0xfd, 0x41, 0x10, 0x0b, 0x06, 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, 0x78, 0x02, 0x07, 0x00, 0xfe, 0x57, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x57, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x57, 0x09, 0x32, 0x00 -}; -static const Image confirming_23_image = {22, 22, sizeof(confirming_23_data), confirming_23_data}; - -static const uint8_t confirming_24_data[250] = -{ - 0x32, 0x00, 0xf7, 0x09, 0x4e, 0xa3, 0xc6, 0xea, 0x0e, 0x0d, 0x09, 0x06, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x02, 0x09, 0x00, 0xfe, 0x4e, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x02, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x09, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x4e, 0x06, 0xff, 0xfc, 0xc6, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x06, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x02, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x4e, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x4e, 0x06, 0x41, 0xfd, 0x0e, 0x02, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x4e, 0x0b, 0xff, 0xff, 0x41, 0x04, 0x10, 0xff, 0x06, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0b, 0xff, 0xff, 0x41, 0x02, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, 0x41, 0xc6, 0x0b, 0xff, 0xfd, 0x4e, 0x0d, 0x02, 0x07, 0x00, 0xfe, 0x4e, 0xc6, 0x0a, 0xff, 0xfe, 0xc6, 0x10, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x4e, 0xa3, 0xc6, 0x02, 0xea, 0xfc, 0xc6, 0xa3, 0x4e, 0x09, 0x32, 0x00 -}; -static const Image confirming_24_image = {22, 22, sizeof(confirming_24_data), confirming_24_data}; - -static const uint8_t confirming_25_data[249] = -{ - 0x32, 0x00, 0xf7, 0x0b, 0x55, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x08, 0x05, 0x0c, 0x00, 0xfe, 0x4c, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, 0x09, 0x00, 0xfe, 0x55, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x4c, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xc6, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x4c, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0b, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x06, 0x2a, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x55, 0x0b, 0xff, 0x05, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0b, 0xa3, 0x0a, 0xff, 0xff, 0xc6, 0x03, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, 0x4c, 0xc6, 0x0a, 0xff, 0xfc, 0x55, 0x10, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x55, 0xc6, 0x0a, 0xff, 0xfe, 0x10, 0x05, 0x09, 0x00, 0xfe, 0x4c, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x4c, 0x0b, 0x00, 0xfc, 0x0b, 0x55, 0xa3, 0xc6, 0x02, 0xea, 0xfc, 0xc6, 0xa3, 0x55, 0x0b, 0x32, 0x00 -}; -static const Image confirming_25_image = {22, 22, sizeof(confirming_25_data), confirming_25_data}; - -static const uint8_t confirming_26_data[252] = -{ - 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xd5, 0xea, 0x0e, 0x0c, 0x08, 0x05, 0x0c, 0x00, 0xfe, 0x49, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x79, 0x08, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, 0x06, 0x22, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x57, 0x0a, 0xff, 0xff, 0x22, 0x05, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0b, 0xb4, 0x0a, 0xff, 0x04, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, 0x49, 0xd5, 0x09, 0xff, 0xff, 0xb4, 0x02, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x09, 0xff, 0xfd, 0x22, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x49, 0xb4, 0x08, 0xff, 0xfe, 0xb4, 0x05, 0x0b, 0x00, 0xfc, 0x0b, 0x57, 0xb4, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xb4, 0x57, 0x0b, 0x32, 0x00 -}; -static const Image confirming_26_image = {22, 22, sizeof(confirming_26_data), confirming_26_data}; - -static const uint8_t confirming_27_data[254] = -{ - 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xd5, 0xea, 0x0e, 0x0c, 0x08, 0x05, 0x0c, 0x00, 0xfe, 0x4d, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x4d, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, 0x06, 0xff, 0xff, 0x4d, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, 0x05, 0x27, 0xff, 0x10, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x57, 0x0a, 0xff, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0b, 0xb4, 0x09, 0xff, 0xff, 0x4d, 0x04, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, 0x4d, 0xd5, 0x09, 0xff, 0x03, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x08, 0xff, 0xfc, 0x4d, 0x10, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x4d, 0xb4, 0x07, 0xff, 0xfd, 0xea, 0x0b, 0x05, 0x0b, 0x00, 0xfc, 0x0b, 0x57, 0xb4, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xb4, 0x57, 0x02, 0x32, 0x00 -}; -static const Image confirming_27_image = {22, 22, sizeof(confirming_27_data), confirming_27_data}; - -static const uint8_t confirming_28_data[254] = -{ - 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xe3, 0xfa, 0x0e, 0x0c, 0x08, 0x05, 0x0c, 0x00, 0xfe, 0x57, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xe3, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x57, 0xe3, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xe3, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xe3, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xe3, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, 0x05, 0x2b, 0x03, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x57, 0x09, 0xff, 0xff, 0xb4, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0b, 0xb4, 0x09, 0xff, 0x05, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, 0x57, 0xe3, 0x08, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xe3, 0x07, 0xff, 0xff, 0xb4, 0x02, 0x10, 0xfe, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x57, 0xb4, 0x07, 0xff, 0xfd, 0x10, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x0b, 0x57, 0xb4, 0xe3, 0x02, 0xfa, 0xfd, 0xe3, 0xb4, 0x10, 0x33, 0x00 -}; -static const Image confirming_28_image = {22, 22, sizeof(confirming_28_data), confirming_28_data}; - -static const uint8_t confirming_29_data[255] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x4d, 0x99, 0xbc, 0xf7, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x4d, 0xbc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x4d, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x4d, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xbc, 0x06, 0xff, 0xfe, 0x6b, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x4d, 0x06, 0xff, 0xfc, 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x4d, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xbc, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x4d, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xbc, 0x03, 0xff, 0xff, 0xbc, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x4d, 0x05, 0x27, 0x03, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x4d, 0x09, 0xff, 0x07, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xbc, 0x08, 0xff, 0xff, 0x4d, 0x05, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x4d, 0xdf, 0x07, 0xff, 0xff, 0xdf, 0x04, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x4d, 0xdf, 0x07, 0xff, 0x03, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x4d, 0xbc, 0x06, 0xff, 0x02, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x0a, 0x4d, 0x99, 0xbc, 0x02, 0xf7, 0xfd, 0xbc, 0x27, 0x04, 0x33, 0x00 -}; -static const Image confirming_29_image = {22, 22, sizeof(confirming_29_data), confirming_29_data}; - -static const uint8_t confirming_30_data[261] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xc6, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x04, 0x41, 0xff, 0x22, 0x03, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x08, 0xff, 0xff, 0xa3, 0x07, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x07, 0xff, 0xff, 0xa3, 0x06, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0xa3, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0xff, 0xa3, 0x03, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xc6, 0xea, 0xa3, 0x0c, 0x0a, 0x04, 0x33, 0x00 -}; -static const Image confirming_30_image = {22, 22, sizeof(confirming_30_data), confirming_30_data}; - -static const uint8_t confirming_31_data[252] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x49, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xc6, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x08, 0xff, 0x08, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x07, 0xff, 0x07, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x49, 0xc6, 0x06, 0xff, 0x06, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x03, 0xff, 0xff, 0xea, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfd, 0x0a, 0x57, 0xa3, 0x02, 0xc6, 0xfc, 0x0e, 0x0c, 0x0a, 0x04, 0x33, 0x00 -}; -static const Image confirming_31_image = {22, 22, sizeof(confirming_31_data), confirming_31_data}; - -static const uint8_t confirming_32_data[256] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x55, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x3c, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x55, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x3c, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd1, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, 0xff, 0xff, 0x3c, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x55, 0x04, 0x3c, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x08, 0xff, 0x08, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xff, 0xea, 0x07, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x3c, 0xd1, 0x05, 0xff, 0xff, 0x78, 0x06, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x55, 0xd1, 0x04, 0xff, 0xff, 0x19, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x3c, 0xa9, 0x03, 0xff, 0x05, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfe, 0x0a, 0x55, 0x02, 0xa9, 0x02, 0x0e, 0xfd, 0x0c, 0x0a, 0x04, 0x33, 0x00 -}; -static const Image confirming_32_image = {22, 22, sizeof(confirming_32_data), confirming_32_data}; - -static const uint8_t confirming_33_data[257] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xb4, 0xdf, 0xf7, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x49, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x49, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xb4, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xb4, 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xdf, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xdf, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x07, 0xff, 0xff, 0xb4, 0x08, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xb4, 0x06, 0xff, 0x08, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x49, 0xdf, 0x05, 0xff, 0x07, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xdf, 0x03, 0xff, 0xff, 0xb4, 0x06, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x49, 0xb4, 0x02, 0xff, 0xff, 0x22, 0x05, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x0a, 0x57, 0x78, 0x0c, 0x02, 0x0e, 0xfd, 0x0c, 0x0a, 0x04, 0x33, 0x00 -}; -static const Image confirming_33_image = {22, 22, sizeof(confirming_33_data), confirming_33_data}; - -static const uint8_t confirming_34_data[256] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x56, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, 0x0c, 0x00, 0xfe, 0x47, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x56, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x47, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x56, 0x06, 0xff, 0xfc, 0xd1, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, 0xff, 0xff, 0x47, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x56, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x56, 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x56, 0x07, 0xff, 0x09, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa9, 0x05, 0xff, 0xff, 0xea, 0x08, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x47, 0xd1, 0x04, 0xff, 0xff, 0x22, 0x07, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x56, 0xd1, 0x02, 0xff, 0xff, 0xea, 0x07, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfc, 0x47, 0xa9, 0xff, 0x56, 0x06, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x0a, 0x56, 0x0a, 0x0c, 0x02, 0x0e, 0xfd, 0x0c, 0x0a, 0x04, 0x33, 0x00 -}; -static const Image confirming_34_image = {22, 22, sizeof(confirming_34_data), confirming_34_data}; - -static const uint8_t confirming_35_data[251] = -{ - 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x09, 0x04, 0x0c, 0x00, 0xfe, 0x33, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x33, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd1, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x57, 0x03, 0x33, 0x05, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x57, 0x07, 0xff, 0x09, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa9, 0x05, 0xff, 0x09, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x33, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xd1, 0x02, 0xff, 0x08, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfd, 0x33, 0xa9, 0x78, 0x07, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x07, 0x04, 0x09, 0x0c, 0x02, 0x0e, 0xfd, 0x0c, 0x09, 0x04, 0x33, 0x00 -}; -static const Image confirming_35_image = {22, 22, sizeof(confirming_35_data), confirming_35_data}; - -static const uint8_t confirming_36_data[256] = -{ - 0x32, 0x00, 0xf6, 0x0a, 0x57, 0xa8, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, 0x01, 0x0b, 0x00, 0xfe, 0x57, 0xa8, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x57, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x57, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa8, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd1, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa8, 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa8, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa8, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa8, 0x03, 0xff, 0xff, 0x57, 0x03, 0x2b, 0x05, 0x03, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0x0a, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa8, 0x04, 0xff, 0xff, 0xa8, 0x09, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x57, 0xd1, 0x02, 0xff, 0xff, 0xea, 0x09, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfd, 0x57, 0xd1, 0xff, 0x09, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x57, 0x2b, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x04, 0x0a, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x0a, 0x04, 0x01, 0x32, 0x00 -}; -static const Image confirming_36_image = {22, 22, sizeof(confirming_36_data), confirming_36_data}; - -static const uint8_t confirming_37_data[255] = -{ - 0x32, 0x00, 0xf6, 0x0a, 0x55, 0xa3, 0xc7, 0xf3, 0x0e, 0x0c, 0x0a, 0x04, 0x01, 0x0b, 0x00, 0xfe, 0x55, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x55, 0xc7, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x07, 0x00, 0xfe, 0x55, 0xc7, 0x05, 0xff, 0xfe, 0xf3, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xc7, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xfe, 0xf3, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x03, 0x2b, 0x05, 0x03, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x05, 0xff, 0xff, 0xf3, 0x0a, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x03, 0xff, 0xff, 0xf3, 0x0a, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfc, 0x55, 0xc7, 0xff, 0xf3, 0x0a, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x55, 0xc7, 0x0a, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0x02, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x04, 0x0a, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x0a, 0x04, 0x01, 0x32, 0x00 -}; -static const Image confirming_37_image = {22, 22, sizeof(confirming_37_data), confirming_37_data}; - -static const uint8_t confirming_38_data[249] = -{ - 0x32, 0x00, 0xff, 0x0a, 0x02, 0x78, 0xf9, 0xc0, 0xea, 0x0e, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x33, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x78, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x33, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xc0, 0x06, 0xff, 0xfe, 0x78, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x78, 0x06, 0xff, 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x78, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x78, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x78, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x78, 0x03, 0xff, 0x03, 0x33, 0x06, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x78, 0x05, 0xff, 0x0b, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0a, 0xc0, 0x03, 0xff, 0x0b, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfd, 0x33, 0xea, 0xc0, 0x0b, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x33, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_38_image = {22, 22, sizeof(confirming_38_data), confirming_38_data}; - -static const uint8_t confirming_39_data[252] = -{ - 0x32, 0x00, 0xfe, 0x0a, 0x76, 0x02, 0xb5, 0xfa, 0xe9, 0x0e, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x33, 0xb5, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x76, 0xe9, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x33, 0xe9, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xb5, 0x06, 0xff, 0xfe, 0x76, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x76, 0x06, 0xff, 0xfc, 0xe9, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb5, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xb5, 0x05, 0xff, 0xff, 0xb5, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xe9, 0x04, 0xff, 0xfe, 0xe9, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xe9, 0x04, 0xff, 0xff, 0x76, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xb5, 0x03, 0xff, 0xff, 0xb5, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xb5, 0x03, 0xff, 0xff, 0x76, 0x02, 0x33, 0x06, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x76, 0x04, 0xff, 0xff, 0x33, 0x0b, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfc, 0x0a, 0xb5, 0xff, 0xe9, 0x0c, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x33, 0x76, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_39_image = {22, 22, sizeof(confirming_39_data), confirming_39_data}; - -static const uint8_t confirming_40_data[248] = -{ - 0x32, 0x00, 0xf6, 0x0a, 0x34, 0x79, 0xbc, 0xea, 0x0e, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xbc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x79, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xbc, 0x06, 0xff, 0xfe, 0x79, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x79, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xbc, 0x05, 0xff, 0xff, 0xbc, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x79, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xbc, 0x03, 0xff, 0xff, 0xbc, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x79, 0x03, 0xff, 0x02, 0x34, 0x07, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x34, 0x02, 0xff, 0xff, 0xea, 0x0d, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfd, 0x0a, 0xbc, 0x79, 0x0d, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_40_image = {22, 22, sizeof(confirming_40_data), confirming_40_data}; - -static const uint8_t confirming_41_data[245] = -{ - 0x32, 0x00, 0xf6, 0x0a, 0x34, 0x7a, 0xc0, 0xea, 0x0e, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x7a, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xc0, 0x06, 0xff, 0xfe, 0x7a, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x7a, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x7a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x7a, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x7a, 0x03, 0xff, 0xff, 0x34, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xfd, 0x34, 0xea, 0x7a, 0x0e, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x03, 0x0a, 0x0e, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_41_image = {22, 22, sizeof(confirming_41_data), confirming_41_data}; - -static const uint8_t confirming_42_data[243] = -{ - 0x32, 0x00, 0xf6, 0x09, 0x34, 0x81, 0xc0, 0xea, 0x0e, 0x0d, 0x09, 0x04, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x34, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xc0, 0x06, 0xff, 0xfe, 0x81, 0x09, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, 0xfc, 0xea, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0x81, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x81, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x34, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xfb, 0x81, 0xff, 0xc0, 0x34, 0x04, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x10, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x04, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x04, 0x01, 0x32, 0x00 -}; -static const Image confirming_42_image = {22, 22, sizeof(confirming_42_data), confirming_42_data}; - -static const uint8_t confirming_43_data[244] = -{ - 0x32, 0x00, 0xf6, 0x09, 0x34, 0x82, 0xca, 0xf3, 0x0e, 0x0c, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xca, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x34, 0xca, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xca, 0x05, 0xff, 0xfe, 0xf3, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xca, 0x06, 0xff, 0xfe, 0x82, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, 0xfc, 0xca, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x82, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xca, 0x05, 0xff, 0xff, 0x82, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xfe, 0xf3, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xff, 0x34, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xfb, 0xca, 0xff, 0xf3, 0xca, 0x34, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x0e, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0c, 0x0c, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0c, 0x0a, 0x10, 0xfe, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_43_image = {22, 22, sizeof(confirming_43_data), confirming_43_data}; - -static const uint8_t confirming_44_data[241] = -{ - 0x32, 0x00, 0xf6, 0x09, 0x34, 0x7a, 0xc0, 0xea, 0x0e, 0x0c, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x7a, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xc0, 0x06, 0xff, 0xfe, 0x7a, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, 0xfc, 0xea, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x7a, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x7a, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x7a, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0x04, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0c, 0x0c, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0c, 0x0a, 0x10, 0xfe, 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_44_image = {22, 22, sizeof(confirming_44_data), confirming_44_data}; - -static const uint8_t confirming_45_data[239] = -{ - 0x32, 0x00, 0xff, 0x09, 0x02, 0x6e, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x27, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x6e, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x27, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, 0x6e, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x6e, 0x06, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x6e, 0x06, 0xff, 0xff, 0x27, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xcc, 0x05, 0xff, 0xff, 0x6e, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0x06, 0xff, 0xff, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0x05, 0x27, 0xff, 0x0b, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_45_image = {22, 22, sizeof(confirming_45_data), confirming_45_data}; - -static const uint8_t confirming_46_data[246] = -{ - 0x32, 0x00, 0xff, 0x09, 0x02, 0x76, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x30, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x76, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x30, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, 0x76, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x76, 0x06, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x76, 0x06, 0xff, 0xff, 0x30, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0xcc, 0x05, 0xff, 0xff, 0x76, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0x02, 0x30, 0xfe, 0x76, 0xcc, 0x02, 0xff, 0xff, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_46_image = {22, 22, sizeof(confirming_46_data), confirming_46_data}; - -static const uint8_t confirming_47_data[245] = -{ - 0x32, 0x00, 0xff, 0x09, 0x02, 0x78, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x78, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, 0x78, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x78, 0x06, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x78, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xfe, 0x10, 0x78, 0x04, 0xff, 0xff, 0x78, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xfe, 0x78, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_47_image = {22, 22, sizeof(confirming_47_data), confirming_47_data}; - -static const uint8_t confirming_48_data[247] = -{ - 0x32, 0x00, 0xfe, 0x09, 0x59, 0x02, 0xcc, 0xfa, 0xff, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x59, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x59, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x59, 0xcc, 0x06, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, 0x59, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x59, 0x06, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0f, 0x59, 0x05, 0xff, 0xff, 0x59, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xfd, 0xcc, 0xff, 0xcc, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_48_image = {22, 22, sizeof(confirming_48_data), confirming_48_data}; - -static const uint8_t confirming_49_data[250] = -{ - 0x32, 0x00, 0xff, 0x09, 0x02, 0x6a, 0xf9, 0xcc, 0xff, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x6a, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x6a, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x6a, 0xcc, 0x06, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, 0x6a, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xfe, 0x05, 0x6a, 0x05, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x02, 0x10, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x10, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x04, 0x10, 0xfe, 0x6a, 0xcc, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_49_image = {22, 22, sizeof(confirming_49_data), confirming_49_data}; - -static const uint8_t confirming_50_data[250] = -{ - 0x32, 0x00, 0xfe, 0x0a, 0x4e, 0x02, 0xca, 0xfa, 0xff, 0x0f, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x4e, 0xca, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x4e, 0xca, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x4e, 0xca, 0x06, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x4e, 0x06, 0xff, 0xfe, 0x4e, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x02, 0x10, 0xff, 0xca, 0x03, 0xff, 0xfc, 0xca, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x04, 0x10, 0x02, 0xff, 0xff, 0x4e, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x4e, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_50_image = {22, 22, sizeof(confirming_50_data), confirming_50_data}; - -static const uint8_t confirming_51_data[251] = -{ - 0x32, 0x00, 0xfe, 0x0a, 0x54, 0x02, 0xd4, 0xfa, 0xff, 0x0f, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x54, 0xd4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x54, 0xd4, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x05, 0xd4, 0x06, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfc, 0x01, 0x0b, 0x10, 0xd4, 0x04, 0xff, 0xfe, 0x54, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x03, 0x10, 0xff, 0x54, 0x02, 0xff, 0xfc, 0xd4, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xfe, 0xff, 0x54, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_51_image = {22, 22, sizeof(confirming_51_data), confirming_51_data}; - -static const uint8_t confirming_52_data[251] = -{ - 0x32, 0x00, 0xfe, 0x0a, 0x53, 0x02, 0xba, 0xfa, 0xff, 0x0f, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x53, 0xba, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x10, 0xba, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfd, 0x04, 0x0d, 0x53, 0x05, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x02, 0x10, 0xff, 0x53, 0x03, 0xff, 0xfe, 0x53, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x04, 0x10, 0xfa, 0x53, 0xff, 0xba, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0x02, 0x53, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_52_image = {22, 22, sizeof(confirming_52_data), confirming_52_data}; - -static const uint8_t confirming_53_data[251] = -{ - 0x32, 0x00, 0xfe, 0x0a, 0x52, 0x02, 0xc8, 0xfa, 0xff, 0x0f, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x52, 0xc8, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x10, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfc, 0x04, 0x0d, 0x10, 0x52, 0x04, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, 0xc8, 0x02, 0xff, 0xfe, 0x52, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x05, 0x10, 0xfb, 0xff, 0xc8, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x06, 0x10, 0xff, 0x52, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_53_image = {22, 22, sizeof(confirming_53_data), confirming_53_data}; - -static const uint8_t confirming_54_data[249] = -{ - 0x32, 0x00, 0xff, 0x0a, 0x02, 0x6d, 0xf9, 0xe2, 0xff, 0x0f, 0x0d, 0x08, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x6d, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfd, 0x06, 0x0d, 0x10, 0x04, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x02, 0x10, 0xff, 0x6d, 0x03, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x04, 0x10, 0x02, 0xff, 0xfe, 0x6d, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0xe2, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x07, 0x10, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_54_image = {22, 22, sizeof(confirming_54_data), confirming_54_data}; - -static const uint8_t confirming_55_data[251] = -{ - 0x32, 0x00, 0xfe, 0x01, 0x10, 0x02, 0xa3, 0xfa, 0xf7, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfd, 0x04, 0x0b, 0xa3, 0x03, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x02, 0x10, 0x03, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfc, 0xa3, 0xff, 0xf7, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x05, 0x10, 0xfd, 0xff, 0xa3, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0xa3, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_55_image = {22, 22, sizeof(confirming_55_data), confirming_55_data}; - -static const uint8_t confirming_56_data[250] = -{ - 0x32, 0x00, 0xfd, 0x01, 0x05, 0x89, 0x02, 0xfb, 0xfb, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfc, 0x04, 0x0b, 0x10, 0x89, 0x02, 0xfb, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x03, 0x10, 0x02, 0xfb, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x04, 0x10, 0x02, 0xfb, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0xfe, 0x89, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0x0d, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_56_image = {22, 22, sizeof(confirming_56_data), confirming_56_data}; - -static const uint8_t confirming_57_data[250] = -{ - 0x32, 0x00, 0xfd, 0x01, 0x05, 0x09, 0x02, 0xf8, 0xfb, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x02, 0x10, 0xfe, 0x6a, 0xf8, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x04, 0x10, 0xff, 0xf8, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x05, 0x10, 0xfe, 0xf8, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0xfe, 0x6a, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0x0d, 0x04, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_57_image = {22, 22, sizeof(confirming_57_data), confirming_57_data}; - -static const uint8_t confirming_58_data[247] = -{ - 0x32, 0x00, 0xf6, 0x01, 0x05, 0x09, 0x0d, 0x86, 0x0f, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x03, 0x10, 0xff, 0x86, 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x04, 0x10, 0xff, 0x86, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x06, 0x10, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0x02, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x0d, 0x02, 0x00, 0xff, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_58_image = {22, 22, sizeof(confirming_58_data), confirming_58_data}; - -static const uint8_t confirming_59_data[240] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x05, 0x10, 0x02, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0x02, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x0d, 0x02, 0x00, 0xff, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_59_image = {22, 22, sizeof(confirming_59_data), confirming_59_data}; - -static const uint8_t confirming_60_data[236] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0x02, 0x0c, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x0f, 0x02, 0x08, 0xff, 0x0f, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x0a, 0x02, 0x08, 0xff, 0x0a, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x08, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x09, 0x04, 0x08, 0xfe, 0x09, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x0b, 0x06, 0x08, 0xff, 0x0b, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0e, 0x08, 0x08, 0xff, 0x0e, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x0a, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_60_image = {22, 22, sizeof(confirming_60_data), confirming_60_data}; - -static const uint8_t confirming_61_data[174] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x10, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x10, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x10, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x10, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x10, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x10, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_61_image = {22, 22, sizeof(confirming_61_data), confirming_61_data}; - -static const uint8_t confirming_62_data[277] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x23, 0x44, 0x10, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x23, 0x5c, 0x44, 0x02, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x23, 0x5c, 0x60, 0x44, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, 0xfe, 0x17, 0x54, 0x02, 0x60, 0xff, 0x44, 0x03, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0x44, 0x03, 0x60, 0xff, 0x54, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x17, 0x23, 0x02, 0x10, 0xff, 0x31, 0x03, 0x60, 0xff, 0x31, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x23, 0x02, 0x54, 0x02, 0x10, 0xff, 0x54, 0x02, 0x60, 0xff, 0x31, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xfd, 0x0d, 0x10, 0x44, 0x03, 0x60, 0x02, 0x31, 0x02, 0x60, 0xff, 0x31, 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xfd, 0x31, 0x5c, 0x60, 0x02, 0x54, 0xfe, 0x60, 0x44, 0x07, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x23, 0x5c, 0x02, 0x60, 0xff, 0x54, 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, 0x23, 0x02, 0x5c, 0xff, 0x17, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x23, 0x31, 0x07, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_62_image = {22, 22, sizeof(confirming_62_data), confirming_62_data}; - -static const uint8_t confirming_63_data[277] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x36, 0x78, 0x10, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x36, 0xa5, 0x78, 0x02, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x36, 0xa5, 0xaf, 0x78, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, 0xfe, 0x1d, 0xa5, 0x02, 0xaf, 0xff, 0x78, 0x03, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0x78, 0x03, 0xaf, 0xff, 0x97, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x1d, 0x36, 0x02, 0x10, 0xff, 0x52, 0x03, 0xaf, 0xff, 0x52, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x36, 0x02, 0x97, 0x02, 0x10, 0xff, 0x97, 0x02, 0xaf, 0xff, 0x52, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xfd, 0x0d, 0x10, 0x78, 0x03, 0xaf, 0x02, 0x52, 0x02, 0xaf, 0xff, 0x52, 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xff, 0x52, 0x02, 0xaf, 0x02, 0x97, 0xfe, 0xaf, 0x78, 0x07, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x36, 0xa5, 0x02, 0xaf, 0xff, 0x97, 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, 0x36, 0x02, 0xa5, 0xff, 0x1d, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x36, 0x52, 0x07, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_63_image = {22, 22, sizeof(confirming_63_data), confirming_63_data}; - -static const uint8_t confirming_64_data[277] = -{ - 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x4a, 0xac, 0x10, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x4a, 0xf0, 0xac, 0x02, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x4a, 0xf0, 0xff, 0xac, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, 0xfe, 0x24, 0xf0, 0x02, 0xff, 0xff, 0xac, 0x03, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0xac, 0x03, 0xff, 0xff, 0xdb, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x24, 0x4a, 0x02, 0x10, 0xff, 0x73, 0x03, 0xff, 0xff, 0x73, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x4a, 0x02, 0xdb, 0x02, 0x10, 0xff, 0xdb, 0x02, 0xff, 0xff, 0x73, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xfd, 0x0d, 0x10, 0xac, 0x03, 0xff, 0x02, 0x73, 0x02, 0xff, 0xff, 0x73, 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xff, 0x73, 0x02, 0xff, 0x02, 0xdb, 0xfe, 0xff, 0xac, 0x07, 0x10, 0xff, 0x07, 0x04, 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x4a, 0xf0, 0x02, 0xff, 0xff, 0xdb, 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, 0x4a, 0x02, 0xf0, 0xff, 0x24, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x4a, 0x73, 0x07, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, 0x00 -}; -static const Image confirming_64_image = {22, 22, sizeof(confirming_64_data), confirming_64_data}; +static const uint8_t confirming_1_data[240] = { + 0x32, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, + 0x56, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, + 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, + 0xfe, 0x49, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x49, + 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x6c, 0x06, 0xff, 0xfe, + 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x56, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, + 0xff, 0xd5, 0x06, 0xff, 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, + 0xff, 0x49, 0x02, 0x00, 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, + 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, + 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, + 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, + 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf1, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, + 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, + 0x08, 0x22, 0xff, 0x59, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, + 0x10, 0xff, 0xff, 0x56, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, + 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, + 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, + 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, + 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x32, 0x00}; +static const Image confirming_1_image = {22, 22, sizeof(confirming_1_data), + confirming_1_data}; + +static const uint8_t confirming_2_data[240] = { + 0x32, 0x00, 0xfc, 0x0a, 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, + 0x56, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, + 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, + 0xfe, 0x49, 0xd5, 0x05, 0xff, 0x02, 0xfa, 0x05, 0xff, 0xfe, 0xd5, 0x49, + 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0x02, 0x6c, 0x06, 0xff, 0xfe, + 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x56, 0x06, 0xff, 0xff, 0xd5, 0x02, 0x04, + 0xff, 0xd5, 0x06, 0xff, 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, + 0xff, 0x49, 0x02, 0x00, 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, + 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, + 0xff, 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0a, 0x04, + 0x00, 0xfe, 0x0a, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, + 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf1, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, + 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, + 0x08, 0x22, 0xff, 0x59, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, + 0x10, 0xff, 0xff, 0x56, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, + 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, + 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, + 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, + 0x56, 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x56, 0x0a, 0x32, 0x00}; +static const Image confirming_2_image = {22, 22, sizeof(confirming_2_data), + confirming_2_data}; + +static const uint8_t confirming_3_data[248] = { + 0x32, 0x00, 0xf6, 0x05, 0x56, 0x97, 0xd5, 0xfa, 0x0f, 0xd5, 0x97, 0x56, + 0x05, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0xff, 0x0f, 0x03, 0xff, + 0xfe, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x05, 0xff, 0xff, 0x0f, + 0x04, 0xff, 0xfe, 0xd5, 0x59, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, + 0xfe, 0xfa, 0x0f, 0x05, 0xff, 0xfe, 0xd5, 0x49, 0x05, 0x00, 0xfe, 0x05, + 0xa3, 0x06, 0xff, 0xfe, 0x6c, 0x05, 0x06, 0xff, 0xfe, 0xa3, 0x05, 0x04, + 0x00, 0xff, 0x56, 0x06, 0xff, 0xfc, 0xd5, 0x05, 0x00, 0xd5, 0x06, 0xff, + 0xff, 0x56, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, + 0xff, 0x49, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, + 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xd5, 0x04, 0x00, + 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x12, 0x04, 0x00, 0xfe, 0x12, 0xe3, + 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x59, + 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, + 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, + 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x56, 0x08, 0x33, 0xff, 0x59, + 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x56, 0x10, 0xff, 0xff, 0x56, + 0x04, 0x00, 0xfe, 0x05, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x05, 0x05, 0x00, + 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x59, + 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, + 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x05, 0x56, 0x97, 0xd5, 0x02, + 0xfa, 0xfc, 0xd5, 0x97, 0x56, 0x05, 0x32, 0x00}; +static const Image confirming_3_image = {22, 22, sizeof(confirming_3_data), + confirming_3_data}; + +static const uint8_t confirming_4_data[251] = { + 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x97, 0xd5, 0xf1, 0x02, 0x0e, 0xfd, 0x97, + 0x55, 0x0a, 0x0b, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x02, 0x0e, 0x02, + 0xff, 0xfe, 0xa3, 0x41, 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x02, + 0x0e, 0x03, 0xff, 0xfe, 0xd5, 0x55, 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, + 0xff, 0xff, 0xfa, 0x02, 0x0e, 0x04, 0xff, 0xfe, 0xd5, 0x41, 0x05, 0x00, + 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfd, 0x6b, 0x0a, 0x0e, 0x05, 0xff, 0xfe, + 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, 0x04, 0x00, + 0xd5, 0x06, 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, + 0x41, 0x02, 0x00, 0xff, 0x41, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, + 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, + 0xd5, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x0e, 0x04, 0x00, + 0xfe, 0x0e, 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, + 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf1, 0x04, + 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, + 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x55, 0x08, + 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x55, 0x10, + 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, + 0x0a, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, + 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, + 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, + 0x97, 0xd5, 0x02, 0xf1, 0xfc, 0xd5, 0x97, 0x55, 0x0a, 0x32, 0x00}; +static const Image confirming_4_image = {22, 22, sizeof(confirming_4_data), + confirming_4_data}; + +static const uint8_t confirming_5_data[252] = { + 0x32, 0x00, 0xfb, 0x0a, 0x57, 0x97, 0xd5, 0xfa, 0x02, 0x0e, 0xfd, 0x0a, + 0x33, 0x0a, 0x0b, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x03, 0x0e, 0xfd, + 0xff, 0xa3, 0x49, 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x03, 0x0e, + 0x02, 0xff, 0xfe, 0xd5, 0x57, 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, + 0xff, 0xfa, 0x02, 0x0e, 0xff, 0x97, 0x03, 0xff, 0xfe, 0xd5, 0x49, 0x05, + 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfd, 0x70, 0x0a, 0x0e, 0x05, 0xff, + 0xfe, 0xa3, 0x0a, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, 0x05, + 0x00, 0x0e, 0x06, 0xff, 0xff, 0x57, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, + 0xff, 0x33, 0x02, 0x00, 0xff, 0x20, 0x06, 0xff, 0xff, 0x97, 0x04, 0x00, + 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, + 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x0e, 0x04, + 0x00, 0xfe, 0x0e, 0xe3, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x57, 0x04, 0xff, 0xff, 0xfa, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, + 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x57, + 0x08, 0x33, 0xff, 0x57, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x57, + 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, + 0xa3, 0x0a, 0x05, 0x00, 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, + 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x57, 0x09, 0x00, + 0xfe, 0x49, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, + 0x57, 0x97, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0x97, 0x57, 0x0a, 0x32, 0x00}; +static const Image confirming_5_image = {22, 22, sizeof(confirming_5_data), + confirming_5_data}; + +static const uint8_t confirming_6_data[249] = { + 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x99, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x0a, + 0x05, 0x0c, 0x00, 0xfe, 0x45, 0xa6, 0x04, 0xff, 0x04, 0x10, 0xfe, 0xa6, + 0x45, 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x04, 0x10, 0xfd, 0xff, + 0xe0, 0x55, 0x07, 0x00, 0xfe, 0x45, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, + 0x02, 0x10, 0x03, 0xff, 0xfe, 0xe0, 0x45, 0x05, 0x00, 0xfe, 0x0a, 0xa6, + 0x06, 0xff, 0xfe, 0x6b, 0x0a, 0x02, 0x10, 0x04, 0xff, 0xfe, 0xa6, 0x0a, + 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xe0, 0x05, 0x00, 0x0e, 0x06, + 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x3d, 0x02, + 0x00, 0xff, 0x05, 0x06, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc2, 0x05, + 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xa6, 0x05, 0xff, 0xff, 0xc2, 0x04, + 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x10, 0x04, 0x00, 0xfe, 0x10, + 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, + 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, + 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, + 0xc2, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x3d, 0xff, + 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, + 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa6, 0x0e, 0xff, 0xfe, 0xa6, 0x0a, 0x05, + 0x00, 0xfe, 0x45, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x45, 0x07, 0x00, 0xfe, + 0x55, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x45, 0xa6, + 0x08, 0xff, 0xfe, 0xa6, 0x45, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x99, 0xc2, + 0x02, 0xf7, 0xfc, 0xc2, 0x99, 0x55, 0x0a, 0x32, 0x00}; +static const Image confirming_6_image = {22, 22, sizeof(confirming_6_data), + confirming_6_data}; + +static const uint8_t confirming_7_data[249] = { + 0x32, 0x00, 0xf7, 0x0a, 0x55, 0x8c, 0xc2, 0xf1, 0x10, 0x0d, 0x0a, 0x05, + 0x0c, 0x00, 0xfe, 0x41, 0xa4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x41, + 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0xe0, 0x55, + 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xff, 0xfa, 0x04, 0x10, 0x02, + 0xff, 0xfe, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x0a, 0xa4, 0x06, 0xff, 0xfe, + 0x8c, 0x0a, 0x02, 0x10, 0xff, 0xa4, 0x03, 0xff, 0xfe, 0xa4, 0x0a, 0x04, + 0x00, 0xff, 0x55, 0x06, 0xff, 0xfb, 0xe0, 0x05, 0x00, 0x0d, 0x10, 0x05, + 0xff, 0xff, 0x55, 0x04, 0x00, 0xff, 0x8c, 0x06, 0xff, 0xff, 0x41, 0x02, + 0x00, 0xff, 0x05, 0x06, 0xff, 0xff, 0x8c, 0x04, 0x00, 0xff, 0xc2, 0x05, + 0xff, 0xff, 0xa4, 0x04, 0x00, 0xff, 0xa4, 0x05, 0xff, 0xff, 0xc2, 0x04, + 0x00, 0xff, 0xf1, 0x04, 0xff, 0xfe, 0xf1, 0x10, 0x04, 0x00, 0xfe, 0x10, + 0xf1, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, 0xf1, 0x04, 0xff, 0xff, + 0x5e, 0x06, 0x00, 0xff, 0x5e, 0x04, 0xff, 0xff, 0xf1, 0x04, 0x00, 0xff, + 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, + 0xc2, 0x04, 0x00, 0xff, 0x8c, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, + 0x5e, 0x03, 0xff, 0xff, 0x8c, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, + 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xa4, 0x0e, 0xff, 0xfe, 0xa4, 0x0a, 0x05, + 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, + 0x55, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa4, + 0x08, 0xff, 0xfe, 0xa4, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x8c, 0xc2, + 0x02, 0xf1, 0xfc, 0xc2, 0x8c, 0x55, 0x0a, 0x32, 0x00}; +static const Image confirming_7_image = {22, 22, sizeof(confirming_7_data), + confirming_7_data}; + +static const uint8_t confirming_8_data[249] = { + 0x32, 0x00, 0xf7, 0x09, 0x55, 0xa3, 0xc2, 0xf7, 0x0e, 0x0c, 0x09, 0x04, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, + 0x09, 0x00, 0xfe, 0x59, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x59, + 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x04, 0x10, + 0xfd, 0xff, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, + 0x78, 0x09, 0x03, 0x10, 0x03, 0xff, 0xfe, 0xa3, 0x09, 0x04, 0x00, 0xff, + 0x55, 0x06, 0xff, 0xfa, 0xe0, 0x09, 0x00, 0x0e, 0x10, 0x59, 0x04, 0xff, + 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, + 0xfe, 0x04, 0x10, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xc2, 0x05, + 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xc2, 0x04, + 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x10, 0x04, 0x00, 0xfe, 0x10, + 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, + 0x59, 0x06, 0x00, 0xff, 0x59, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, + 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, + 0xc2, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, + 0x59, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, + 0x55, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, + 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, + 0x59, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x59, 0x09, 0x00, 0xfe, 0x41, 0xa3, + 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x55, 0xa3, 0xc2, + 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x55, 0x09, 0x32, 0x00}; +static const Image confirming_8_image = {22, 22, sizeof(confirming_8_data), + confirming_8_data}; + +static const uint8_t confirming_9_data[249] = { + 0x32, 0x00, 0xfb, 0x0b, 0x57, 0x97, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x0b, + 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, + 0x05, 0x09, 0x00, 0xfe, 0x57, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, + 0x05, 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, + 0x10, 0xfe, 0xe0, 0x41, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, + 0x6c, 0x05, 0x04, 0x10, 0x02, 0xff, 0xfe, 0xa3, 0x0b, 0x04, 0x00, 0xff, + 0x57, 0x06, 0xff, 0xfc, 0xe0, 0x05, 0x00, 0x0e, 0x02, 0x10, 0x04, 0xff, + 0xff, 0x57, 0x04, 0x00, 0xff, 0x97, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, + 0xfe, 0x05, 0x10, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xc2, 0x05, + 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0xa3, 0x05, 0xff, 0xff, 0xc2, 0x04, + 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xe0, 0x13, 0x04, 0x00, 0xfe, 0x13, + 0xf7, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, + 0x57, 0x06, 0x00, 0xff, 0x6c, 0x04, 0xff, 0xff, 0xf7, 0x04, 0x00, 0xff, + 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, + 0xc2, 0x04, 0x00, 0xff, 0x97, 0x03, 0xff, 0xff, 0x57, 0x08, 0x33, 0xff, + 0x57, 0x03, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, + 0x57, 0x04, 0x00, 0xfe, 0x0b, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0b, 0x05, + 0x00, 0xfe, 0x41, 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, + 0x57, 0xe0, 0x0a, 0xff, 0xfe, 0xe0, 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, + 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x0b, 0x57, 0x97, 0xc2, + 0x02, 0xf7, 0xfc, 0xc2, 0x97, 0x57, 0x0b, 0x32, 0x00}; +static const Image confirming_9_image = {22, 22, sizeof(confirming_9_data), + confirming_9_data}; + +static const uint8_t confirming_10_data[249] = { + 0x32, 0x00, 0xfb, 0x0a, 0x55, 0x99, 0xc7, 0xee, 0x02, 0x0e, 0xfe, 0x0a, + 0x05, 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, + 0x05, 0x09, 0x00, 0xfe, 0x55, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, + 0x05, 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, + 0x10, 0xfe, 0x0e, 0x22, 0x05, 0x00, 0xfe, 0x0a, 0xb1, 0x06, 0xff, 0xfe, + 0x6b, 0x0a, 0x05, 0x10, 0xfd, 0xee, 0xb1, 0x0a, 0x04, 0x00, 0xff, 0x55, + 0x06, 0xff, 0xfc, 0xdf, 0x05, 0x00, 0x0e, 0x03, 0x10, 0x03, 0xff, 0xff, + 0x55, 0x04, 0x00, 0xff, 0x99, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, + 0x05, 0x02, 0x10, 0x04, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc7, 0x05, + 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x0a, 0x05, 0xff, 0xff, 0xc7, 0x04, + 0x00, 0xff, 0xee, 0x04, 0xff, 0xfe, 0xee, 0x10, 0x04, 0x00, 0xfe, 0x10, + 0xee, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xff, + 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, + 0xc7, 0x03, 0xff, 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, + 0xc7, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, + 0x55, 0x03, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, + 0x55, 0x04, 0x00, 0xfe, 0x0a, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x0a, 0x05, + 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, 0xdf, 0x41, 0x07, 0x00, 0xfe, + 0x55, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, + 0x08, 0xff, 0xfe, 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x0a, 0x55, 0x99, 0xc7, + 0x02, 0xee, 0xfc, 0xc7, 0x99, 0x55, 0x0a, 0x32, 0x00}; +static const Image confirming_10_image = {22, 22, sizeof(confirming_10_data), + confirming_10_data}; + +static const uint8_t confirming_11_data[246] = { + 0x32, 0x00, 0xf7, 0x09, 0x55, 0x99, 0xc7, 0xee, 0x10, 0x0d, 0x09, 0x04, + 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x09, 0x04, + 0x09, 0x00, 0xfe, 0x55, 0xe0, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x04, + 0x07, 0x00, 0xfe, 0x41, 0xe0, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xb1, 0x06, 0xff, 0xfe, 0x6b, 0x09, + 0x06, 0x10, 0x02, 0x09, 0x04, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xe0, + 0x09, 0x00, 0x0d, 0x04, 0x10, 0xfd, 0xee, 0xff, 0x55, 0x04, 0x00, 0xff, + 0x99, 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x03, 0x10, 0x03, + 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0x99, 0x04, + 0x00, 0xfe, 0x09, 0xee, 0x04, 0xff, 0xff, 0xc7, 0x04, 0x00, 0xff, 0xee, + 0x04, 0xff, 0xfe, 0xee, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xee, 0x04, 0xff, + 0xff, 0xee, 0x04, 0x00, 0xff, 0xee, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, + 0xff, 0x6b, 0x04, 0xff, 0xff, 0xee, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, + 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x04, 0x00, + 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, + 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, + 0xfe, 0x09, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x09, 0x05, 0x00, 0xfe, 0x41, + 0xe0, 0x0c, 0xff, 0xfe, 0xe0, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xe0, 0x0a, + 0xff, 0xfe, 0xe0, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, 0x08, 0xff, 0xfe, + 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x55, 0x99, 0xc7, 0x02, 0xee, 0xfc, + 0xc7, 0x99, 0x55, 0x09, 0x32, 0x00}; +static const Image confirming_11_image = {22, 22, sizeof(confirming_11_data), + confirming_11_data}; + +static const uint8_t confirming_12_data[244] = { + 0x32, 0x00, 0xf7, 0x09, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x09, 0x04, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x09, 0x04, + 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x04, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x8a, 0x09, + 0x06, 0x10, 0xff, 0x09, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, + 0x09, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x55, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x04, 0x10, 0x02, 0xff, 0xff, + 0xa3, 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xfe, + 0x09, 0x10, 0x04, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, + 0xfe, 0xe3, 0x10, 0x04, 0x00, 0xfe, 0x10, 0xe3, 0x04, 0xff, 0xff, 0xfa, + 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x5e, 0x06, 0x00, 0xff, 0x5e, + 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, + 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, + 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x5e, 0x03, 0xff, 0xff, 0xa3, + 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x09, + 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, + 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, + 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, + 0x0b, 0x00, 0xfc, 0x09, 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, + 0x55, 0x09, 0x32, 0x00}; +static const Image confirming_12_image = {22, 22, sizeof(confirming_12_data), + confirming_12_data}; + +static const uint8_t confirming_13_data[245] = { + 0x32, 0x00, 0xf7, 0x08, 0x55, 0x97, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, + 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x6b, 0x08, + 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0x97, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x05, 0x10, 0xfe, 0x22, 0x97, + 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0x97, 0x04, 0x00, 0xff, 0x08, + 0x02, 0x10, 0xff, 0xa3, 0x02, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xfa, + 0x04, 0xff, 0xfe, 0xe3, 0x10, 0x05, 0x00, 0xff, 0xe3, 0x04, 0xff, 0xff, + 0xfa, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, + 0x6b, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, + 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, + 0x97, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, + 0x97, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, + 0x08, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, + 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, + 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, + 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0x97, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, + 0x97, 0x55, 0x08, 0x32, 0x00}; +static const Image confirming_13_image = {22, 22, sizeof(confirming_13_data), + confirming_13_data}; + +static const uint8_t confirming_14_data[241] = { + 0x32, 0x00, 0xf7, 0x08, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, + 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x8a, 0x08, + 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x04, + 0x10, 0xfe, 0x8a, 0xd5, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, + 0x10, 0x05, 0x00, 0xff, 0x10, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, + 0xfa, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x6b, 0x04, 0xff, 0xff, + 0xfa, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, + 0xc2, 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, + 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, + 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, + 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, + 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x55, 0x09, + 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, + 0x08, 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x55, 0x08, 0x32, + 0x00}; +static const Image confirming_14_image = {22, 22, sizeof(confirming_14_data), + confirming_14_data}; + +static const uint8_t confirming_15_data[240] = { + 0x32, 0x00, 0xf7, 0x08, 0x55, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x45, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, + 0x09, 0x00, 0xfe, 0x59, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, + 0x07, 0x00, 0xfe, 0x45, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x7a, 0x08, + 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x45, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, 0x05, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, + 0x05, 0x00, 0x03, 0x10, 0xfd, 0xa3, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xfa, + 0x04, 0xff, 0xff, 0x59, 0x06, 0x00, 0xff, 0x59, 0x04, 0xff, 0xff, 0xfa, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, + 0x03, 0xff, 0xff, 0xd5, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, + 0x08, 0x27, 0xff, 0x59, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x55, + 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, 0xfe, + 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x45, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x45, + 0x07, 0x00, 0xfe, 0x59, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x59, 0x09, 0x00, + 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x45, 0x0b, 0x00, 0xfc, 0x08, + 0x55, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x55, 0x08, 0x32, 0x00}; +static const Image confirming_15_image = {22, 22, sizeof(confirming_15_data), + confirming_15_data}; + +static const uint8_t confirming_16_data[236] = { + 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xd5, 0xfa, 0x10, 0x0d, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x03, + 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, + 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x08, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, + 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x57, + 0x06, 0x00, 0xff, 0x57, 0x04, 0xff, 0xff, 0xfa, 0x04, 0x00, 0xff, 0xd5, + 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xd5, + 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x08, 0x22, 0xff, 0x57, + 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, + 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, 0xff, 0xfe, 0xa3, 0x0a, 0x05, 0x00, + 0xfe, 0x49, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x49, 0x07, 0x00, 0xfe, 0x57, + 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x57, 0x09, 0x00, 0xfe, 0x49, 0xa3, 0x08, + 0xff, 0xfe, 0xa3, 0x49, 0x0b, 0x00, 0xfc, 0x0a, 0x57, 0xa3, 0xd5, 0x02, + 0xfa, 0xfc, 0xd5, 0xa3, 0x57, 0x0a, 0x32, 0x00}; +static const Image confirming_16_image = {22, 22, sizeof(confirming_16_data), + confirming_16_data}; + +static const uint8_t confirming_17_data[234] = { + 0x32, 0x00, 0xf7, 0x08, 0x55, 0x99, 0xc7, 0xfa, 0x10, 0x0d, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x41, 0xb1, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0d, 0x03, + 0x09, 0x00, 0xfe, 0x55, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x08, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xff, 0xfa, 0x06, 0x10, 0xfe, + 0x0d, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xb1, 0x06, 0xff, 0xfe, 0x6b, 0x08, + 0x06, 0x10, 0xff, 0x0d, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0x99, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x08, 0x05, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, 0x10, + 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xff, 0x55, + 0x06, 0x00, 0xff, 0x08, 0x05, 0x10, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, + 0xff, 0xb1, 0x08, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, 0x04, 0x00, + 0xff, 0x99, 0x03, 0xff, 0xff, 0x55, 0x08, 0x41, 0xff, 0x55, 0x03, 0xff, + 0xff, 0x99, 0x04, 0x00, 0xff, 0x55, 0x10, 0xff, 0xff, 0x55, 0x04, 0x00, + 0xfe, 0x08, 0xb1, 0x0e, 0xff, 0xfe, 0xb1, 0x08, 0x05, 0x00, 0xfe, 0x41, + 0xd5, 0x0c, 0xff, 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x55, 0xd5, 0x0a, + 0xff, 0xfe, 0xd5, 0x55, 0x09, 0x00, 0xfe, 0x41, 0xb1, 0x08, 0xff, 0xfe, + 0xb1, 0x41, 0x0b, 0x00, 0xfc, 0x08, 0x55, 0x99, 0xc7, 0x02, 0xfa, 0xfc, + 0xc7, 0x99, 0x55, 0x08, 0x32, 0x00}; +static const Image confirming_17_image = {22, 22, sizeof(confirming_17_data), + confirming_17_data}; + +static const uint8_t confirming_18_data[241] = { + 0x32, 0x00, 0xf7, 0x08, 0x4e, 0xa3, 0xd5, 0xfa, 0x0e, 0x0c, 0x08, 0x03, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x03, + 0x09, 0x00, 0xfe, 0x4e, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x08, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x03, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x78, + 0x08, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x4e, 0x06, 0xff, 0xfc, + 0xd5, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, + 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x08, + 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xfa, 0x04, 0xff, 0xff, 0x4e, 0x06, 0x00, 0xff, 0x08, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xfb, + 0xc2, 0xff, 0xa3, 0x41, 0x0e, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, + 0x4e, 0x08, 0x41, 0xff, 0x4e, 0x03, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, + 0x4e, 0x10, 0xff, 0xff, 0x4e, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, 0xff, + 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, 0xd5, + 0x41, 0x07, 0x00, 0xfe, 0x4e, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x4e, 0x09, + 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, + 0x08, 0x4e, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x4e, 0x08, 0x32, + 0x00}; +static const Image confirming_18_image = {22, 22, sizeof(confirming_18_data), + confirming_18_data}; + +static const uint8_t confirming_19_data[242] = { + 0x32, 0x00, 0xf7, 0x08, 0x57, 0xa3, 0xc2, 0xf7, 0x0e, 0x0c, 0x08, 0x05, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x05, + 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, + 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x08, 0xa3, 0x06, 0xff, 0xfe, 0x7a, + 0x08, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, + 0xdf, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xa3, + 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, + 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x08, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, + 0x22, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, + 0x57, 0x08, 0x41, 0xff, 0x57, 0x02, 0xff, 0xfe, 0xc2, 0x22, 0x04, 0x00, + 0xff, 0x57, 0x10, 0xff, 0xff, 0x57, 0x04, 0x00, 0xfe, 0x08, 0xa3, 0x0e, + 0xff, 0xfe, 0xa3, 0x08, 0x05, 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, + 0xdf, 0x41, 0x07, 0x00, 0xfe, 0x57, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x57, + 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, + 0xfc, 0x08, 0x57, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x57, 0x08, + 0x32, 0x00}; +static const Image confirming_19_image = {22, 22, sizeof(confirming_19_data), + confirming_19_data}; + +static const uint8_t confirming_20_data[243] = { + 0x32, 0x00, 0xf7, 0x09, 0x57, 0xa3, 0xd5, 0xfa, 0x0e, 0x0c, 0x09, 0x04, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x04, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x7a, + 0x09, 0x06, 0x10, 0xff, 0x0c, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, + 0xd5, 0x09, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, + 0x06, 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, + 0x04, 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x04, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xbc, 0x08, 0x00, 0xff, + 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, + 0x57, 0x08, 0x41, 0xfe, 0x57, 0xa3, 0x02, 0x10, 0xff, 0x09, 0x04, 0x00, + 0xff, 0x57, 0x0f, 0xff, 0xfe, 0xfa, 0x22, 0x04, 0x00, 0xfe, 0x09, 0xa3, + 0x0e, 0xff, 0xfe, 0xa3, 0x09, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, + 0xfe, 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x57, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, + 0x57, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, + 0x00, 0xfc, 0x09, 0x57, 0xa3, 0xd5, 0x02, 0xfa, 0xfc, 0xd5, 0xa3, 0x57, + 0x09, 0x32, 0x00}; +static const Image confirming_20_image = {22, 22, sizeof(confirming_20_data), + confirming_20_data}; + +static const uint8_t confirming_21_data[242] = { + 0x32, 0x00, 0xf7, 0x0a, 0x51, 0xa3, 0xd5, 0xea, 0x0e, 0x0c, 0x0a, 0x03, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x03, + 0x09, 0x00, 0xfe, 0x51, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x41, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x03, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x51, 0x06, 0xff, 0xfc, 0xd5, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x51, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x51, + 0x08, 0x41, 0xff, 0x22, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x51, + 0x0e, 0xff, 0xfd, 0x51, 0x10, 0x03, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x0e, + 0xff, 0xfe, 0xa3, 0x03, 0x05, 0x00, 0xfe, 0x41, 0xd5, 0x0c, 0xff, 0xfe, + 0xd5, 0x41, 0x07, 0x00, 0xfe, 0x51, 0xd5, 0x0a, 0xff, 0xfe, 0xd5, 0x51, + 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, + 0xfc, 0x0a, 0x51, 0xa3, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xa3, 0x51, 0x0a, + 0x32, 0x00}; +static const Image confirming_21_image = {22, 22, sizeof(confirming_21_data), + confirming_21_data}; + +static const uint8_t confirming_22_data[245] = { + 0x32, 0x00, 0xfb, 0x0b, 0x55, 0xa3, 0xc2, 0xf7, 0x02, 0x0e, 0xfe, 0x07, + 0x03, 0x0c, 0x00, 0xfe, 0x45, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, + 0x03, 0x09, 0x00, 0xfe, 0x55, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0e, + 0x07, 0x07, 0x00, 0xfe, 0x45, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, + 0x10, 0xfe, 0x0e, 0x03, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, + 0x78, 0x07, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, + 0xfc, 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x03, 0x04, 0x00, 0xff, + 0xa3, 0x06, 0xff, 0xff, 0x3f, 0x02, 0x00, 0xff, 0x03, 0x06, 0x10, 0xff, + 0x07, 0x04, 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, + 0x0b, 0x05, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, + 0xdf, 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, + 0xff, 0xf7, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, + 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, 0xff, 0xc2, 0x08, 0x00, + 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, + 0xff, 0x55, 0x07, 0x3f, 0xfe, 0x22, 0x07, 0x03, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x55, 0x0d, 0xff, 0x03, 0x10, 0xff, 0x03, 0x04, 0x00, 0xfe, + 0x0b, 0xa3, 0x0d, 0xff, 0xfe, 0x78, 0x0b, 0x06, 0x00, 0xfe, 0x45, 0xdf, + 0x0c, 0xff, 0xfe, 0xdf, 0x3f, 0x07, 0x00, 0xfe, 0x55, 0xdf, 0x0a, 0xff, + 0xfe, 0xdf, 0x55, 0x09, 0x00, 0xfe, 0x45, 0xa3, 0x08, 0xff, 0xfe, 0xa3, + 0x45, 0x0b, 0x00, 0xfc, 0x0b, 0x55, 0xa3, 0xc2, 0x02, 0xf7, 0xfc, 0xc2, + 0xa3, 0x55, 0x0b, 0x32, 0x00}; +static const Image confirming_22_image = {22, 22, sizeof(confirming_22_data), + confirming_22_data}; + +static const uint8_t confirming_23_data[238] = { + 0x32, 0x00, 0xf7, 0x09, 0x57, 0xa3, 0xc2, 0xf7, 0x10, 0x0d, 0x09, 0x06, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x02, + 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, + 0x07, 0x00, 0xfe, 0x41, 0xdf, 0x05, 0xff, 0xff, 0xf7, 0x06, 0x10, 0xfe, + 0x0d, 0x02, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x09, + 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xdf, + 0x06, 0x00, 0x0d, 0x06, 0x10, 0xff, 0x06, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x02, 0x06, 0x10, 0xff, 0x09, 0x04, + 0x00, 0xff, 0xc2, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, 0x05, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, 0x10, + 0x05, 0x00, 0x06, 0x10, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xff, 0x57, + 0x06, 0x00, 0xff, 0x06, 0x05, 0x10, 0x04, 0x00, 0xff, 0xc2, 0x03, 0xff, + 0xff, 0xc2, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, + 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, 0x07, 0x41, 0xfe, 0x02, 0x06, 0x03, + 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x57, 0x0c, 0xff, 0x04, 0x10, 0xff, + 0x06, 0x04, 0x00, 0xfe, 0x09, 0xa3, 0x0c, 0xff, 0xfd, 0x41, 0x10, 0x0b, + 0x06, 0x00, 0xfe, 0x41, 0xdf, 0x0c, 0xff, 0xfe, 0x78, 0x02, 0x07, 0x00, + 0xfe, 0x57, 0xdf, 0x0a, 0xff, 0xfe, 0xdf, 0x57, 0x09, 0x00, 0xfe, 0x41, + 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x57, 0xa3, + 0xc2, 0x02, 0xf7, 0xfc, 0xc2, 0xa3, 0x57, 0x09, 0x32, 0x00}; +static const Image confirming_23_image = {22, 22, sizeof(confirming_23_data), + confirming_23_data}; + +static const uint8_t confirming_24_data[250] = { + 0x32, 0x00, 0xf7, 0x09, 0x4e, 0xa3, 0xc6, 0xea, 0x0e, 0x0d, 0x09, 0x06, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x02, + 0x09, 0x00, 0xfe, 0x4e, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, 0x06, + 0x07, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0d, 0x02, 0x05, 0x00, 0xfe, 0x09, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x09, + 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x4e, 0x06, 0xff, 0xfc, 0xc6, + 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x06, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x02, 0x06, 0x10, 0xff, 0x09, 0x04, + 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x09, 0x05, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x4e, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0b, + 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x4e, + 0x06, 0x41, 0xfd, 0x0e, 0x02, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, + 0xff, 0x4e, 0x0b, 0xff, 0xff, 0x41, 0x04, 0x10, 0xff, 0x06, 0x04, 0x00, + 0xfe, 0x09, 0xa3, 0x0b, 0xff, 0xff, 0x41, 0x02, 0x10, 0xff, 0x0b, 0x06, + 0x00, 0xfe, 0x41, 0xc6, 0x0b, 0xff, 0xfd, 0x4e, 0x0d, 0x02, 0x07, 0x00, + 0xfe, 0x4e, 0xc6, 0x0a, 0xff, 0xfe, 0xc6, 0x10, 0x09, 0x00, 0xfe, 0x41, + 0xa3, 0x08, 0xff, 0xfe, 0xa3, 0x41, 0x0b, 0x00, 0xfc, 0x09, 0x4e, 0xa3, + 0xc6, 0x02, 0xea, 0xfc, 0xc6, 0xa3, 0x4e, 0x09, 0x32, 0x00}; +static const Image confirming_24_image = {22, 22, sizeof(confirming_24_data), + confirming_24_data}; + +static const uint8_t confirming_25_data[249] = { + 0x32, 0x00, 0xf7, 0x0b, 0x55, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x08, 0x05, + 0x0c, 0x00, 0xfe, 0x4c, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, + 0x09, 0x00, 0xfe, 0x55, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, + 0x07, 0x00, 0xfe, 0x4c, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x08, + 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xc6, + 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x4c, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0b, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x55, + 0x06, 0x2a, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, + 0xff, 0x55, 0x0b, 0xff, 0x05, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x0b, + 0xa3, 0x0a, 0xff, 0xff, 0xc6, 0x03, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, + 0x4c, 0xc6, 0x0a, 0xff, 0xfc, 0x55, 0x10, 0x0c, 0x05, 0x07, 0x00, 0xfe, + 0x55, 0xc6, 0x0a, 0xff, 0xfe, 0x10, 0x05, 0x09, 0x00, 0xfe, 0x4c, 0xa3, + 0x08, 0xff, 0xfe, 0xa3, 0x4c, 0x0b, 0x00, 0xfc, 0x0b, 0x55, 0xa3, 0xc6, + 0x02, 0xea, 0xfc, 0xc6, 0xa3, 0x55, 0x0b, 0x32, 0x00}; +static const Image confirming_25_image = {22, 22, sizeof(confirming_25_data), + confirming_25_data}; + +static const uint8_t confirming_26_data[252] = { + 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xd5, 0xea, 0x0e, 0x0c, 0x08, 0x05, + 0x0c, 0x00, 0xfe, 0x49, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, + 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, + 0x07, 0x00, 0xfe, 0x49, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x79, 0x08, + 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, 0x06, + 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, + 0x06, 0x22, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, + 0xff, 0x57, 0x0a, 0xff, 0xff, 0x22, 0x05, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x0b, 0xb4, 0x0a, 0xff, 0x04, 0x10, 0xff, 0x0b, 0x06, 0x00, 0xfe, + 0x49, 0xd5, 0x09, 0xff, 0xff, 0xb4, 0x02, 0x10, 0xfe, 0x0c, 0x05, 0x07, + 0x00, 0xfe, 0x57, 0xd5, 0x09, 0xff, 0xfd, 0x22, 0x0c, 0x05, 0x09, 0x00, + 0xfe, 0x49, 0xb4, 0x08, 0xff, 0xfe, 0xb4, 0x05, 0x0b, 0x00, 0xfc, 0x0b, + 0x57, 0xb4, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xb4, 0x57, 0x0b, 0x32, 0x00}; +static const Image confirming_26_image = {22, 22, sizeof(confirming_26_data), + confirming_26_data}; + +static const uint8_t confirming_27_data[254] = { + 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xd5, 0xea, 0x0e, 0x0c, 0x08, 0x05, + 0x0c, 0x00, 0xfe, 0x4d, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x05, + 0x09, 0x00, 0xfe, 0x57, 0xd5, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, + 0x07, 0x00, 0xfe, 0x4d, 0xd5, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x05, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x78, 0x08, + 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd5, + 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, 0x06, + 0xff, 0xff, 0x4d, 0x02, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0xd5, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd5, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, 0x57, + 0x05, 0x27, 0xff, 0x10, 0x02, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, + 0x04, 0x00, 0xff, 0x57, 0x0a, 0xff, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x0b, 0xb4, 0x09, 0xff, 0xff, 0x4d, 0x04, 0x10, 0xff, 0x0b, 0x06, + 0x00, 0xfe, 0x4d, 0xd5, 0x09, 0xff, 0x03, 0x10, 0xfe, 0x0c, 0x05, 0x07, + 0x00, 0xfe, 0x57, 0xd5, 0x08, 0xff, 0xfc, 0x4d, 0x10, 0x0c, 0x05, 0x09, + 0x00, 0xfe, 0x4d, 0xb4, 0x07, 0xff, 0xfd, 0xea, 0x0b, 0x05, 0x0b, 0x00, + 0xfc, 0x0b, 0x57, 0xb4, 0xd5, 0x02, 0xea, 0xfc, 0xd5, 0xb4, 0x57, 0x02, + 0x32, 0x00}; +static const Image confirming_27_image = {22, 22, sizeof(confirming_27_data), + confirming_27_data}; + +static const uint8_t confirming_28_data[254] = { + 0x32, 0x00, 0xf7, 0x0b, 0x57, 0xb4, 0xe3, 0xfa, 0x0e, 0x0c, 0x08, 0x05, + 0x0c, 0x00, 0xfe, 0x57, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xe3, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x05, + 0x07, 0x00, 0xfe, 0x57, 0xe3, 0x05, 0xff, 0xfe, 0xfa, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0b, 0xb4, 0x06, 0xff, 0xfe, 0x78, + 0x08, 0x06, 0x10, 0xff, 0x0b, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, + 0xe3, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0xb4, + 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, + 0x04, 0x00, 0xff, 0xe3, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0b, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xfa, 0x04, 0xff, 0xfe, 0xe3, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xfa, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xe3, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, + 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, + 0x57, 0x05, 0x2b, 0x03, 0x02, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0x57, 0x09, 0xff, 0xff, 0xb4, 0x06, 0x10, 0xff, 0x05, 0x04, + 0x00, 0xfe, 0x0b, 0xb4, 0x09, 0xff, 0x05, 0x10, 0xff, 0x0b, 0x06, 0x00, + 0xfe, 0x57, 0xe3, 0x08, 0xff, 0x04, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, + 0xfe, 0x57, 0xe3, 0x07, 0xff, 0xff, 0xb4, 0x02, 0x10, 0xfe, 0x0c, 0x05, + 0x09, 0x00, 0xfe, 0x57, 0xb4, 0x07, 0xff, 0xfd, 0x10, 0x0b, 0x04, 0x0b, + 0x00, 0xfc, 0x0b, 0x57, 0xb4, 0xe3, 0x02, 0xfa, 0xfd, 0xe3, 0xb4, 0x10, + 0x33, 0x00}; +static const Image confirming_28_image = {22, 22, sizeof(confirming_28_data), + confirming_28_data}; + +static const uint8_t confirming_29_data[255] = { + 0x32, 0x00, 0xf7, 0x0a, 0x4d, 0x99, 0xbc, 0xf7, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x4d, 0xbc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x4d, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x4d, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xbc, 0x06, 0xff, 0xfe, 0x6b, + 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x4d, 0x06, 0xff, 0xfc, + 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0x99, + 0x06, 0xff, 0xff, 0x4d, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, + 0x04, 0x00, 0xff, 0xbc, 0x05, 0xff, 0xff, 0x99, 0x04, 0x00, 0xff, 0x0a, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xf7, 0x04, 0xff, 0xff, 0x4d, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xbc, 0x03, 0xff, 0xff, 0xbc, 0x08, 0x00, 0xff, + 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x99, 0x03, 0xff, 0xff, + 0x4d, 0x05, 0x27, 0x03, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0x4d, 0x09, 0xff, 0x07, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, + 0x0a, 0xbc, 0x08, 0xff, 0xff, 0x4d, 0x05, 0x10, 0xff, 0x0a, 0x06, 0x00, + 0xfe, 0x4d, 0xdf, 0x07, 0xff, 0xff, 0xdf, 0x04, 0x10, 0xfe, 0x0c, 0x04, + 0x07, 0x00, 0xfe, 0x4d, 0xdf, 0x07, 0xff, 0x03, 0x10, 0xfe, 0x0c, 0x07, + 0x09, 0x00, 0xfe, 0x4d, 0xbc, 0x06, 0xff, 0x02, 0x10, 0xfe, 0x0a, 0x04, + 0x0b, 0x00, 0xfc, 0x0a, 0x4d, 0x99, 0xbc, 0x02, 0xf7, 0xfd, 0xbc, 0x27, + 0x04, 0x33, 0x00}; +static const Image confirming_29_image = {22, 22, sizeof(confirming_29_data), + confirming_29_data}; + +static const uint8_t confirming_30_data[261] = { + 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xc6, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x41, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, + 0x04, 0x41, 0xff, 0x22, 0x03, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, + 0x04, 0x00, 0xff, 0x57, 0x08, 0xff, 0xff, 0xa3, 0x07, 0x10, 0xff, 0x04, + 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x07, 0xff, 0xff, 0xa3, 0x06, 0x10, 0xff, + 0x0a, 0x06, 0x00, 0xfe, 0x41, 0xc6, 0x06, 0xff, 0xff, 0xa3, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0xff, 0xa3, + 0x04, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x41, 0xa3, 0x04, 0xff, + 0xff, 0xa3, 0x03, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xf7, 0x0a, 0x57, + 0xa3, 0xc6, 0xea, 0xa3, 0x0c, 0x0a, 0x04, 0x33, 0x00}; +static const Image confirming_30_image = {22, 22, sizeof(confirming_30_data), + confirming_30_data}; + +static const uint8_t confirming_31_data[252] = { + 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa3, 0xc6, 0xea, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x49, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xc6, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x49, 0xc6, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xc6, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa3, 0x06, + 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0xc6, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xc6, 0x03, 0xff, 0xff, 0xc6, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, 0x03, 0xff, 0xff, 0x57, + 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, + 0xff, 0x57, 0x08, 0xff, 0x08, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, + 0xa3, 0x07, 0xff, 0x07, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x49, 0xc6, + 0x06, 0xff, 0x06, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x57, 0xc6, + 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x49, 0xa3, + 0x03, 0xff, 0xff, 0xea, 0x04, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfd, + 0x0a, 0x57, 0xa3, 0x02, 0xc6, 0xfc, 0x0e, 0x0c, 0x0a, 0x04, 0x33, 0x00}; +static const Image confirming_31_image = {22, 22, sizeof(confirming_31_data), + confirming_31_data}; + +static const uint8_t confirming_32_data[256] = { + 0x32, 0x00, 0xf7, 0x0a, 0x55, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x3c, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x55, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x3c, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x55, 0x06, 0xff, 0xfc, 0xd1, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, + 0xff, 0xff, 0x3c, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x55, + 0x04, 0x3c, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, + 0xff, 0x55, 0x08, 0xff, 0x08, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, + 0xa9, 0x06, 0xff, 0xff, 0xea, 0x07, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, + 0x3c, 0xd1, 0x05, 0xff, 0xff, 0x78, 0x06, 0x10, 0xfe, 0x0c, 0x04, 0x07, + 0x00, 0xfe, 0x55, 0xd1, 0x04, 0xff, 0xff, 0x19, 0x05, 0x10, 0xfe, 0x0c, + 0x07, 0x09, 0x00, 0xfe, 0x3c, 0xa9, 0x03, 0xff, 0x05, 0x10, 0xfe, 0x0a, + 0x04, 0x0b, 0x00, 0xfe, 0x0a, 0x55, 0x02, 0xa9, 0x02, 0x0e, 0xfd, 0x0c, + 0x0a, 0x04, 0x33, 0x00}; +static const Image confirming_32_image = {22, 22, sizeof(confirming_32_data), + confirming_32_data}; + +static const uint8_t confirming_33_data[257] = { + 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xb4, 0xdf, 0xf7, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x49, 0xb4, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xdf, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x49, 0xdf, 0x05, 0xff, 0xfe, 0xf7, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xb4, 0x06, 0xff, 0xfe, 0x78, + 0x07, 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, + 0xdf, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xb4, + 0x06, 0xff, 0xff, 0x49, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, + 0x04, 0x00, 0xff, 0xdf, 0x05, 0xff, 0xff, 0xb4, 0x04, 0x00, 0xff, 0x0a, + 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf7, 0x04, 0xff, 0xfe, 0xdf, + 0x10, 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, + 0xf7, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0xdf, 0x03, 0xff, 0xff, 0xb4, 0x08, 0x00, 0xff, + 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xb4, 0x03, 0xff, 0xff, + 0x57, 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0x57, 0x07, 0xff, 0xff, 0xb4, 0x08, 0x10, 0xff, 0x04, 0x04, + 0x00, 0xfe, 0x0a, 0xb4, 0x06, 0xff, 0x08, 0x10, 0xff, 0x0a, 0x06, 0x00, + 0xfe, 0x49, 0xdf, 0x05, 0xff, 0x07, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, + 0xfe, 0x57, 0xdf, 0x03, 0xff, 0xff, 0xb4, 0x06, 0x10, 0xfe, 0x0c, 0x07, + 0x09, 0x00, 0xfe, 0x49, 0xb4, 0x02, 0xff, 0xff, 0x22, 0x05, 0x10, 0xfe, + 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x0a, 0x57, 0x78, 0x0c, 0x02, 0x0e, 0xfd, + 0x0c, 0x0a, 0x04, 0x33, 0x00}; +static const Image confirming_33_image = {22, 22, sizeof(confirming_33_data), + confirming_33_data}; + +static const uint8_t confirming_34_data[256] = { + 0x32, 0x00, 0xf7, 0x0a, 0x56, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, + 0x0c, 0x00, 0xfe, 0x47, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x56, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x47, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x56, 0x06, 0xff, 0xfc, 0xd1, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, + 0xff, 0xff, 0x47, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x0a, 0x04, + 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x56, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x56, + 0x04, 0x22, 0x04, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x0a, 0x04, 0x00, + 0xff, 0x56, 0x07, 0xff, 0x09, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, + 0xa9, 0x05, 0xff, 0xff, 0xea, 0x08, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, + 0x47, 0xd1, 0x04, 0xff, 0xff, 0x22, 0x07, 0x10, 0xfe, 0x0c, 0x04, 0x07, + 0x00, 0xfe, 0x56, 0xd1, 0x02, 0xff, 0xff, 0xea, 0x07, 0x10, 0xfe, 0x0c, + 0x07, 0x09, 0x00, 0xfc, 0x47, 0xa9, 0xff, 0x56, 0x06, 0x10, 0xfe, 0x0a, + 0x04, 0x0b, 0x00, 0xfc, 0x0a, 0x56, 0x0a, 0x0c, 0x02, 0x0e, 0xfd, 0x0c, + 0x0a, 0x04, 0x33, 0x00}; +static const Image confirming_34_image = {22, 22, sizeof(confirming_34_data), + confirming_34_data}; + +static const uint8_t confirming_35_data[251] = { + 0x32, 0x00, 0xf7, 0x0a, 0x57, 0xa9, 0xd1, 0xea, 0x0e, 0x0c, 0x09, 0x04, + 0x0c, 0x00, 0xfe, 0x33, 0xa9, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, 0x04, + 0x09, 0x00, 0xfe, 0x57, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, 0x07, + 0x07, 0x00, 0xfe, 0x33, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, 0xfe, + 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa9, 0x06, 0xff, 0xfe, 0x78, 0x07, + 0x06, 0x10, 0xff, 0x0a, 0x05, 0x00, 0xff, 0x57, 0x06, 0xff, 0xfc, 0xd1, + 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, 0xa9, 0x06, + 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, + 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa9, 0x04, 0x00, 0xff, 0x0a, 0x05, + 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, 0xea, 0x10, + 0x05, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xea, + 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa9, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa9, 0x03, 0xff, 0xff, 0x57, + 0x03, 0x33, 0x05, 0x02, 0xff, 0x07, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, + 0xff, 0x57, 0x07, 0xff, 0x09, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, + 0xa9, 0x05, 0xff, 0x09, 0x10, 0xff, 0x0a, 0x06, 0x00, 0xfe, 0x33, 0xd1, + 0x03, 0xff, 0xff, 0xa9, 0x08, 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, + 0x57, 0xd1, 0x02, 0xff, 0x08, 0x10, 0xfe, 0x0c, 0x07, 0x09, 0x00, 0xfd, + 0x33, 0xa9, 0x78, 0x07, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x07, + 0x04, 0x09, 0x0c, 0x02, 0x0e, 0xfd, 0x0c, 0x09, 0x04, 0x33, 0x00}; +static const Image confirming_35_image = {22, 22, sizeof(confirming_35_data), + confirming_35_data}; + +static const uint8_t confirming_36_data[256] = { + 0x32, 0x00, 0xf6, 0x0a, 0x57, 0xa8, 0xd1, 0xea, 0x0e, 0x0c, 0x0a, 0x04, + 0x01, 0x0b, 0x00, 0xfe, 0x57, 0xa8, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, + 0x04, 0x09, 0x00, 0xfe, 0x57, 0xd1, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, + 0x07, 0x07, 0x00, 0xfe, 0x57, 0xd1, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa8, 0x06, 0xff, 0xfe, 0x78, + 0x07, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, + 0xfc, 0xd1, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, + 0xa8, 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, + 0x0a, 0x04, 0x00, 0xff, 0xd1, 0x05, 0xff, 0xff, 0xa8, 0x04, 0x00, 0xff, + 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, + 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x57, 0x06, 0x00, 0xff, 0x07, 0x04, + 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xd1, 0x03, 0xff, 0xff, 0xa8, 0x08, + 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa8, 0x03, + 0xff, 0xff, 0x57, 0x03, 0x2b, 0x05, 0x03, 0xff, 0x07, 0x03, 0x10, 0xff, + 0x0a, 0x04, 0x00, 0xff, 0x57, 0x06, 0xff, 0x0a, 0x10, 0xff, 0x04, 0x04, + 0x00, 0xfe, 0x0a, 0xa8, 0x04, 0xff, 0xff, 0xa8, 0x09, 0x10, 0xfe, 0x0a, + 0x01, 0x05, 0x00, 0xfe, 0x57, 0xd1, 0x02, 0xff, 0xff, 0xea, 0x09, 0x10, + 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfd, 0x57, 0xd1, 0xff, 0x09, 0x10, 0xfe, + 0x0c, 0x07, 0x09, 0x00, 0xfe, 0x57, 0x2b, 0x08, 0x10, 0xfe, 0x0a, 0x04, + 0x0b, 0x00, 0xfc, 0x01, 0x04, 0x0a, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x0a, + 0x04, 0x01, 0x32, 0x00}; +static const Image confirming_36_image = {22, 22, sizeof(confirming_36_data), + confirming_36_data}; + +static const uint8_t confirming_37_data[255] = { + 0x32, 0x00, 0xf6, 0x0a, 0x55, 0xa3, 0xc7, 0xf3, 0x0e, 0x0c, 0x0a, 0x04, + 0x01, 0x0b, 0x00, 0xfe, 0x55, 0xa3, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, + 0x04, 0x09, 0x00, 0xfe, 0x55, 0xc7, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, + 0x07, 0x07, 0x00, 0xfe, 0x55, 0xc7, 0x05, 0xff, 0xfe, 0xf3, 0x0e, 0x05, + 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xa3, 0x06, 0xff, 0xfe, + 0x78, 0x07, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x55, 0x06, + 0xff, 0xfc, 0xc7, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, + 0xff, 0xa3, 0x06, 0xff, 0xff, 0x2b, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x0a, 0x04, 0x00, 0xff, 0xc7, 0x05, 0xff, 0xff, 0xa3, 0x04, 0x00, + 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, + 0xfe, 0xf3, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xff, 0x55, 0x06, 0x00, 0xff, 0x07, + 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc7, 0x03, 0xff, 0xff, 0xc7, + 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xa3, + 0x03, 0xff, 0xff, 0x55, 0x03, 0x2b, 0x05, 0x03, 0xff, 0x07, 0x03, 0x10, + 0xff, 0x0a, 0x04, 0x00, 0xff, 0x55, 0x05, 0xff, 0xff, 0xf3, 0x0a, 0x10, + 0xff, 0x04, 0x04, 0x00, 0xfe, 0x0a, 0xa3, 0x03, 0xff, 0xff, 0xf3, 0x0a, + 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfc, 0x55, 0xc7, 0xff, 0xf3, 0x0a, + 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x55, 0xc7, 0x0a, 0x10, 0xfe, + 0x0c, 0x07, 0x09, 0x00, 0x02, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, + 0x00, 0xfc, 0x01, 0x04, 0x0a, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x0a, 0x04, + 0x01, 0x32, 0x00}; +static const Image confirming_37_image = {22, 22, sizeof(confirming_37_data), + confirming_37_data}; + +static const uint8_t confirming_38_data[249] = { + 0x32, 0x00, 0xff, 0x0a, 0x02, 0x78, 0xf9, 0xc0, 0xea, 0x0e, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x33, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x78, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x33, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xc0, 0x06, 0xff, 0xfe, + 0x78, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x78, 0x06, + 0xff, 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0x78, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x08, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x78, 0x04, 0x00, + 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, + 0xfe, 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x78, 0x06, 0x00, 0xff, 0x05, + 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, + 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x78, + 0x03, 0xff, 0x03, 0x33, 0x06, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, + 0x04, 0x00, 0xff, 0x78, 0x05, 0xff, 0x0b, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x0a, 0xc0, 0x03, 0xff, 0x0b, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, + 0xfd, 0x33, 0xea, 0xc0, 0x0b, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, + 0x33, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, + 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, + 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_38_image = {22, 22, sizeof(confirming_38_data), + confirming_38_data}; + +static const uint8_t confirming_39_data[252] = { + 0x32, 0x00, 0xfe, 0x0a, 0x76, 0x02, 0xb5, 0xfa, 0xe9, 0x0e, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x33, 0xb5, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0a, 0x04, 0x09, 0x00, 0xfe, 0x76, 0xe9, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x33, 0xe9, 0x06, 0xff, 0xff, 0x0e, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xb5, 0x06, 0xff, 0xfe, + 0x76, 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x76, 0x06, + 0xff, 0xfc, 0xe9, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0xb5, 0x06, 0xff, 0xff, 0x33, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x08, 0x04, 0x00, 0xff, 0xb5, 0x05, 0xff, 0xff, 0xb5, 0x04, 0x00, + 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xe9, 0x04, 0xff, + 0xfe, 0xe9, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xe9, 0x04, 0xff, 0xff, 0x76, 0x06, 0x00, 0xff, 0x05, + 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xb5, 0x03, 0xff, 0xff, 0xb5, + 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xb5, + 0x03, 0xff, 0xff, 0x76, 0x02, 0x33, 0x06, 0x03, 0xff, 0x05, 0x03, 0x10, + 0xff, 0x08, 0x04, 0x00, 0xff, 0x76, 0x04, 0xff, 0xff, 0x33, 0x0b, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xfc, 0x0a, 0xb5, 0xff, 0xe9, 0x0c, 0x10, 0xfe, + 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x33, 0x76, 0x0c, 0x10, 0xfe, 0x0d, 0x04, + 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, + 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, + 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_39_image = {22, 22, sizeof(confirming_39_data), + confirming_39_data}; + +static const uint8_t confirming_40_data[248] = { + 0x32, 0x00, 0xf6, 0x0a, 0x34, 0x79, 0xbc, 0xea, 0x0e, 0x0d, 0x08, 0x05, + 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xbc, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, + 0x04, 0x09, 0x00, 0xfe, 0x79, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, + 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, + 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xbc, 0x06, 0xff, 0xfe, 0x79, + 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, + 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, + 0x79, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, + 0x08, 0x04, 0x00, 0xff, 0xbc, 0x05, 0xff, 0xff, 0xbc, 0x04, 0x00, 0xff, + 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, + 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x79, 0x06, 0x00, 0xff, 0x05, 0x04, + 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xbc, 0x03, 0xff, 0xff, 0xbc, 0x08, + 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x79, 0x03, + 0xff, 0x02, 0x34, 0x07, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xff, 0x34, 0x02, 0xff, 0xff, 0xea, 0x0d, 0x10, 0xff, 0x05, 0x04, + 0x00, 0xfd, 0x0a, 0xbc, 0x79, 0x0d, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, + 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, + 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, + 0x10, 0xfe, 0x0a, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, + 0x0e, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_40_image = {22, 22, sizeof(confirming_40_data), + confirming_40_data}; + +static const uint8_t confirming_41_data[245] = { + 0x32, 0x00, 0xf6, 0x0a, 0x34, 0x7a, 0xc0, 0xea, 0x0e, 0x0d, 0x08, 0x05, + 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0a, + 0x04, 0x09, 0x00, 0xfe, 0x7a, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, + 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, + 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x0a, 0xc0, 0x06, 0xff, 0xfe, 0x7a, + 0x08, 0x06, 0x10, 0xfe, 0x0a, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, + 0xfc, 0xea, 0x08, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, + 0x7a, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, + 0x08, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x7a, 0x04, 0x00, 0xff, + 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, + 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x7a, 0x06, 0x00, 0xff, 0x05, 0x04, + 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x08, + 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x7a, 0x03, + 0xff, 0xff, 0x34, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x08, 0x04, + 0x00, 0xfd, 0x34, 0xea, 0x7a, 0x0e, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, + 0x03, 0x0a, 0x0e, 0x10, 0xfe, 0x0a, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, + 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, + 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0a, 0x08, 0x10, 0xfe, 0x0a, + 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, + 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_41_image = {22, 22, sizeof(confirming_41_data), + confirming_41_data}; + +static const uint8_t confirming_42_data[243] = { + 0x32, 0x00, 0xf6, 0x09, 0x34, 0x81, 0xc0, 0xea, 0x0e, 0x0d, 0x09, 0x04, + 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, + 0x04, 0x09, 0x00, 0xfe, 0x34, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0d, + 0x06, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, + 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xc0, 0x06, 0xff, 0xfe, 0x81, + 0x09, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, + 0xfc, 0xea, 0x06, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x04, 0x04, 0x00, 0xff, + 0x81, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, + 0x09, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x81, 0x04, 0x00, 0xff, + 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, + 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x34, 0x06, 0x00, 0xff, 0x06, 0x04, + 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x08, + 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xfb, 0x81, 0xff, + 0xc0, 0x34, 0x04, 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, + 0x00, 0xff, 0x0d, 0x10, 0x10, 0xff, 0x04, 0x04, 0x00, 0xfe, 0x01, 0x0b, + 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, + 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, + 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, + 0x00, 0xfc, 0x01, 0x04, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x04, + 0x01, 0x32, 0x00}; +static const Image confirming_42_image = {22, 22, sizeof(confirming_42_data), + confirming_42_data}; + +static const uint8_t confirming_43_data[244] = { + 0x32, 0x00, 0xf6, 0x09, 0x34, 0x82, 0xca, 0xf3, 0x0e, 0x0c, 0x09, 0x05, + 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xca, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, + 0x04, 0x09, 0x00, 0xfe, 0x34, 0xca, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, + 0x05, 0x07, 0x00, 0xfe, 0x34, 0xca, 0x05, 0xff, 0xfe, 0xf3, 0x0e, 0x05, + 0x10, 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xca, 0x06, 0xff, 0xfe, + 0x82, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, + 0xff, 0xfc, 0xca, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0x82, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xff, 0xca, 0x05, 0xff, 0xff, 0x82, 0x04, 0x00, + 0xff, 0x09, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, + 0xfe, 0xf3, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, + 0x04, 0x00, 0xff, 0xf3, 0x04, 0xff, 0xff, 0x34, 0x06, 0x00, 0xff, 0x05, + 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xfb, 0xca, 0xff, 0xf3, 0xca, 0x34, + 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x0e, + 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, + 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, + 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0c, 0x0c, + 0x10, 0xfe, 0x0c, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0c, 0x0a, 0x10, 0xfe, + 0x0c, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x09, + 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_43_image = {22, 22, sizeof(confirming_43_data), + confirming_43_data}; + +static const uint8_t confirming_44_data[241] = { + 0x32, 0x00, 0xf6, 0x09, 0x34, 0x7a, 0xc0, 0xea, 0x0e, 0x0c, 0x09, 0x05, + 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xc0, 0x04, 0xff, 0x04, 0x10, 0xfe, 0x0b, + 0x04, 0x09, 0x00, 0xfe, 0x7a, 0xea, 0x05, 0xff, 0x05, 0x10, 0xfe, 0x0c, + 0x05, 0x07, 0x00, 0xfe, 0x34, 0xea, 0x06, 0xff, 0xff, 0x0e, 0x05, 0x10, + 0xfe, 0x0c, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xc0, 0x06, 0xff, 0xfe, 0x7a, + 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x34, 0x06, 0xff, + 0xfc, 0xea, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, + 0x7a, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, + 0x09, 0x04, 0x00, 0xff, 0xc0, 0x05, 0xff, 0xff, 0x7a, 0x04, 0x00, 0xff, + 0x09, 0x05, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0xea, 0x04, 0xff, 0xfe, + 0xea, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0xea, 0x04, 0xff, 0xff, 0x7a, 0x06, 0x00, 0xff, 0x05, 0x04, + 0x10, 0xff, 0x0e, 0x04, 0x00, 0x04, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, + 0x0c, 0x03, 0x10, 0xff, 0x0c, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, + 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, + 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, + 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0c, 0x0c, 0x10, 0xfe, 0x0c, + 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0c, 0x0a, 0x10, 0xfe, 0x0c, 0x05, 0x09, + 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, + 0x01, 0x05, 0x09, 0x0c, 0x02, 0x0e, 0xfc, 0x0c, 0x09, 0x05, 0x01, 0x32, + 0x00}; +static const Image confirming_44_image = {22, 22, sizeof(confirming_44_data), + confirming_44_data}; + +static const uint8_t confirming_45_data[239] = { + 0x32, 0x00, 0xff, 0x09, 0x02, 0x6e, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x27, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x6e, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x27, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, + 0x6e, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x6e, 0x06, + 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0x6e, 0x06, 0xff, 0xff, 0x27, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xff, 0xcc, 0x05, 0xff, 0xff, 0x6e, 0x04, 0x00, + 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0x06, 0xff, 0xff, 0x10, + 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0x05, + 0x27, 0xff, 0x0b, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, + 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, + 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, + 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, + 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, + 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, + 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, + 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_45_image = {22, 22, sizeof(confirming_45_data), + confirming_45_data}; + +static const uint8_t confirming_46_data[246] = { + 0x32, 0x00, 0xff, 0x09, 0x02, 0x76, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x30, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x76, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x30, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, + 0x76, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x76, 0x06, + 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0x76, 0x06, 0xff, 0xff, 0x30, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xff, 0xcc, 0x05, 0xff, 0xff, 0x76, 0x04, 0x00, + 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0x02, 0x30, 0xfe, 0x76, + 0xcc, 0x02, 0xff, 0xff, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, + 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, + 0xff, 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, + 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, + 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, + 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, + 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, + 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0e, 0xfc, + 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_46_image = {22, 22, sizeof(confirming_46_data), + confirming_46_data}; + +static const uint8_t confirming_47_data[245] = { + 0x32, 0x00, 0xff, 0x09, 0x02, 0x78, 0xf9, 0xcc, 0xff, 0x0e, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x34, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x78, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x34, 0xcc, 0x06, 0xff, 0xff, 0x0e, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, + 0x78, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x78, 0x06, + 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xff, 0x78, 0x06, 0xff, 0xff, 0x34, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xfe, 0x10, 0x78, 0x04, 0xff, 0xff, 0x78, 0x04, + 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0e, 0x04, + 0x10, 0xfe, 0x78, 0x10, 0x04, 0x00, 0xfe, 0x01, 0x0e, 0x04, 0x10, 0xff, + 0x0e, 0x04, 0x00, 0xff, 0x0e, 0x04, 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, + 0x05, 0x04, 0x10, 0xff, 0x0e, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, + 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, + 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, + 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, + 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, + 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, + 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, + 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0e, 0xfc, 0x0d, + 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_47_image = {22, 22, sizeof(confirming_47_data), + confirming_47_data}; + +static const uint8_t confirming_48_data[247] = { + 0x32, 0x00, 0xfe, 0x09, 0x59, 0x02, 0xcc, 0xfa, 0xff, 0x0f, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x59, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x59, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x59, 0xcc, 0x06, 0xff, 0xff, 0x0f, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, + 0x59, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x59, 0x06, + 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x0f, 0x59, 0x05, 0xff, 0xff, 0x59, 0x02, 0x00, 0xff, 0x04, 0x06, + 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xfd, 0xcc, 0xff, + 0xcc, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, + 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, + 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x05, 0x06, + 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, + 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, + 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x05, 0x03, + 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, + 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, + 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, + 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, + 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, + 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_48_image = {22, 22, sizeof(confirming_48_data), + confirming_48_data}; + +static const uint8_t confirming_49_data[250] = { + 0x32, 0x00, 0xff, 0x09, 0x02, 0x6a, 0xf9, 0xcc, 0xff, 0x0f, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x6a, 0xcc, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x6a, 0xcc, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x6a, 0xcc, 0x06, 0xff, 0xff, 0x0f, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x09, 0xcc, 0x06, 0xff, 0xfe, + 0x6a, 0x07, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xfe, 0x05, 0x6a, + 0x05, 0xff, 0xfc, 0xcc, 0x07, 0x00, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, + 0x00, 0xff, 0x09, 0x02, 0x10, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x10, 0x02, + 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x04, + 0x10, 0xfe, 0x6a, 0xcc, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, + 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, + 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, + 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, + 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, + 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, + 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, + 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, + 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, + 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_49_image = {22, 22, sizeof(confirming_49_data), + confirming_49_data}; + +static const uint8_t confirming_50_data[250] = { + 0x32, 0x00, 0xfe, 0x0a, 0x4e, 0x02, 0xca, 0xfa, 0xff, 0x0f, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x4e, 0xca, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x4e, 0xca, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x4e, 0xca, 0x06, 0xff, 0xff, 0x0f, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x4e, 0x06, 0xff, 0xfe, + 0x4e, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x02, + 0x10, 0xff, 0xca, 0x03, 0xff, 0xfc, 0xca, 0x06, 0x00, 0x0e, 0x06, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x04, 0x10, 0x02, 0xff, 0xff, 0x4e, + 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, + 0x05, 0x10, 0xff, 0x4e, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, + 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, + 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, + 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, + 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, + 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, + 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, + 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, + 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, + 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_50_image = {22, 22, sizeof(confirming_50_data), + confirming_50_data}; + +static const uint8_t confirming_51_data[251] = { + 0x32, 0x00, 0xfe, 0x0a, 0x54, 0x02, 0xd4, 0xfa, 0xff, 0x0f, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x54, 0xd4, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x54, 0xd4, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x05, 0xd4, 0x06, 0xff, 0xff, 0x0f, 0x05, + 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfc, 0x01, 0x0b, 0x10, 0xd4, 0x04, + 0xff, 0xfe, 0x54, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, + 0x05, 0x03, 0x10, 0xff, 0x54, 0x02, 0xff, 0xfc, 0xd4, 0x06, 0x00, 0x0e, + 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0xfe, 0xff, + 0x54, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, + 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, + 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, + 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, + 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, + 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, + 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, + 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, + 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, + 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, + 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, + 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_51_image = {22, 22, sizeof(confirming_51_data), + confirming_51_data}; + +static const uint8_t confirming_52_data[251] = { + 0x32, 0x00, 0xfe, 0x0a, 0x53, 0x02, 0xba, 0xfa, 0xff, 0x0f, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x53, 0xba, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x10, 0xba, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x06, 0x07, 0x00, 0xfd, 0x04, 0x0d, 0x53, 0x05, 0xff, 0xff, 0x0f, + 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x02, 0x10, + 0xff, 0x53, 0x03, 0xff, 0xfe, 0x53, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, + 0x04, 0x00, 0xff, 0x05, 0x04, 0x10, 0xfa, 0x53, 0xff, 0xba, 0x06, 0x00, + 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x05, 0x10, 0x02, + 0x53, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, + 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, + 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, + 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, + 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, + 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, + 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, + 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, + 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, + 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, + 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, + 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_52_image = {22, 22, sizeof(confirming_52_data), + confirming_52_data}; + +static const uint8_t confirming_53_data[251] = { + 0x32, 0x00, 0xfe, 0x0a, 0x52, 0x02, 0xc8, 0xfa, 0xff, 0x0f, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x52, 0xc8, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x10, 0x05, 0xff, 0x05, 0x10, 0xfe, + 0x0d, 0x06, 0x07, 0x00, 0xfc, 0x04, 0x0d, 0x10, 0x52, 0x04, 0xff, 0xff, + 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x03, + 0x10, 0xff, 0xc8, 0x02, 0xff, 0xfe, 0x52, 0x08, 0x06, 0x10, 0xfe, 0x0b, + 0x01, 0x04, 0x00, 0xff, 0x05, 0x05, 0x10, 0xfb, 0xff, 0xc8, 0x06, 0x00, + 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x06, 0x10, 0xff, + 0x52, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, + 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, + 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, + 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, + 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, + 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, + 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, + 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, + 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, + 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, + 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, + 0x08, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_53_image = {22, 22, sizeof(confirming_53_data), + confirming_53_data}; + +static const uint8_t confirming_54_data[249] = { + 0x32, 0x00, 0xff, 0x0a, 0x02, 0x6d, 0xf9, 0xe2, 0xff, 0x0f, 0x0d, 0x08, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x6d, 0x04, 0xff, 0x04, 0x10, 0xfe, + 0x0b, 0x04, 0x09, 0x00, 0xfd, 0x06, 0x0d, 0x10, 0x04, 0xff, 0x05, 0x10, + 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x02, 0x10, 0xff, 0x6d, + 0x03, 0xff, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, + 0x01, 0x0b, 0x04, 0x10, 0x02, 0xff, 0xfe, 0x6d, 0x08, 0x06, 0x10, 0xfe, + 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0xe2, 0x06, 0x00, + 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x08, 0x07, 0x10, 0x02, + 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x0d, 0x05, + 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, + 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, + 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, + 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, + 0x0d, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x00, 0xff, 0x0b, 0x03, 0x10, 0xff, + 0x0d, 0x04, 0x00, 0xff, 0x08, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, + 0x06, 0x03, 0x10, 0xff, 0x08, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, + 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, + 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, + 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, + 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x08, 0x0d, + 0x02, 0x0f, 0xfc, 0x0d, 0x08, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_54_image = {22, 22, sizeof(confirming_54_data), + confirming_54_data}; + +static const uint8_t confirming_55_data[251] = { + 0x32, 0x00, 0xfe, 0x01, 0x10, 0x02, 0xa3, 0xfa, 0xf7, 0x0f, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfd, 0x04, 0x0b, 0xa3, 0x03, 0xff, 0x04, 0x10, + 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x02, 0x10, 0x03, 0xff, + 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x03, 0x10, + 0xfc, 0xa3, 0xff, 0xf7, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, + 0xfe, 0x01, 0x0b, 0x05, 0x10, 0xfd, 0xff, 0xa3, 0x07, 0x06, 0x10, 0xfe, + 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0xa3, 0x07, 0x00, + 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, + 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, + 0x0d, 0x05, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, + 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, + 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, + 0x10, 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, + 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, + 0x03, 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, + 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, + 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, + 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, + 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, + 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_55_image = {22, 22, sizeof(confirming_55_data), + confirming_55_data}; + +static const uint8_t confirming_56_data[250] = { + 0x32, 0x00, 0xfd, 0x01, 0x05, 0x89, 0x02, 0xfb, 0xfb, 0x0f, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfc, 0x04, 0x0b, 0x10, 0x89, 0x02, 0xfb, 0x04, + 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x03, 0x10, 0x02, + 0xfb, 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x04, + 0x10, 0x02, 0xfb, 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, + 0xfe, 0x01, 0x0b, 0x06, 0x10, 0xfe, 0x89, 0x07, 0x06, 0x10, 0xfe, 0x0b, + 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0x0d, 0x07, 0x00, 0x0e, + 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, + 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, + 0x05, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x09, 0x05, 0x10, 0xff, 0x0d, + 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, + 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, + 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, + 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, + 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, + 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, + 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, + 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, + 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_56_image = {22, 22, sizeof(confirming_56_data), + confirming_56_data}; + +static const uint8_t confirming_57_data[250] = { + 0x32, 0x00, 0xfd, 0x01, 0x05, 0x09, 0x02, 0xf8, 0xfb, 0x0f, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x02, 0x10, 0xfe, 0x6a, 0xf8, + 0x04, 0x10, 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x04, 0x10, + 0xff, 0xf8, 0x05, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, 0xfe, 0x04, 0x0d, + 0x05, 0x10, 0xfe, 0xf8, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, + 0xfe, 0x01, 0x0b, 0x06, 0x10, 0xfe, 0x6a, 0x07, 0x06, 0x10, 0xfe, 0x0b, + 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xfc, 0x0d, 0x04, 0x00, 0x0e, + 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, + 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, + 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, + 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, + 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, + 0xff, 0x05, 0x06, 0x00, 0xff, 0x05, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, + 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, + 0xff, 0x05, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, + 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, + 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, 0x00, 0xfe, 0x04, + 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, + 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_57_image = {22, 22, sizeof(confirming_57_data), + confirming_57_data}; + +static const uint8_t confirming_58_data[247] = { + 0x32, 0x00, 0xf6, 0x01, 0x05, 0x09, 0x0d, 0x86, 0x0f, 0x0d, 0x09, 0x05, + 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x03, 0x10, 0xff, 0x86, 0x04, 0x10, + 0xfe, 0x0b, 0x04, 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x04, 0x10, 0xff, 0x86, + 0x05, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, 0xfe, 0x04, 0x0d, 0x06, 0x10, + 0xff, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, 0x0b, + 0x06, 0x10, 0x02, 0x08, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, + 0x05, 0x06, 0x10, 0xff, 0x0d, 0x02, 0x00, 0xff, 0x0e, 0x06, 0x10, 0xff, + 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x04, 0x02, 0x00, 0xff, + 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, 0xff, + 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, + 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, 0x00, 0xfe, 0x01, 0x0f, 0x04, + 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x06, 0x06, + 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, 0x03, + 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, 0x03, 0x10, 0xff, 0x0d, 0x04, + 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, 0x08, 0x03, 0xff, 0x06, 0x03, + 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, + 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, + 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, + 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, + 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, + 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_58_image = {22, 22, sizeof(confirming_58_data), + confirming_58_data}; + +static const uint8_t confirming_59_data[240] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x05, 0x10, 0x02, 0x0f, 0x05, 0x10, 0xfe, 0x0d, 0x04, + 0x05, 0x00, 0xfe, 0x01, 0x0b, 0x06, 0x10, 0x02, 0x08, 0x06, 0x10, 0xfe, + 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x06, 0x10, 0xff, 0x0d, 0x02, 0x00, + 0xff, 0x0e, 0x06, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, + 0xff, 0x04, 0x02, 0x00, 0xff, 0x04, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, + 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0a, 0x04, 0x00, 0xff, 0x0a, 0x05, 0x10, + 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x01, 0x04, + 0x00, 0xfe, 0x01, 0x0f, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, + 0x04, 0x10, 0xff, 0x06, 0x06, 0x00, 0xff, 0x06, 0x04, 0x10, 0xff, 0x0f, + 0x04, 0x00, 0xff, 0x0d, 0x03, 0x10, 0xff, 0x0c, 0x08, 0x00, 0xff, 0x0c, + 0x03, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x05, + 0x08, 0x03, 0xff, 0x06, 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, + 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, + 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, + 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, + 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, + 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_59_image = {22, 22, sizeof(confirming_59_data), + confirming_59_data}; + +static const uint8_t confirming_60_data[236] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, + 0x0b, 0x06, 0x10, 0x02, 0x0c, 0x06, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, + 0xff, 0x05, 0x06, 0x10, 0xff, 0x0f, 0x02, 0x08, 0xff, 0x0f, 0x06, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x06, 0x10, 0xff, 0x0a, 0x02, 0x08, + 0xff, 0x0a, 0x06, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x0d, 0x05, 0x10, + 0xff, 0x0d, 0x04, 0x08, 0xff, 0x0d, 0x05, 0x10, 0xff, 0x0d, 0x04, 0x00, + 0xff, 0x0f, 0x04, 0x10, 0xfe, 0x0f, 0x09, 0x04, 0x08, 0xfe, 0x09, 0x0f, + 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x04, 0x10, 0xff, 0x0b, + 0x06, 0x08, 0xff, 0x0b, 0x04, 0x10, 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0d, + 0x03, 0x10, 0xff, 0x0e, 0x08, 0x08, 0xff, 0x0e, 0x03, 0x10, 0xff, 0x0d, + 0x04, 0x00, 0xff, 0x09, 0x03, 0x10, 0xff, 0x0b, 0x08, 0x0a, 0xff, 0x0b, + 0x03, 0x10, 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, + 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, + 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, + 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, + 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, + 0x0f, 0xfc, 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_60_image = {22, 22, sizeof(confirming_60_data), + confirming_60_data}; + +static const uint8_t confirming_61_data[174] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x09, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x06, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x06, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x05, 0x00, 0xfe, 0x01, + 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, + 0xff, 0x05, 0x04, 0x00, 0xff, 0x09, 0x10, 0x10, 0xff, 0x09, 0x04, 0x00, + 0xff, 0x0d, 0x10, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x10, 0x10, + 0xff, 0x0f, 0x04, 0x00, 0xff, 0x0f, 0x10, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xff, 0x0d, 0x10, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x09, 0x10, 0x10, + 0xff, 0x09, 0x04, 0x00, 0xff, 0x05, 0x10, 0x10, 0xff, 0x05, 0x04, 0x00, + 0xfe, 0x01, 0x0b, 0x0e, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, 0xfe, 0x04, + 0x0d, 0x0c, 0x10, 0xfe, 0x0d, 0x04, 0x07, 0x00, 0xfe, 0x06, 0x0d, 0x0a, + 0x10, 0xfe, 0x0d, 0x06, 0x09, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, + 0x0b, 0x04, 0x0b, 0x00, 0xfc, 0x01, 0x05, 0x09, 0x0d, 0x02, 0x0f, 0xfc, + 0x0d, 0x09, 0x05, 0x01, 0x32, 0x00}; +static const Image confirming_61_image = {22, 22, sizeof(confirming_61_data), + confirming_61_data}; + +static const uint8_t confirming_62_data[277] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x23, 0x44, 0x10, 0x0d, 0x04, 0x05, + 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x23, 0x5c, 0x44, 0x02, 0x10, + 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x23, 0x5c, + 0x60, 0x44, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, + 0xfe, 0x17, 0x54, 0x02, 0x60, 0xff, 0x44, 0x03, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0x44, 0x03, 0x60, 0xff, 0x54, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x17, 0x23, + 0x02, 0x10, 0xff, 0x31, 0x03, 0x60, 0xff, 0x31, 0x04, 0x10, 0xff, 0x0f, + 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x23, 0x02, 0x54, 0x02, 0x10, + 0xff, 0x54, 0x02, 0x60, 0xff, 0x31, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xfd, 0x0d, 0x10, 0x44, 0x03, 0x60, 0x02, 0x31, 0x02, 0x60, 0xff, 0x31, + 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xfd, 0x31, + 0x5c, 0x60, 0x02, 0x54, 0xfe, 0x60, 0x44, 0x07, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x23, 0x5c, 0x02, 0x60, 0xff, 0x54, + 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, + 0x23, 0x02, 0x5c, 0xff, 0x17, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, + 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x23, 0x31, 0x07, 0x10, 0xfe, 0x0d, + 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, + 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, + 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, + 0x00}; +static const Image confirming_62_image = {22, 22, sizeof(confirming_62_data), + confirming_62_data}; + +static const uint8_t confirming_63_data[277] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x36, 0x78, 0x10, 0x0d, 0x04, 0x05, + 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x36, 0xa5, 0x78, 0x02, 0x10, + 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x36, 0xa5, + 0xaf, 0x78, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, + 0xfe, 0x1d, 0xa5, 0x02, 0xaf, 0xff, 0x78, 0x03, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0x78, 0x03, 0xaf, 0xff, 0x97, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x1d, 0x36, + 0x02, 0x10, 0xff, 0x52, 0x03, 0xaf, 0xff, 0x52, 0x04, 0x10, 0xff, 0x0f, + 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x36, 0x02, 0x97, 0x02, 0x10, + 0xff, 0x97, 0x02, 0xaf, 0xff, 0x52, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xfd, 0x0d, 0x10, 0x78, 0x03, 0xaf, 0x02, 0x52, 0x02, 0xaf, 0xff, 0x52, + 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xff, 0x52, + 0x02, 0xaf, 0x02, 0x97, 0xfe, 0xaf, 0x78, 0x07, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x36, 0xa5, 0x02, 0xaf, 0xff, 0x97, + 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, + 0x36, 0x02, 0xa5, 0xff, 0x1d, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, + 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x36, 0x52, 0x07, 0x10, 0xfe, 0x0d, + 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, + 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, + 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, + 0x00}; +static const Image confirming_63_image = {22, 22, sizeof(confirming_63_data), + confirming_63_data}; + +static const uint8_t confirming_64_data[277] = { + 0x32, 0x00, 0xfc, 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, + 0x05, 0x01, 0x0b, 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, + 0x09, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x07, 0x00, + 0xfe, 0x04, 0x0d, 0x09, 0x10, 0xfb, 0x4a, 0xac, 0x10, 0x0d, 0x04, 0x05, + 0x00, 0xfe, 0x01, 0x0b, 0x09, 0x10, 0xfd, 0x4a, 0xf0, 0xac, 0x02, 0x10, + 0xfe, 0x0b, 0x01, 0x04, 0x00, 0xff, 0x05, 0x09, 0x10, 0xfc, 0x4a, 0xf0, + 0xff, 0xac, 0x03, 0x10, 0xff, 0x05, 0x04, 0x00, 0xff, 0x07, 0x08, 0x10, + 0xfe, 0x24, 0xf0, 0x02, 0xff, 0xff, 0xac, 0x03, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x0d, 0x08, 0x10, 0xff, 0xac, 0x03, 0xff, 0xff, 0xdb, 0x03, + 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x0f, 0x03, 0x10, 0xfe, 0x24, 0x4a, + 0x02, 0x10, 0xff, 0x73, 0x03, 0xff, 0xff, 0x73, 0x04, 0x10, 0xff, 0x0f, + 0x04, 0x00, 0xff, 0x0f, 0x02, 0x10, 0xff, 0x4a, 0x02, 0xdb, 0x02, 0x10, + 0xff, 0xdb, 0x02, 0xff, 0xff, 0x73, 0x05, 0x10, 0xff, 0x0f, 0x04, 0x00, + 0xfd, 0x0d, 0x10, 0xac, 0x03, 0xff, 0x02, 0x73, 0x02, 0xff, 0xff, 0x73, + 0x06, 0x10, 0xff, 0x0d, 0x04, 0x00, 0xff, 0x07, 0x02, 0x10, 0xff, 0x73, + 0x02, 0xff, 0x02, 0xdb, 0xfe, 0xff, 0xac, 0x07, 0x10, 0xff, 0x07, 0x04, + 0x00, 0xff, 0x05, 0x03, 0x10, 0xfe, 0x4a, 0xf0, 0x02, 0xff, 0xff, 0xdb, + 0x08, 0x10, 0xff, 0x05, 0x04, 0x00, 0xfe, 0x01, 0x0b, 0x03, 0x10, 0xff, + 0x4a, 0x02, 0xf0, 0xff, 0x24, 0x07, 0x10, 0xfe, 0x0b, 0x01, 0x05, 0x00, + 0xfe, 0x04, 0x0d, 0x03, 0x10, 0xfe, 0x4a, 0x73, 0x07, 0x10, 0xfe, 0x0d, + 0x04, 0x07, 0x00, 0xfe, 0x05, 0x0d, 0x0a, 0x10, 0xfe, 0x0d, 0x05, 0x09, + 0x00, 0xfe, 0x04, 0x0b, 0x08, 0x10, 0xfe, 0x0b, 0x04, 0x0b, 0x00, 0xfc, + 0x01, 0x05, 0x07, 0x0d, 0x02, 0x0f, 0xfc, 0x0d, 0x07, 0x05, 0x01, 0x32, + 0x00}; +static const Image confirming_64_image = {22, 22, sizeof(confirming_64_data), + confirming_64_data}; const VariantAnimation confirming = { 64, @@ -484,51 +1720,113 @@ const VariantAnimation confirming = { {231, 2, 20, 100, &confirming_62_image}, {231, 2, 20, 100, &confirming_63_image}, {231, 2, 20, 100, &confirming_64_image}, - } -}; + }}; /* --- Warning Animation --------------------------------------------------- */ -static const uint8_t warning_1_data[446] = -{ - 0x11, 0x00, 0xf9, 0x17, 0x8c, 0xd2, 0xe5, 0xd2, 0x8c, 0x17, 0x21, 0x00, 0xfe, 0x2e, 0xd2, 0x05, 0xe5, 0xfe, 0xd2, 0x2e, 0x1f, 0x00, 0xfe, 0x22, 0xd2, 0x07, 0xe5, 0xfe, 0xd2, 0x22, 0x1e, 0x00, 0xff, 0xb8, 0x09, 0xe5, 0xff, 0xb8, 0x1d, 0x00, 0xff, 0x58, 0x0b, 0xe5, 0xff, 0x58, 0x1b, 0x00, 0xfe, 0x0b, 0xd2, 0x0b, 0xe5, 0xfe, 0xd2, 0x0b, 0x1a, 0x00, 0xff, 0x72, 0x0d, 0xe5, 0xff, 0x72, 0x19, 0x00, 0xff, 0x22, 0x0f, 0xe5, 0xff, 0x22, 0x18, 0x00, 0xff, 0xa1, 0x0f, 0xe5, 0xff, 0xa1, 0x17, 0x00, 0xff, 0x3a, 0x11, 0xe5, 0xff, 0x3a, 0x16, 0x00, 0xff, 0xb8, 0x07, 0xe5, 0xfc, 0x8c, 0x3a, 0x58, 0xd2, 0x06, 0xe5, 0xff, 0xb8, 0x15, 0x00, 0xff, 0x58, 0x07, 0xe5, 0xff, 0x72, 0x03, 0x00, 0xfe, 0x17, 0xd2, 0x06, 0xe5, 0xff, 0x58, 0x13, 0x00, 0xfe, 0x17, 0xd2, 0x07, 0xe5, 0xff, 0x17, 0x04, 0x00, 0xff, 0xa1, 0x06, 0xe5, 0xfe, 0xd2, 0x17, 0x12, 0x00, 0xff, 0x8c, 0x08, 0xe5, 0xff, 0x17, 0x04, 0x00, 0xff, 0x8c, 0x07, 0xe5, 0xff, 0x8c, 0x11, 0x00, 0xff, 0x2e, 0x09, 0xe5, 0xff, 0x2e, 0x04, 0x00, 0xff, 0xa1, 0x08, 0xe5, 0xff, 0x2e, 0x10, 0x00, 0xff, 0xa1, 0x09, 0xe5, 0xff, 0x3a, 0x04, 0x00, 0xff, 0xb8, 0x08, 0xe5, 0xff, 0xa1, 0x0f, 0x00, 0xff, 0x46, 0x0a, 0xe5, 0xff, 0x46, 0x04, 0x00, 0xff, 0xd2, 0x09, 0xe5, 0xff, 0x46, 0x0d, 0x00, 0xfe, 0x0b, 0xd2, 0x0a, 0xe5, 0xff, 0x58, 0x04, 0x00, 0xff, 0xd2, 0x09, 0xe5, 0xfe, 0xd2, 0x0b, 0x0c, 0x00, 0xff, 0x72, 0x0b, 0xe5, 0xff, 0x58, 0x04, 0x00, 0x0b, 0xe5, 0xff, 0x72, 0x0b, 0x00, 0xff, 0x17, 0x0c, 0xe5, 0xff, 0x72, 0x03, 0x00, 0xff, 0x0b, 0x0c, 0xe5, 0xff, 0x17, 0x0a, 0x00, 0xff, 0x8c, 0x0c, 0xe5, 0xff, 0x8c, 0x03, 0x00, 0xff, 0x22, 0x0c, 0xe5, 0xff, 0x8c, 0x09, 0x00, 0xff, 0x2e, 0x0d, 0xe5, 0xff, 0x8c, 0x03, 0x00, 0xff, 0x2e, 0x0d, 0xe5, 0xff, 0x2e, 0x08, 0x00, 0xff, 0xb8, 0x0d, 0xe5, 0xff, 0xb8, 0x03, 0x00, 0xff, 0x46, 0x0d, 0xe5, 0xff, 0xb8, 0x07, 0x00, 0xff, 0x58, 0x0f, 0xe5, 0xfc, 0x46, 0x00, 0x0b, 0xb8, 0x0e, 0xe5, 0xff, 0x58, 0x05, 0x00, 0xfe, 0x0b, 0xd2, 0x10, 0xe5, 0xfe, 0xb8, 0xd2, 0x0f, 0xe5, 0xfe, 0xd2, 0x0b, 0x04, 0x00, 0xff, 0x8c, 0x23, 0xe5, 0xff, 0x8c, 0x03, 0x00, 0xff, 0x22, 0x10, 0xe5, 0xfb, 0xd2, 0x58, 0x00, 0x22, 0xa1, 0x10, 0xe5, 0xff, 0x22, 0x02, 0x00, 0xff, 0xa1, 0x10, 0xe5, 0xff, 0x58, 0x03, 0x00, 0xfe, 0x0b, 0xd2, 0x0f, 0xe5, 0xfd, 0xa1, 0x00, 0x2e, 0x11, 0xe5, 0xff, 0x22, 0x04, 0x00, 0xff, 0xa1, 0x10, 0xe5, 0xfe, 0x2e, 0x8c, 0x11, 0xe5, 0xff, 0x58, 0x04, 0x00, 0xff, 0xd2, 0x10, 0xe5, 0xfe, 0x8c, 0xd2, 0x11, 0xe5, 0xfb, 0xd2, 0x2e, 0x00, 0x0b, 0x8c, 0x11, 0xe5, 0xff, 0xd2, 0x14, 0xe5, 0xff, 0xd2, 0x3d, 0xe5, 0xff, 0xa1, 0x27, 0xe5, 0xfe, 0xa1, 0x2e, 0x27, 0xe5, 0xfd, 0x2e, 0x00, 0x58, 0x25, 0xe5, 0xff, 0x58, 0x03, 0x00, 0xfd, 0x17, 0x72, 0xb8, 0x1f, 0xe5, 0xfd, 0xb8, 0x72, 0x17, 0x02, 0x00 -}; -static const Image warning_1_image = {41, 37, sizeof(warning_1_data), warning_1_data}; - -const VariantAnimation warning = { - 21, - { - {107, 7, 500, 100, &warning_1_image}, - {107, 7, 50, 90, &warning_1_image}, - {107, 7, 50, 80, &warning_1_image}, - {107, 7, 50, 70, &warning_1_image}, - {107, 7, 50, 60, &warning_1_image}, - {107, 7, 50, 50, &warning_1_image}, - {107, 7, 50, 40, &warning_1_image}, - {107, 7, 50, 30, &warning_1_image}, - {107, 7, 50, 20, &warning_1_image}, - {107, 7, 50, 10, &warning_1_image}, - {107, 7, 50, 0, &warning_1_image}, - {107, 7, 50, 10, &warning_1_image}, - {107, 7, 50, 20, &warning_1_image}, - {107, 7, 50, 30, &warning_1_image}, - {107, 7, 50, 40, &warning_1_image}, - {107, 7, 50, 50, &warning_1_image}, - {107, 7, 50, 60, &warning_1_image}, - {107, 7, 50, 70, &warning_1_image}, - {107, 7, 50, 80, &warning_1_image}, - {107, 7, 50, 90, &warning_1_image}, - {107, 7, 50, 100, &warning_1_image}, - } -}; - +static const uint8_t warning_1_data[446] = { + 0x11, 0x00, 0xf9, 0x17, 0x8c, 0xd2, 0xe5, 0xd2, 0x8c, 0x17, 0x21, 0x00, + 0xfe, 0x2e, 0xd2, 0x05, 0xe5, 0xfe, 0xd2, 0x2e, 0x1f, 0x00, 0xfe, 0x22, + 0xd2, 0x07, 0xe5, 0xfe, 0xd2, 0x22, 0x1e, 0x00, 0xff, 0xb8, 0x09, 0xe5, + 0xff, 0xb8, 0x1d, 0x00, 0xff, 0x58, 0x0b, 0xe5, 0xff, 0x58, 0x1b, 0x00, + 0xfe, 0x0b, 0xd2, 0x0b, 0xe5, 0xfe, 0xd2, 0x0b, 0x1a, 0x00, 0xff, 0x72, + 0x0d, 0xe5, 0xff, 0x72, 0x19, 0x00, 0xff, 0x22, 0x0f, 0xe5, 0xff, 0x22, + 0x18, 0x00, 0xff, 0xa1, 0x0f, 0xe5, 0xff, 0xa1, 0x17, 0x00, 0xff, 0x3a, + 0x11, 0xe5, 0xff, 0x3a, 0x16, 0x00, 0xff, 0xb8, 0x07, 0xe5, 0xfc, 0x8c, + 0x3a, 0x58, 0xd2, 0x06, 0xe5, 0xff, 0xb8, 0x15, 0x00, 0xff, 0x58, 0x07, + 0xe5, 0xff, 0x72, 0x03, 0x00, 0xfe, 0x17, 0xd2, 0x06, 0xe5, 0xff, 0x58, + 0x13, 0x00, 0xfe, 0x17, 0xd2, 0x07, 0xe5, 0xff, 0x17, 0x04, 0x00, 0xff, + 0xa1, 0x06, 0xe5, 0xfe, 0xd2, 0x17, 0x12, 0x00, 0xff, 0x8c, 0x08, 0xe5, + 0xff, 0x17, 0x04, 0x00, 0xff, 0x8c, 0x07, 0xe5, 0xff, 0x8c, 0x11, 0x00, + 0xff, 0x2e, 0x09, 0xe5, 0xff, 0x2e, 0x04, 0x00, 0xff, 0xa1, 0x08, 0xe5, + 0xff, 0x2e, 0x10, 0x00, 0xff, 0xa1, 0x09, 0xe5, 0xff, 0x3a, 0x04, 0x00, + 0xff, 0xb8, 0x08, 0xe5, 0xff, 0xa1, 0x0f, 0x00, 0xff, 0x46, 0x0a, 0xe5, + 0xff, 0x46, 0x04, 0x00, 0xff, 0xd2, 0x09, 0xe5, 0xff, 0x46, 0x0d, 0x00, + 0xfe, 0x0b, 0xd2, 0x0a, 0xe5, 0xff, 0x58, 0x04, 0x00, 0xff, 0xd2, 0x09, + 0xe5, 0xfe, 0xd2, 0x0b, 0x0c, 0x00, 0xff, 0x72, 0x0b, 0xe5, 0xff, 0x58, + 0x04, 0x00, 0x0b, 0xe5, 0xff, 0x72, 0x0b, 0x00, 0xff, 0x17, 0x0c, 0xe5, + 0xff, 0x72, 0x03, 0x00, 0xff, 0x0b, 0x0c, 0xe5, 0xff, 0x17, 0x0a, 0x00, + 0xff, 0x8c, 0x0c, 0xe5, 0xff, 0x8c, 0x03, 0x00, 0xff, 0x22, 0x0c, 0xe5, + 0xff, 0x8c, 0x09, 0x00, 0xff, 0x2e, 0x0d, 0xe5, 0xff, 0x8c, 0x03, 0x00, + 0xff, 0x2e, 0x0d, 0xe5, 0xff, 0x2e, 0x08, 0x00, 0xff, 0xb8, 0x0d, 0xe5, + 0xff, 0xb8, 0x03, 0x00, 0xff, 0x46, 0x0d, 0xe5, 0xff, 0xb8, 0x07, 0x00, + 0xff, 0x58, 0x0f, 0xe5, 0xfc, 0x46, 0x00, 0x0b, 0xb8, 0x0e, 0xe5, 0xff, + 0x58, 0x05, 0x00, 0xfe, 0x0b, 0xd2, 0x10, 0xe5, 0xfe, 0xb8, 0xd2, 0x0f, + 0xe5, 0xfe, 0xd2, 0x0b, 0x04, 0x00, 0xff, 0x8c, 0x23, 0xe5, 0xff, 0x8c, + 0x03, 0x00, 0xff, 0x22, 0x10, 0xe5, 0xfb, 0xd2, 0x58, 0x00, 0x22, 0xa1, + 0x10, 0xe5, 0xff, 0x22, 0x02, 0x00, 0xff, 0xa1, 0x10, 0xe5, 0xff, 0x58, + 0x03, 0x00, 0xfe, 0x0b, 0xd2, 0x0f, 0xe5, 0xfd, 0xa1, 0x00, 0x2e, 0x11, + 0xe5, 0xff, 0x22, 0x04, 0x00, 0xff, 0xa1, 0x10, 0xe5, 0xfe, 0x2e, 0x8c, + 0x11, 0xe5, 0xff, 0x58, 0x04, 0x00, 0xff, 0xd2, 0x10, 0xe5, 0xfe, 0x8c, + 0xd2, 0x11, 0xe5, 0xfb, 0xd2, 0x2e, 0x00, 0x0b, 0x8c, 0x11, 0xe5, 0xff, + 0xd2, 0x14, 0xe5, 0xff, 0xd2, 0x3d, 0xe5, 0xff, 0xa1, 0x27, 0xe5, 0xfe, + 0xa1, 0x2e, 0x27, 0xe5, 0xfd, 0x2e, 0x00, 0x58, 0x25, 0xe5, 0xff, 0x58, + 0x03, 0x00, 0xfd, 0x17, 0x72, 0xb8, 0x1f, 0xe5, 0xfd, 0xb8, 0x72, 0x17, + 0x02, 0x00}; +static const Image warning_1_image = {41, 37, sizeof(warning_1_data), + warning_1_data}; + +const VariantAnimation warning = {21, + { + {107, 7, 500, 100, &warning_1_image}, + {107, 7, 50, 90, &warning_1_image}, + {107, 7, 50, 80, &warning_1_image}, + {107, 7, 50, 70, &warning_1_image}, + {107, 7, 50, 60, &warning_1_image}, + {107, 7, 50, 50, &warning_1_image}, + {107, 7, 50, 40, &warning_1_image}, + {107, 7, 50, 30, &warning_1_image}, + {107, 7, 50, 20, &warning_1_image}, + {107, 7, 50, 10, &warning_1_image}, + {107, 7, 50, 0, &warning_1_image}, + {107, 7, 50, 10, &warning_1_image}, + {107, 7, 50, 20, &warning_1_image}, + {107, 7, 50, 30, &warning_1_image}, + {107, 7, 50, 40, &warning_1_image}, + {107, 7, 50, 50, &warning_1_image}, + {107, 7, 50, 60, &warning_1_image}, + {107, 7, 50, 70, &warning_1_image}, + {107, 7, 50, 80, &warning_1_image}, + {107, 7, 50, 90, &warning_1_image}, + {107, 7, 50, 100, &warning_1_image}, + }}; /* --- Unplug Image -------------------------------------------------------- */ -static const uint8_t unplug_data[395] = -{ - 0x2b, 0x00, 0xfe, 0xa5, 0x11, 0x2a, 0x00, 0xfd, 0x21, 0xd2, 0x4d, 0x29, 0x00, 0xfc, 0x21, 0xb7, 0xc6, 0x21, 0x26, 0x00, 0xfa, 0x03, 0x33, 0x88, 0xd2, 0xc6, 0x33, 0x1b, 0x00, 0xfb, 0x07, 0x6b, 0xc6, 0x4d, 0x03, 0x04, 0x00, 0xf7, 0x21, 0x6b, 0x88, 0xc6, 0xd2, 0xc6, 0x88, 0x11, 0x01, 0x18, 0x00, 0xfc, 0x11, 0x01, 0x4d, 0xb7, 0x02, 0xd2, 0xfe, 0xc6, 0x11, 0x02, 0x00, 0xfe, 0x33, 0x88, 0x02, 0xd2, 0xfc, 0xb7, 0x88, 0x4d, 0x07, 0x19, 0x00, 0xfc, 0x03, 0xa5, 0xd2, 0xa5, 0x05, 0xd2, 0xf9, 0x88, 0x07, 0x88, 0xd2, 0xc6, 0x6b, 0x21, 0x1d, 0x00, 0xfe, 0x03, 0xb7, 0x08, 0xd2, 0xfc, 0xb7, 0xd2, 0x6b, 0x07, 0x20, 0x00, 0xff, 0x33, 0x09, 0xd2, 0xfd, 0x4d, 0x00, 0x03, 0x20, 0x00, 0xfe, 0x01, 0x88, 0x08, 0xd2, 0xff, 0x4d, 0x1b, 0x00, 0xfe, 0x11, 0x07, 0x04, 0x00, 0xfd, 0x03, 0x6b, 0xc6, 0x08, 0xd2, 0xfe, 0xc6, 0x11, 0x18, 0x00, 0xfc, 0x01, 0x33, 0xd2, 0xa5, 0x03, 0x00, 0xfb, 0x4d, 0xb7, 0xd2, 0xa5, 0x88, 0x08, 0xd2, 0xff, 0x6b, 0x18, 0x00, 0xfe, 0x07, 0x6b, 0x02, 0xd2, 0xf7, 0x33, 0x00, 0x4d, 0xd2, 0xb7, 0x33, 0x00, 0x07, 0xb7, 0x08, 0xd2, 0xff, 0x21, 0x15, 0x00, 0xfd, 0x01, 0x4d, 0xb7, 0x04, 0xd2, 0xfd, 0x03, 0x07, 0x4d, 0x02, 0x03, 0xfd, 0x00, 0x11, 0x88, 0x07, 0xd2, 0xfe, 0xc6, 0x33, 0x14, 0x00, 0xfe, 0x21, 0xa5, 0x06, 0xd2, 0xff, 0x6b, 0x03, 0x00, 0xfb, 0x03, 0x4d, 0xc6, 0xd2, 0xc6, 0x05, 0xd2, 0xfe, 0x88, 0x11, 0x15, 0x00, 0xff, 0x88, 0x08, 0xd2, 0xf8, 0x07, 0x03, 0x21, 0xa5, 0xd2, 0xa5, 0x33, 0x21, 0x03, 0xd2, 0xfe, 0xa5, 0x33, 0x17, 0x00, 0xfe, 0x21, 0xc6, 0x07, 0xd2, 0xfa, 0x88, 0x03, 0x21, 0xb7, 0x4d, 0x01, 0x02, 0x00, 0xff, 0x88, 0x02, 0xd2, 0xff, 0x07, 0x19, 0x00, 0xff, 0x6b, 0x08, 0xd2, 0xfd, 0x21, 0x00, 0x01, 0x04, 0x00, 0xfd, 0x11, 0xb7, 0x4d, 0x19, 0x00, 0xfd, 0x01, 0x11, 0xb7, 0x07, 0xd2, 0xfe, 0xc6, 0x01, 0x23, 0x00, 0xff, 0x6b, 0x08, 0xd2, 0xff, 0x4d, 0x22, 0x00, 0xfe, 0x33, 0xc6, 0x09, 0xd2, 0xff, 0x03, 0x1f, 0x00, 0xfb, 0x21, 0x88, 0xd2, 0xb7, 0x4d, 0x08, 0xd2, 0xfe, 0x6b, 0x01, 0x1a, 0x00, 0xfc, 0x03, 0x33, 0x6b, 0xa5, 0x02, 0xd2, 0xfc, 0x6b, 0x03, 0x00, 0x88, 0x04, 0xd2, 0xfc, 0x88, 0x4d, 0x6b, 0x07, 0x17, 0x00, 0xfb, 0x03, 0x11, 0x4d, 0xa5, 0xc6, 0x02, 0xd2, 0xfd, 0xa5, 0x6b, 0x11, 0x03, 0x00, 0xfb, 0x11, 0xc6, 0xd2, 0xa5, 0x33, 0x1a, 0x00, 0xfe, 0x11, 0x88, 0x02, 0xd2, 0xfc, 0xa5, 0x6b, 0x4d, 0x11, 0x07, 0x00, 0xfe, 0x33, 0x4d, 0x1c, 0x00, 0xfc, 0x88, 0xd2, 0x6b, 0x21, 0x02, 0x03, 0x27, 0x00, 0xfe, 0x6b, 0x4d, 0x2b, 0x00 -}; +static const uint8_t unplug_data[395] = { + 0x2b, 0x00, 0xfe, 0xa5, 0x11, 0x2a, 0x00, 0xfd, 0x21, 0xd2, 0x4d, 0x29, + 0x00, 0xfc, 0x21, 0xb7, 0xc6, 0x21, 0x26, 0x00, 0xfa, 0x03, 0x33, 0x88, + 0xd2, 0xc6, 0x33, 0x1b, 0x00, 0xfb, 0x07, 0x6b, 0xc6, 0x4d, 0x03, 0x04, + 0x00, 0xf7, 0x21, 0x6b, 0x88, 0xc6, 0xd2, 0xc6, 0x88, 0x11, 0x01, 0x18, + 0x00, 0xfc, 0x11, 0x01, 0x4d, 0xb7, 0x02, 0xd2, 0xfe, 0xc6, 0x11, 0x02, + 0x00, 0xfe, 0x33, 0x88, 0x02, 0xd2, 0xfc, 0xb7, 0x88, 0x4d, 0x07, 0x19, + 0x00, 0xfc, 0x03, 0xa5, 0xd2, 0xa5, 0x05, 0xd2, 0xf9, 0x88, 0x07, 0x88, + 0xd2, 0xc6, 0x6b, 0x21, 0x1d, 0x00, 0xfe, 0x03, 0xb7, 0x08, 0xd2, 0xfc, + 0xb7, 0xd2, 0x6b, 0x07, 0x20, 0x00, 0xff, 0x33, 0x09, 0xd2, 0xfd, 0x4d, + 0x00, 0x03, 0x20, 0x00, 0xfe, 0x01, 0x88, 0x08, 0xd2, 0xff, 0x4d, 0x1b, + 0x00, 0xfe, 0x11, 0x07, 0x04, 0x00, 0xfd, 0x03, 0x6b, 0xc6, 0x08, 0xd2, + 0xfe, 0xc6, 0x11, 0x18, 0x00, 0xfc, 0x01, 0x33, 0xd2, 0xa5, 0x03, 0x00, + 0xfb, 0x4d, 0xb7, 0xd2, 0xa5, 0x88, 0x08, 0xd2, 0xff, 0x6b, 0x18, 0x00, + 0xfe, 0x07, 0x6b, 0x02, 0xd2, 0xf7, 0x33, 0x00, 0x4d, 0xd2, 0xb7, 0x33, + 0x00, 0x07, 0xb7, 0x08, 0xd2, 0xff, 0x21, 0x15, 0x00, 0xfd, 0x01, 0x4d, + 0xb7, 0x04, 0xd2, 0xfd, 0x03, 0x07, 0x4d, 0x02, 0x03, 0xfd, 0x00, 0x11, + 0x88, 0x07, 0xd2, 0xfe, 0xc6, 0x33, 0x14, 0x00, 0xfe, 0x21, 0xa5, 0x06, + 0xd2, 0xff, 0x6b, 0x03, 0x00, 0xfb, 0x03, 0x4d, 0xc6, 0xd2, 0xc6, 0x05, + 0xd2, 0xfe, 0x88, 0x11, 0x15, 0x00, 0xff, 0x88, 0x08, 0xd2, 0xf8, 0x07, + 0x03, 0x21, 0xa5, 0xd2, 0xa5, 0x33, 0x21, 0x03, 0xd2, 0xfe, 0xa5, 0x33, + 0x17, 0x00, 0xfe, 0x21, 0xc6, 0x07, 0xd2, 0xfa, 0x88, 0x03, 0x21, 0xb7, + 0x4d, 0x01, 0x02, 0x00, 0xff, 0x88, 0x02, 0xd2, 0xff, 0x07, 0x19, 0x00, + 0xff, 0x6b, 0x08, 0xd2, 0xfd, 0x21, 0x00, 0x01, 0x04, 0x00, 0xfd, 0x11, + 0xb7, 0x4d, 0x19, 0x00, 0xfd, 0x01, 0x11, 0xb7, 0x07, 0xd2, 0xfe, 0xc6, + 0x01, 0x23, 0x00, 0xff, 0x6b, 0x08, 0xd2, 0xff, 0x4d, 0x22, 0x00, 0xfe, + 0x33, 0xc6, 0x09, 0xd2, 0xff, 0x03, 0x1f, 0x00, 0xfb, 0x21, 0x88, 0xd2, + 0xb7, 0x4d, 0x08, 0xd2, 0xfe, 0x6b, 0x01, 0x1a, 0x00, 0xfc, 0x03, 0x33, + 0x6b, 0xa5, 0x02, 0xd2, 0xfc, 0x6b, 0x03, 0x00, 0x88, 0x04, 0xd2, 0xfc, + 0x88, 0x4d, 0x6b, 0x07, 0x17, 0x00, 0xfb, 0x03, 0x11, 0x4d, 0xa5, 0xc6, + 0x02, 0xd2, 0xfd, 0xa5, 0x6b, 0x11, 0x03, 0x00, 0xfb, 0x11, 0xc6, 0xd2, + 0xa5, 0x33, 0x1a, 0x00, 0xfe, 0x11, 0x88, 0x02, 0xd2, 0xfc, 0xa5, 0x6b, + 0x4d, 0x11, 0x07, 0x00, 0xfe, 0x33, 0x4d, 0x1c, 0x00, 0xfc, 0x88, 0xd2, + 0x6b, 0x21, 0x02, 0x03, 0x27, 0x00, 0xfe, 0x6b, 0x4d, 0x2b, 0x00}; static const Image unplug_image = {45, 27, sizeof(unplug_data), unplug_data}; const AnimationFrame unplug_frame = {208, 21, 20, 100, &unplug_image}; @@ -540,9 +1838,8 @@ const AnimationFrame unplug_frame = {208, 21, 20, 100, &unplug_image}; * OUTPUT * confirm icon frame */ -const AnimationFrame *get_confirm_icon_frame(void) -{ - return &confirm_icon_frame; +const AnimationFrame *get_confirm_icon_frame(void) { + return &confirm_icon_frame; } /* @@ -553,10 +1850,9 @@ const AnimationFrame *get_confirm_icon_frame(void) * OUTPUT * confirmed frame */ -const AnimationFrame *get_confirmed_frame(void) -{ - // the confirmed image is the final frame of the confirming animation - return &confirming.frames[confirming.count-1]; +const AnimationFrame *get_confirmed_frame(void) { + // the confirmed image is the final frame of the confirming animation + return &confirming.frames[confirming.count - 1]; } /* @@ -567,10 +1863,7 @@ const AnimationFrame *get_confirmed_frame(void) * OUTPUT * unplug frame */ -const AnimationFrame *get_unplug_frame(void) -{ - return &unplug_frame; -} +const AnimationFrame *get_unplug_frame(void) { return &unplug_frame; } /* * get_warning_frame() - Get warning icon frame @@ -580,10 +1873,7 @@ const AnimationFrame *get_unplug_frame(void) * OUTPUT * warining frame */ -const AnimationFrame *get_warning_frame(void) -{ - return &warning.frames[0]; -} +const AnimationFrame *get_warning_frame(void) { return &warning.frames[0]; } /* * get_confirming_animation() - Get confirming animation @@ -593,10 +1883,7 @@ const AnimationFrame *get_warning_frame(void) * OUTPUT * confirming animation */ -const VariantAnimation *get_confirming_animation(void) -{ - return &confirming; -} +const VariantAnimation *get_confirming_animation(void) { return &confirming; } /* * get_warning_animation() - Get warning animation @@ -606,10 +1893,7 @@ const VariantAnimation *get_confirming_animation(void) * OUTPUT * warning animation */ -const VariantAnimation *get_warning_animation(void) -{ - return &warning; -} +const VariantAnimation *get_warning_animation(void) { return &warning; } /* * get_image_animation_duration() - Calculate animation duration @@ -619,16 +1903,14 @@ const VariantAnimation *get_warning_animation(void) * OUTPUT * animation duration */ -uint32_t get_image_animation_duration(const VariantAnimation *animation) -{ - uint32_t duration = 0; +uint32_t get_image_animation_duration(const VariantAnimation *animation) { + uint32_t duration = 0; - for(int i = 0; i < animation->count; i++) - { - duration += animation->frames[i].duration; - } + for (int i = 0; i < animation->count; i++) { + duration += animation->frames[i].duration; + } - return duration; + return duration; } /* @@ -642,23 +1924,18 @@ uint32_t get_image_animation_duration(const VariantAnimation *animation) * number of the frame that should be displayed */ int get_image_animation_frame(const VariantAnimation *animation, - const uint32_t elapsed, bool loop) -{ - uint32_t adjusted_elapsed = (loop) - ? elapsed % get_image_animation_duration(animation) - : elapsed; - uint32_t current_time = 0; - - for(int i = 0; i < animation->count; i++) - { - current_time += animation->frames[i].duration; + const uint32_t elapsed, bool loop) { + uint32_t adjusted_elapsed = + (loop) ? elapsed % get_image_animation_duration(animation) : elapsed; + uint32_t current_time = 0; - if(adjusted_elapsed <= current_time) - { - return i; - } + for (int i = 0; i < animation->count; i++) { + current_time += animation->frames[i].duration; + + if (adjusted_elapsed <= current_time) { + return i; } + } - return -1; + return -1; } - diff --git a/lib/board/signatures.c b/lib/board/signatures.c index 3d502cbd7..20def0ec1 100644 --- a/lib/board/signatures.c +++ b/lib/board/signatures.c @@ -27,50 +27,66 @@ #include volatile const uint8_t valid_pubkey[PUBKEYS] = { - 0xff, - 0xff, - 0xff, - 0xff, - 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, }; -int signatures_ok(void) -{ - uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); - uint8_t sigindex1, sigindex2, sigindex3, firmware_fingerprint[32]; +int signatures_ok(void) { + uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); + uint8_t sigindex1, sigindex2, sigindex3, firmware_fingerprint[32]; - sigindex1 = *((uint8_t *)FLASH_META_SIGINDEX1); - sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2); - sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3); + sigindex1 = *((uint8_t *)FLASH_META_SIGINDEX1); + sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2); + sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3); - if(sigindex1 < 1 || sigindex1 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ - if(sigindex2 < 1 || sigindex2 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ - if(sigindex3 < 1 || sigindex3 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ + if (sigindex1 < 1 || sigindex1 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ + if (sigindex2 < 1 || sigindex2 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ + if (sigindex3 < 1 || sigindex3 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ - if(sigindex1 == sigindex2) { return SIG_FAIL; } /* Duplicate use */ - if(sigindex1 == sigindex3) { return SIG_FAIL; } /* Duplicate use */ - if(sigindex2 == sigindex3) { return SIG_FAIL; } /* Duplicate use */ + if (sigindex1 == sigindex2) { + return SIG_FAIL; + } /* Duplicate use */ + if (sigindex1 == sigindex3) { + return SIG_FAIL; + } /* Duplicate use */ + if (sigindex2 == sigindex3) { + return SIG_FAIL; + } /* Duplicate use */ - if(0xff != valid_pubkey[sigindex1 - 1]) { return KEY_EXPIRED; } /* Expired signing key */ - if(0xff != valid_pubkey[sigindex2 - 1]) { return KEY_EXPIRED; } /* Expired signing key */ - if(0xff != valid_pubkey[sigindex3 - 1]) { return KEY_EXPIRED; } /* Expired signing key */ + if (0xff != valid_pubkey[sigindex1 - 1]) { + return KEY_EXPIRED; + } /* Expired signing key */ + if (0xff != valid_pubkey[sigindex2 - 1]) { + return KEY_EXPIRED; + } /* Expired signing key */ + if (0xff != valid_pubkey[sigindex3 - 1]) { + return KEY_EXPIRED; + } /* Expired signing key */ - sha256_Raw((uint8_t *)FLASH_APP_START, codelen, firmware_fingerprint); + sha256_Raw((uint8_t *)FLASH_APP_START, codelen, firmware_fingerprint); - if(ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, - firmware_fingerprint) != 0) { /* Failure */ - return SIG_FAIL; - } + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], + (uint8_t *)FLASH_META_SIG1, + firmware_fingerprint) != 0) { /* Failure */ + return SIG_FAIL; + } - if(ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, - firmware_fingerprint) != 0) { /* Failure */ - return SIG_FAIL; - } + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], + (uint8_t *)FLASH_META_SIG2, + firmware_fingerprint) != 0) { /* Failure */ + return SIG_FAIL; + } - if(ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, - firmware_fingerprint) != 0) { /* Failure */ - return KEY_EXPIRED; - } + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], + (uint8_t *)FLASH_META_SIG3, + firmware_fingerprint) != 0) { /* Failure */ + return KEY_EXPIRED; + } - return SIG_OK; + return SIG_OK; } diff --git a/lib/board/strlcat.c b/lib/board/strlcat.c index 2b6f1adbb..23c7101c9 100644 --- a/lib/board/strlcat.c +++ b/lib/board/strlcat.c @@ -17,7 +17,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; +static char *rcsid = + "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include @@ -30,30 +31,26 @@ static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; +size_t strlcat(char *dst, const char *src, size_t siz) { + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') d++; + dlen = d - dst; + n = siz - dlen; - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; + if (n == 0) return (dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; - return(dlen + (s - src)); /* count does not include NUL */ + return (dlen + (s - src)); /* count does not include NUL */ } diff --git a/lib/board/strlcpy.c b/lib/board/strlcpy.c index 82cbfac01..c80ac340d 100644 --- a/lib/board/strlcpy.c +++ b/lib/board/strlcpy.c @@ -17,7 +17,8 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; +static char *rcsid = + "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include @@ -28,28 +29,24 @@ static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; +size_t strlcpy(char *dst, const char *src, size_t siz) { + register char *d = dst; + register const char *s = src; + register size_t n = siz; - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) break; + } while (--n != 0); + } - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } - return(s - src - 1); /* count does not include NUL */ + return (s - src - 1); /* count does not include NUL */ } diff --git a/lib/board/supervise.c b/lib/board/supervise.c index e140b913c..71db96799 100644 --- a/lib/board/supervise.c +++ b/lib/board/supervise.c @@ -15,12 +15,11 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include +#include #else -# include -# include +#include +#include #endif #include @@ -33,193 +32,194 @@ /// Return context from user isr processing void svc_busr_return(void) { - __asm__ __volatile__ ("svc %0" :: "i" (SVC_BUSR_RET) : "memory"); + __asm__ __volatile__("svc %0" ::"i"(SVC_BUSR_RET) : "memory"); } /// Return context from user isr processing void svc_tusr_return(void) { - __asm__ __volatile__ ("svc %0" :: "i" (SVC_TUSR_RET) : "memory"); + __asm__ __volatile__("svc %0" ::"i"(SVC_TUSR_RET) : "memory"); } /// Enable interrupts void svc_enable_interrupts(void) { - __asm__ __volatile__ ("svc %0" :: "i" (SVC_ENA_INTR) : "memory"); + __asm__ __volatile__("svc %0" ::"i"(SVC_ENA_INTR) : "memory"); } /// Return context from user isr processing void svc_disable_interrupts(void) { - __asm__ __volatile__ ("svc %0" :: "i" (SVC_DIS_INTR) : "memory"); + __asm__ __volatile__("svc %0" ::"i"(SVC_DIS_INTR) : "memory"); } /// \brief Erase a flash sector. /// @param sector sector number 0..11 void svc_flash_erase_sector(uint32_t sector) { - _param_1 = sector; - _param_2 = 0; - _param_3 = 0; - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_ERASE) : "memory"); + _param_1 = sector; + _param_2 = 0; + _param_3 = 0; + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_ERASE) : "memory"); } bool svc_flash_pgm_blk(uint32_t beginAddr, uint32_t data, uint32_t align) { - _param_1 = beginAddr; - _param_2 = data; - _param_3 = align; - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_PGM_BLK) : "memory"); - return !!_param_1; + _param_1 = beginAddr; + _param_2 = data; + _param_3 = align; + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_PGM_BLK) : "memory"); + return !!_param_1; } bool svc_flash_pgm_word(uint32_t beginAddr, uint32_t data) { - _param_1 = beginAddr; - _param_2 = data; - _param_3 = 0; - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_PGM_WORD) : "memory"); - return !!_param_1; + _param_1 = beginAddr; + _param_2 = data; + _param_3 = 0; + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_PGM_WORD) : "memory"); + return !!_param_1; } void svhandler_flash_erase_sector(void) { - uint32_t sector = _param_1; + uint32_t sector = _param_1; - // Do not allow firmware to erase bootstrap or bootloader sectors. - if ((sector == FLASH_BOOTSTRAP_SECTOR) || - (sector >= FLASH_BOOT_SECTOR_FIRST && sector <= FLASH_BOOT_SECTOR_LAST)) { - return; - } + // Do not allow firmware to erase bootstrap or bootloader sectors. + if ((sector == FLASH_BOOTSTRAP_SECTOR) || + (sector >= FLASH_BOOT_SECTOR_FIRST && sector <= FLASH_BOOT_SECTOR_LAST)) { + return; + } - // Unlock flash. - flash_clear_status_flags(); - flash_unlock(); + // Unlock flash. + flash_clear_status_flags(); + flash_unlock(); - // Erase the sector. - flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); + // Erase the sector. + flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); - // Return flash status. - _param_1 = !!flash_chk_status(); - _param_2 = 0; - _param_3 = 0; + // Return flash status. + _param_1 = !!flash_chk_status(); + _param_2 = 0; + _param_3 = 0; - // Wait for any write operation to complete. - flash_wait_for_last_operation(); + // Wait for any write operation to complete. + flash_wait_for_last_operation(); - // Disable writes to flash. - FLASH_CR &= ~FLASH_CR_PG; + // Disable writes to flash. + FLASH_CR &= ~FLASH_CR_PG; - // lock flash register - FLASH_CR |= FLASH_CR_LOCK; + // lock flash register + FLASH_CR |= FLASH_CR_LOCK; } void svhandler_flash_pgm_blk(void) { - uint32_t beginAddr = _param_1; - uint32_t data = _param_2; - uint32_t length = _param_3; - - // Protect from overflow. - if (beginAddr + length < beginAddr) - return; - - // Do not allow firmware to erase bootstrap or bootloader sectors. - if (((beginAddr >= BSTRP_FLASH_SECT_START) && - (beginAddr <= (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN - 1))) || - (((beginAddr + length) >= BSTRP_FLASH_SECT_START) && - ((beginAddr + length) <= (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN - 1)))) { - return; - } - - if (((beginAddr >= BLDR_FLASH_SECT_START) && - (beginAddr <= (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN - 1))) || - (((beginAddr + length) >= BLDR_FLASH_SECT_START) && - ((beginAddr + length) <= (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN - 1)))) { - return; - } - - // Unlock flash. - flash_clear_status_flags(); - flash_unlock(); - - // Flash write. - flash_program(beginAddr, (uint8_t *)data, length); - - // Return flash status. - _param_1 = !!flash_chk_status(); - _param_2 = 0; - _param_3 = 0; - - // Wait for any write operation to complete. - flash_wait_for_last_operation(); - - // Disable writes to flash. - FLASH_CR &= ~FLASH_CR_PG; - - // Lock flash register - FLASH_CR |= FLASH_CR_LOCK; + uint32_t beginAddr = _param_1; + uint32_t data = _param_2; + uint32_t length = _param_3; + + // Protect from overflow. + if (beginAddr + length < beginAddr) return; + + // Do not allow firmware to erase bootstrap or bootloader sectors. + if (((beginAddr >= BSTRP_FLASH_SECT_START) && + (beginAddr <= (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN - 1))) || + (((beginAddr + length) >= BSTRP_FLASH_SECT_START) && + ((beginAddr + length) <= + (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN - 1)))) { + return; + } + + if (((beginAddr >= BLDR_FLASH_SECT_START) && + (beginAddr <= (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN - 1))) || + (((beginAddr + length) >= BLDR_FLASH_SECT_START) && + ((beginAddr + length) <= + (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN - 1)))) { + return; + } + + // Unlock flash. + flash_clear_status_flags(); + flash_unlock(); + + // Flash write. + flash_program(beginAddr, (uint8_t *)data, length); + + // Return flash status. + _param_1 = !!flash_chk_status(); + _param_2 = 0; + _param_3 = 0; + + // Wait for any write operation to complete. + flash_wait_for_last_operation(); + + // Disable writes to flash. + FLASH_CR &= ~FLASH_CR_PG; + + // Lock flash register + FLASH_CR |= FLASH_CR_LOCK; } void svhandler_flash_pgm_word(void) { - uint32_t dst = _param_1; - uint32_t src = _param_2; - - // Do not allow firmware to erase bootstrap or bootloader sectors. - if ((dst >= BSTRP_FLASH_SECT_START) && - (dst <= (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN))) { - return; - } - - if ((dst >= BLDR_FLASH_SECT_START) && - (dst <= (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN))) { - return; - } - - // Unlock flash. - flash_clear_status_flags(); - flash_unlock(); - - // Flash write. - flash_program_word(dst, src); - _param_1 = !!flash_chk_status(); - _param_2 = 0; - _param_3 = 0; - - // Wait for any write operation to complete. - flash_wait_for_last_operation(); - - // Disable writes to flash. - FLASH_CR &= ~FLASH_CR_PG; - - // Lock flash register - FLASH_CR |= FLASH_CR_LOCK; + uint32_t dst = _param_1; + uint32_t src = _param_2; + + // Do not allow firmware to erase bootstrap or bootloader sectors. + if ((dst >= BSTRP_FLASH_SECT_START) && + (dst <= (BSTRP_FLASH_SECT_START + BSTRP_FLASH_SECT_LEN))) { + return; + } + + if ((dst >= BLDR_FLASH_SECT_START) && + (dst <= (BLDR_FLASH_SECT_START + 2 * BLDR_FLASH_SECT_LEN))) { + return; + } + + // Unlock flash. + flash_clear_status_flags(); + flash_unlock(); + + // Flash write. + flash_program_word(dst, src); + _param_1 = !!flash_chk_status(); + _param_2 = 0; + _param_3 = 0; + + // Wait for any write operation to complete. + flash_wait_for_last_operation(); + + // Disable writes to flash. + FLASH_CR &= ~FLASH_CR_PG; + + // Lock flash register + FLASH_CR |= FLASH_CR_LOCK; } void svc_handler_main(uint32_t *stack) { - uint8_t svc_number = ((uint8_t*) stack[6])[-2]; - switch (svc_number) { + uint8_t svc_number = ((uint8_t *)stack[6])[-2]; + switch (svc_number) { case SVC_BUSR_RET: - svhandler_button_usr_return(); - break; + svhandler_button_usr_return(); + break; case SVC_TUSR_RET: - svhandler_timer_usr_return(); - break; + svhandler_timer_usr_return(); + break; case SVC_ENA_INTR: - svhandler_enable_interrupts(); - break; + svhandler_enable_interrupts(); + break; case SVC_DIS_INTR: - svhandler_disable_interrupts(); - break; + svhandler_disable_interrupts(); + break; case SVC_FLASH_ERASE: - svhandler_flash_erase_sector(); - break; + svhandler_flash_erase_sector(); + break; case SVC_FLASH_PGM_BLK: - svhandler_flash_pgm_blk(); - break; + svhandler_flash_pgm_blk(); + break; case SVC_FLASH_PGM_WORD: - svhandler_flash_pgm_word(); - break; + svhandler_flash_pgm_word(); + break; case SVC_FIRMWARE_PRIV: case SVC_FIRMWARE_UNPRIV: - svhandler_start_firmware(svc_number); - break; + svhandler_start_firmware(svc_number); + break; default: - stack[0] = 0xffffffff; - break; - } + stack[0] = 0xffffffff; + break; + } } #endif diff --git a/lib/board/timer.c b/lib/board/timer.c index 3d3042a30..445255a3d 100644 --- a/lib/board/timer.c +++ b/lib/board/timer.c @@ -17,15 +17,14 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include -# include -# include -# include +#include +#include +#include +#include #else -# include -# include +#include +#include #endif #include "keepkey/board/keepkey_board.h" @@ -36,13 +35,11 @@ #include - static volatile uint32_t remaining_delay = UINT32_MAX; static RunnableNode runnables[MAX_RUNNABLES]; static RunnableQueue free_queue = {NULL, 0}; static RunnableQueue active_queue = {NULL, 0}; - /* * runnable_queue_peek() - Get pointer to head node in task manager (queue) * @@ -51,9 +48,8 @@ static RunnableQueue active_queue = {NULL, 0}; * OUTPUT * head node in the queue */ -static RunnableNode *runnable_queue_peek(RunnableQueue *queue) -{ - return(queue->head); +static RunnableNode *runnable_queue_peek(RunnableQueue *queue) { + return (queue->head); } /* @@ -66,48 +62,41 @@ static RunnableNode *runnable_queue_peek(RunnableQueue *queue) * OUTPUT * pointer to a node containing the requested task function */ -static RunnableNode *runnable_queue_get(RunnableQueue *queue, Runnable callback) -{ - RunnableNode *current = queue->head; - RunnableNode *result = NULL; - - /* check queue is empty */ - if(current != NULL) - { - if(current->runnable == callback) - { - result = current; - queue->head = current->next; +static RunnableNode *runnable_queue_get(RunnableQueue *queue, + Runnable callback) { + RunnableNode *current = queue->head; + RunnableNode *result = NULL; + + /* check queue is empty */ + if (current != NULL) { + if (current->runnable == callback) { + result = current; + queue->head = current->next; + } else { + /* search through the linklist for node that contains the runnable + callback function */ + RunnableNode *previous = current; + current = current->next; + + while ((current != NULL) && (result == NULL)) { + // Found the node! + if (current->runnable == callback) { + result = current; + previous->next = current->next; + result->next = NULL; } - else - { - /* search through the linklist for node that contains the runnable - callback function */ - RunnableNode *previous = current; - current = current->next; - - while((current != NULL) && (result == NULL)) - { - // Found the node! - if(current->runnable == callback) - { - result = current; - previous->next = current->next; - result->next = NULL; - } - - previous = current; - current = current->next; - } - } - } - if(result != NULL) - { - queue->size -= 1; + previous = current; + current = current->next; + } } + } + + if (result != NULL) { + queue->size -= 1; + } - return(result); + return (result); } /* @@ -119,26 +108,22 @@ static RunnableNode *runnable_queue_get(RunnableQueue *queue, Runnable callback) * OUTPUT * none */ -static void runnable_queue_push(RunnableQueue *queue, RunnableNode *node) -{ +static void runnable_queue_push(RunnableQueue *queue, RunnableNode *node) { #ifndef EMULATOR - svc_disable_interrupts(); + svc_disable_interrupts(); #endif - if(queue->head != NULL) - { - node->next = queue->head; - } - else - { - node->next = NULL; - } + if (queue->head != NULL) { + node->next = queue->head; + } else { + node->next = NULL; + } - queue->head = node; - queue->size += 1; + queue->head = node; + queue->size += 1; #ifndef EMULATOR - svc_enable_interrupts(); + svc_enable_interrupts(); #endif } @@ -150,83 +135,68 @@ static void runnable_queue_push(RunnableQueue *queue, RunnableNode *node) * OUTPUT * pointer to an available node retrieved from the queue */ -static RunnableNode *runnable_queue_pop(RunnableQueue *queue) -{ +static RunnableNode *runnable_queue_pop(RunnableQueue *queue) { #ifndef EMULATOR - svc_disable_interrupts(); + svc_disable_interrupts(); #endif - RunnableNode *runnable_node = queue->head; + RunnableNode *runnable_node = queue->head; - if(runnable_node != NULL) - { - queue->head = runnable_node->next; - queue->size -= 1; - } + if (runnable_node != NULL) { + queue->head = runnable_node->next; + queue->size -= 1; + } #ifndef EMULATOR - svc_enable_interrupts(); + svc_enable_interrupts(); #endif - return(runnable_node); + return (runnable_node); } /* - * run_runnables() - Run task (callback function) located in task manager (queue) + * run_runnables() - Run task (callback function) located in task manager + * (queue) * * INPUT * none * OUTPUT * none */ -static void run_runnables(void) -{ - // Do timer function work. - RunnableNode *runnable_node = runnable_queue_peek(&active_queue); - - while(runnable_node != NULL) - { - RunnableNode *next = runnable_node->next; - - if(runnable_node->remaining != 0) - { - runnable_node->remaining -= 1; - } +static void run_runnables(void) { + // Do timer function work. + RunnableNode *runnable_node = runnable_queue_peek(&active_queue); - if(runnable_node->remaining == 0) - { - if(runnable_node->runnable != NULL) - { - runnable_node->runnable(runnable_node->context); - } - - if(runnable_node->repeating) - { - runnable_node->remaining = runnable_node->period; - } - else - { - runnable_queue_push( - &free_queue, - runnable_queue_get(&active_queue, runnable_node->runnable)); - } - } + while (runnable_node != NULL) { + RunnableNode *next = runnable_node->next; - runnable_node = next; + if (runnable_node->remaining != 0) { + runnable_node->remaining -= 1; } -} + if (runnable_node->remaining == 0) { + if (runnable_node->runnable != NULL) { + runnable_node->runnable(runnable_node->context); + } -void kk_timer_init(void) -{ - for(int i = 0; i < MAX_RUNNABLES; i++) - { - runnable_queue_push(&free_queue, &runnables[ i ]); + if (runnable_node->repeating) { + runnable_node->remaining = runnable_node->period; + } else { + runnable_queue_push( + &free_queue, + runnable_queue_get(&active_queue, runnable_node->runnable)); + } } -} - + runnable_node = next; + } +} +void kk_timer_init(void) { + for (int i = 0; i < MAX_RUNNABLES; i++) { + runnable_queue_push(&free_queue, &runnables[i]); + } +} /* * timer_init() - Timer 4 initialization. Main timer for round robin tasking. @@ -236,55 +206,53 @@ void kk_timer_init(void) * OUTPUT * none */ -void timer_init(void) -{ - int i; +void timer_init(void) { + int i; - for(i = 0; i < MAX_RUNNABLES; i++) - { - runnable_queue_push(&free_queue, &runnables[ i ]); - } + for (i = 0; i < MAX_RUNNABLES; i++) { + runnable_queue_push(&free_queue, &runnables[i]); + } #ifndef EMULATOR - // Set up the timer. - rcc_periph_reset_pulse(RST_TIM4); - timer_enable_irq(TIM4, TIM_DIER_UIE); - timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + // Set up the timer. + rcc_periph_reset_pulse(RST_TIM4); + timer_enable_irq(TIM4, TIM_DIER_UIE); + timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); - /* 1000 * ( 120 / 12000000 ) = 1 ms intervals, - where 1000 is the counter, 120 is the prescalar, - and 12000000 is the clks/second */ - timer_set_prescaler(TIM4, 120000); - timer_set_period(TIM4, 1); + /* 1000 * ( 120 / 12000000 ) = 1 ms intervals, + where 1000 is the counter, 120 is the prescalar, + and 12000000 is the clks/second */ + timer_set_prescaler(TIM4, 120000); + timer_set_period(TIM4, 1); - nvic_set_priority(NVIC_TIM4_IRQ, 16 * 2); + nvic_set_priority(NVIC_TIM4_IRQ, 16 * 2); - timer_enable_counter(TIM4); + timer_enable_counter(TIM4); #else - void tim4_sighandler(int sig); - signal(SIGALRM, tim4_sighandler); - ualarm(1000, 1000); + void tim4_sighandler(int sig); + signal(SIGALRM, tim4_sighandler); + ualarm(1000, 1000); #endif } uint32_t fi_defense_delay(volatile uint32_t value) { #ifndef EMULATOR - int wait = random32() & 0x4fff; - volatile int i = 0; - volatile int j = wait; - while (i < wait) { - if (i + j != wait) { - shutdown(); - } - ++i; - --j; - } - // Double-check loop completion. - if (i != wait || j != 0) { + int wait = random32() & 0x4fff; + volatile int i = 0; + volatile int j = wait; + while (i < wait) { + if (i + j != wait) { shutdown(); } + ++i; + --j; + } + // Double-check loop completion. + if (i != wait || j != 0) { + shutdown(); + } #endif - return value; + return value; } /* @@ -295,17 +263,15 @@ uint32_t fi_defense_delay(volatile uint32_t value) { * OUTPUT * none */ -void delay_us(uint32_t us) -{ +void delay_us(uint32_t us) { #ifndef EMULATOR - uint32_t cnt = us * 20; + uint32_t cnt = us * 20; - while(cnt--) - { - __asm__("nop"); - } + while (cnt--) { + __asm__("nop"); + } #else - usleep(us); + usleep(us); #endif } @@ -317,15 +283,16 @@ void delay_us(uint32_t us) * OUTPUT * none */ -void delay_ms(uint32_t ms) -{ - remaining_delay = ms; +void delay_ms(uint32_t ms) { + remaining_delay = ms; - while(remaining_delay > 0) {} + while (remaining_delay > 0) { + } } /* - * delay_ms_with_callback() - Millisecond delay allowing a callback for extra work + * delay_ms_with_callback() - Millisecond delay allowing a callback for extra + * work * * INPUT * - ms: count in milliseconds @@ -335,17 +302,14 @@ void delay_ms(uint32_t ms) * none */ void delay_ms_with_callback(uint32_t ms, callback_func_t callback_func, - uint32_t frequency_ms) -{ - remaining_delay = ms; - - while(remaining_delay > 0) - { - if(remaining_delay % frequency_ms == 0) - { - (*callback_func)(); - } + uint32_t frequency_ms) { + remaining_delay = ms; + + while (remaining_delay > 0) { + if (remaining_delay % frequency_ms == 0) { + (*callback_func)(); } + } } /* @@ -357,29 +321,27 @@ void delay_ms_with_callback(uint32_t ms, callback_func_t callback_func, * none * */ -void timerisr_usr(void) -{ - /* Decrement the delay */ - if(remaining_delay > 0) - { - remaining_delay--; - } +void timerisr_usr(void) { + /* Decrement the delay */ + if (remaining_delay > 0) { + remaining_delay--; + } - run_runnables(); + run_runnables(); #ifndef EMULATOR - svc_tusr_return(); // this MUST be called last to properly clean up and return + svc_tusr_return(); // this MUST be called last to properly clean up and + // return #endif } #ifdef EMULATOR -void tim4_sighandler(int sig) { - timerisr_usr(); -} +void tim4_sighandler(int sig) { timerisr_usr(); } #endif /* - * post_delayed() - Add delay to existing task (callback function) in task manager (queue) + * post_delayed() - Add delay to existing task (callback function) in task + * manager (queue) * * INPUT * - callback: task function @@ -388,25 +350,24 @@ void tim4_sighandler(int sig) { * OUTPUT * none */ -void post_delayed(Runnable callback, void *context, uint32_t delay_ms) -{ - RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); - - if(runnable_node == NULL) - { - runnable_node = runnable_queue_pop(&free_queue); - } - - runnable_node->runnable = callback; - runnable_node->context = context; - runnable_node->remaining = delay_ms; - runnable_node->period = 0; - runnable_node->repeating = false; - runnable_queue_push(&active_queue, runnable_node); +void post_delayed(Runnable callback, void *context, uint32_t delay_ms) { + RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); + + if (runnable_node == NULL) { + runnable_node = runnable_queue_pop(&free_queue); + } + + runnable_node->runnable = callback; + runnable_node->context = context; + runnable_node->remaining = delay_ms; + runnable_node->period = 0; + runnable_node->repeating = false; + runnable_queue_push(&active_queue, runnable_node); } /* - * post_periodic() - Add repeat and delay to existing task (callback function) in task manager (queue) + * post_periodic() - Add repeat and delay to existing task (callback function) + * in task manager (queue) * * INPUT * - callback: task function @@ -417,22 +378,20 @@ void post_delayed(Runnable callback, void *context, uint32_t delay_ms) * none */ void post_periodic(Runnable callback, void *context, uint32_t period_ms, - uint32_t delay_ms) -{ - RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); + uint32_t delay_ms) { + RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); - if(runnable_node == NULL) - { - runnable_node = runnable_queue_pop(&free_queue); - } + if (runnable_node == NULL) { + runnable_node = runnable_queue_pop(&free_queue); + } - runnable_node->runnable = callback; - runnable_node->context = context; - runnable_node->remaining = delay_ms; - runnable_node->period = period_ms; - runnable_node->repeating = true; + runnable_node->runnable = callback; + runnable_node->context = context; + runnable_node->remaining = delay_ms; + runnable_node->period = period_ms; + runnable_node->repeating = true; - runnable_queue_push(&active_queue, runnable_node); + runnable_queue_push(&active_queue, runnable_node); } /* @@ -443,14 +402,12 @@ void post_periodic(Runnable callback, void *context, uint32_t period_ms, * OUTPUT * none */ -void remove_runnable(Runnable callback) -{ - RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); +void remove_runnable(Runnable callback) { + RunnableNode *runnable_node = runnable_queue_get(&active_queue, callback); - if(runnable_node != NULL) - { - runnable_queue_push(&free_queue, runnable_node); - } + if (runnable_node != NULL) { + runnable_queue_push(&free_queue, runnable_node); + } } /* @@ -461,13 +418,11 @@ void remove_runnable(Runnable callback) * OUTPUT * none */ -void clear_runnables(void) -{ - RunnableNode *runnable_node = runnable_queue_pop(&active_queue); - - while(runnable_node != NULL) - { - runnable_queue_push(&free_queue, runnable_node); - runnable_node = runnable_queue_pop(&active_queue); - } +void clear_runnables(void) { + RunnableNode *runnable_node = runnable_queue_pop(&active_queue); + + while (runnable_node != NULL) { + runnable_queue_push(&free_queue, runnable_node); + runnable_node = runnable_queue_pop(&active_queue); + } } diff --git a/lib/board/udp.c b/lib/board/udp.c index 2b9684cc5..df6c3d41d 100644 --- a/lib/board/udp.c +++ b/lib/board/udp.c @@ -35,51 +35,49 @@ extern usb_rx_callback_t user_debug_rx_callback; static volatile char tiny = 0; void usbInit(const char *origin_url) { - (void)origin_url; - emulatorSocketInit(); + (void)origin_url; + emulatorSocketInit(); } void usbPoll(void) { - emulatorPoll(); + emulatorPoll(); - static uint8_t buf[64] __attribute__ ((aligned(4))); - size_t len; + static uint8_t buf[64] __attribute__((aligned(4))); + size_t len; - int iface = 0; - if (0 < (len = emulatorSocketRead(&iface, buf, sizeof(buf)))) { - if (!tiny) { - if (iface == 0) - { - user_rx_callback(&buf, len); - } else if (iface == 1) { + int iface = 0; + if (0 < (len = emulatorSocketRead(&iface, buf, sizeof(buf)))) { + if (!tiny) { + if (iface == 0) { + user_rx_callback(&buf, len); + } else if (iface == 1) { #if DEBUG_LINK - user_debug_rx_callback(&buf, len); + user_debug_rx_callback(&buf, len); #else - user_rx_callback(&buf, len); + user_rx_callback(&buf, len); #endif - } - } else { - assert(false && "not yet implemented"); - //msg_read_tiny(msg.message, sizeof(msg.message)); - } - } + } + } else { + assert(false && "not yet implemented"); + // msg_read_tiny(msg.message, sizeof(msg.message)); + } + } } bool usb_tx(uint8_t *msg, uint32_t len) { - return emulatorSocketWrite(0, msg, len); + return emulatorSocketWrite(0, msg, len); } #if DEBUG_LINK bool usb_debug_tx(uint8_t *msg, uint32_t len) { - return emulatorSocketWrite(1, msg, len); + return emulatorSocketWrite(1, msg, len); } #endif char usbTiny(char set) { - char old = tiny; - tiny = set; - return old; + char old = tiny; + tiny = set; + return old; } #endif - diff --git a/lib/board/usb.c b/lib/board/usb.c index 38a944e10..3b37dc96c 100644 --- a/lib/board/usb.c +++ b/lib/board/usb.c @@ -18,18 +18,18 @@ */ #ifndef EMULATOR -# include -# include -# include -# include -# include -# include -# include -# include "keepkey/board/keepkey_board.h" -# include "keepkey/board/layout.h" -# include "keepkey/board/timer.h" +#include +#include +#include +#include +#include +#include +#include +#include "keepkey/board/keepkey_board.h" +#include "keepkey/board/layout.h" +#include "keepkey/board/timer.h" #else -# include +#include #endif #include "keepkey/board/keepkey_board.h" @@ -51,11 +51,13 @@ #include #include -#define debugLog(L, B, T) do{}while(0) +#define debugLog(L, B, T) \ + do { \ + } while (0) static bool usb_inited = false; -/* This optional callback is configured by the user to handle receive events. */ +/* This optional callback is configured by the user to handle receive events. */ usb_rx_callback_t user_rx_callback = NULL; #if DEBUG_LINK @@ -76,27 +78,27 @@ usb_u2f_rx_callback_t user_u2f_rx_callback = NULL; #define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_MAIN_IN (0x81) -#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) +#define ENDPOINT_ADDRESS_MAIN_IN (0x81) +#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) #if DEBUG_LINK -#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) -#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) +#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) #endif -#define ENDPOINT_ADDRESS_U2F_IN (0x83) -#define ENDPOINT_ADDRESS_U2F_OUT (0x03) +#define ENDPOINT_ADDRESS_U2F_IN (0x83) +#define ENDPOINT_ADDRESS_U2F_OUT (0x03) -#define USB_STRINGS \ - X(MANUFACTURER, "KeyHodlers, LLC") \ - X(PRODUCT, device_label) \ - X(SERIAL_NUMBER, serial_uuid_str) \ - X(INTERFACE_MAIN, "KeepKey Interface") \ - X(INTERFACE_DEBUG, "KeepKey Debug Link Interface") \ - X(INTERFACE_U2F, "KeepKey U2F Interface") +#define USB_STRINGS \ + X(MANUFACTURER, "KeyHodlers, LLC") \ + X(PRODUCT, device_label) \ + X(SERIAL_NUMBER, serial_uuid_str) \ + X(INTERFACE_MAIN, "KeepKey Interface") \ + X(INTERFACE_DEBUG, "KeepKey Debug Link Interface") \ + X(INTERFACE_U2F, "KeepKey U2F Interface") #define X(name, value) USB_STRING_##name, enum { - USB_STRING_LANGID_CODES, // LANGID code array - USB_STRINGS + USB_STRING_LANGID_CODES, // LANGID code array + USB_STRINGS }; #undef X @@ -104,432 +106,434 @@ static char device_label[33]; static char serial_uuid_str[100]; #define X(name, value) value, -static const char *usb_strings[] = { - USB_STRINGS -}; +static const char *usb_strings[] = {USB_STRINGS}; #undef X static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x2B24, /* KeepKey Vendor ID */ - .idProduct = 0x0002, - .bcdDevice = 0x0100, - .iManufacturer = USB_STRING_MANUFACTURER, - .iProduct = USB_STRING_PRODUCT, - .iSerialNumber = USB_STRING_SERIAL_NUMBER, - .bNumConfigurations = 1, + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0210, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x2B24, /* KeepKey Vendor ID */ + .idProduct = 0x0002, + .bcdDevice = 0x0100, + .iManufacturer = USB_STRING_MANUFACTURER, + .iProduct = USB_STRING_PRODUCT, + .iSerialNumber = USB_STRING_SERIAL_NUMBER, + .bNumConfigurations = 1, }; static const uint8_t hid_report_descriptor_u2f[] = { - 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) - 0x09, 0x01, // USAGE (U2F HID Authenticator Device) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION + 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) + 0x09, 0x01, // USAGE (U2F HID Authenticator Device) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION }; static const struct { - struct usb_hid_descriptor hid_descriptor_u2f; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report_u2f; -} __attribute__((packed)) hid_function_u2f = { - .hid_descriptor_u2f = { - .bLength = sizeof(hid_function_u2f), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report_u2f = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor_u2f), - } -}; - -static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; + struct usb_hid_descriptor hid_descriptor_u2f; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report_u2f; +} __attribute__((packed)) +hid_function_u2f = {.hid_descriptor_u2f = + { + .bLength = sizeof(hid_function_u2f), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report_u2f = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor_u2f), + }}; + +static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_U2F, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_U2F, - .endpoint = hid_endpoints_u2f, - .extra = &hid_function_u2f, - .extralen = sizeof(hid_function_u2f), + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_U2F, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_U2F, + .endpoint = hid_endpoints_u2f, + .extra = &hid_function_u2f, + .extralen = sizeof(hid_function_u2f), }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor webusb_iface_debug[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = webusb_endpoints_debug, - .extra = NULL, - .extralen = 0, + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_DEBUG, + .endpoint = webusb_endpoints_debug, + .extra = NULL, + .extralen = 0, }}; #endif -static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor webusb_iface_main[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = webusb_endpoints_main, - .extra = NULL, - .extralen = 0, + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = webusb_endpoints_main, + .extra = NULL, + .extralen = 0, }}; - // Windows are strict about interfaces appearing // in correct order -static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = webusb_iface_main, +static const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = webusb_iface_main, #if DEBUG_LINK -}, { - .num_altsetting = 1, - .altsetting = webusb_iface_debug, + }, + { + .num_altsetting = 1, + .altsetting = webusb_iface_debug, #endif -}, { - .num_altsetting = 1, - .altsetting = hid_iface_u2f, -}}; + }, + { + .num_altsetting = 1, + .altsetting = hid_iface_u2f, + }}; static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = USB_INTERFACE_COUNT, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = USB_INTERFACE_COUNT, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, }; -static enum usbd_request_return_codes -hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, void (**complete)(usbd_device *, struct usb_setup_data *)) -{ - (void)complete; - (void)dev; - - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; - - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); - return 1; +static enum usbd_request_return_codes hid_control_request( + usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *, struct usb_setup_data *)) { + (void)complete; + (void)dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200)) + return 0; + + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); + return 1; } static volatile char tiny = 0; -static void main_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; - debugLog(0, "", "main_rx_callback"); +static void main_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) + return; + debugLog(0, "", "main_rx_callback"); - if (user_rx_callback) { - user_rx_callback(buf, 64); - } + if (user_rx_callback) { + user_rx_callback(buf, 64); + } } -static void u2f_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); +static void u2f_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); - debugLog(0, "", "u2f_rx_callback"); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; + debugLog(0, "", "u2f_rx_callback"); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; - if (user_u2f_rx_callback) { - user_u2f_rx_callback(tiny, (const U2FHID_FRAME *) (void*) buf); - } + if (user_u2f_rx_callback) { + user_u2f_rx_callback(tiny, (const U2FHID_FRAME *)(void *)buf); + } } #if DEBUG_LINK -static void debug_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "debug_rx_callback"); - - if (user_debug_rx_callback) { - user_debug_rx_callback(buf, 64); - } +static void debug_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static uint8_t buf[64] __attribute__((aligned(4))); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) + return; + debugLog(0, "", "debug_rx_callback"); + + if (user_debug_rx_callback) { + user_debug_rx_callback(buf, 64); + } } #endif -static void set_config(usbd_device *dev, uint16_t wValue) -{ - (void)wValue; - - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); +static void set_config(usbd_device *dev, uint16_t wValue) { + (void)wValue; + + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, + main_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, + u2f_rx_callback); #if DEBUG_LINK - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, + 64, debug_rx_callback); #endif - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request); + usbd_register_control_callback( + dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); +static uint8_t usbd_control_buffer[256] __attribute__((aligned(2))); -static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +static const struct usb_device_capability_descriptor *capabilities[] = { + (const struct usb_device_capability_descriptor + *)&webusb_platform_capability_descriptor, }; static const struct usb_bos_descriptor bos_descriptor = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), - .capabilities = capabilities -}; - -void usbInit(const char *origin_url) -{ - gpio_mode_setup(USB_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, USB_GPIO_PORT_PINS); - gpio_set_af(USB_GPIO_PORT, GPIO_AF10, USB_GPIO_PORT_PINS); - - desig_get_unique_id_as_string(serial_uuid_str, sizeof(serial_uuid_str)); - memory_getDeviceLabel(device_label, sizeof(device_label)); - - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config); - usb21_setup(usbd_dev, &bos_descriptor); - webusb_setup(usbd_dev, origin_url); - // Debug link interface does not have WinUSB set; - // if you really need debug link on windows, edit the descriptor in winusb.c - winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); - - usb_inited = true; + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]), + .capabilities = capabilities}; + +void usbInit(const char *origin_url) { + gpio_mode_setup(USB_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, + USB_GPIO_PORT_PINS); + gpio_set_af(USB_GPIO_PORT, GPIO_AF10, USB_GPIO_PORT_PINS); + + desig_get_unique_id_as_string(serial_uuid_str, sizeof(serial_uuid_str)); + memory_getDeviceLabel(device_label, sizeof(device_label)); + + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, + sizeof(usb_strings) / sizeof(*usb_strings), + usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + webusb_setup(usbd_dev, origin_url); + // Debug link interface does not have WinUSB set; + // if you really need debug link on windows, edit the descriptor in winusb.c + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); + + usb_inited = true; } -void usbPoll(void) -{ - // poll read buffer - usbd_poll(usbd_dev); +void usbPoll(void) { + // poll read buffer + usbd_poll(usbd_dev); } -void usbReconnect(void) -{ - usbd_disconnect(usbd_dev, 1); - delay_us(1000 / 20); - usbd_disconnect(usbd_dev, 0); +void usbReconnect(void) { + usbd_disconnect(usbd_dev, 1); + delay_us(1000 / 20); + usbd_disconnect(usbd_dev, 0); } -char usbTiny(char set) -{ - char old = tiny; - tiny = set; - return old; +char usbTiny(char set) { + char old = tiny; + tiny = set; + return old; } -#endif // EMULATOR +#endif // EMULATOR -bool msg_write(MessageType msg_id, const void *msg) -{ - const pb_field_t *fields = message_fields(NORMAL_MSG, msg_id, OUT_MSG); +bool msg_write(MessageType msg_id, const void *msg) { + const pb_field_t *fields = message_fields(NORMAL_MSG, msg_id, OUT_MSG); - if (!fields) - return false; + if (!fields) return false; - TrezorFrameBuffer framebuf; - memset(&framebuf, 0, sizeof(framebuf)); - framebuf.frame.usb_header.hid_type = '?'; - framebuf.frame.header.pre1 = '#'; - framebuf.frame.header.pre2 = '#'; - framebuf.frame.header.id = __builtin_bswap16(msg_id); + TrezorFrameBuffer framebuf; + memset(&framebuf, 0, sizeof(framebuf)); + framebuf.frame.usb_header.hid_type = '?'; + framebuf.frame.header.pre1 = '#'; + framebuf.frame.header.pre2 = '#'; + framebuf.frame.header.id = __builtin_bswap16(msg_id); - pb_ostream_t os = pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); + pb_ostream_t os = + pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); - if (!pb_encode(&os, fields, msg)) - return false; + if (!pb_encode(&os, fields, msg)) return false; - framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); + framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); - // Chunk out data - for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; pos += 64 - 1) { - uint8_t tmp_buffer[64] = { 0 }; + // Chunk out data + for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; + pos += 64 - 1) { + uint8_t tmp_buffer[64] = {0}; - tmp_buffer[0] = '?'; + tmp_buffer[0] = '?'; - memcpy(tmp_buffer + 1, ((const uint8_t*)&framebuf) + pos, 64 - 1); + memcpy(tmp_buffer + 1, ((const uint8_t *)&framebuf) + pos, 64 - 1); #ifndef EMULATOR - while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, tmp_buffer, 64) == 0) {}; + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, tmp_buffer, + 64) == 0) { + }; #else - emulatorSocketWrite(0, tmp_buffer, sizeof(tmp_buffer)); + emulatorSocketWrite(0, tmp_buffer, sizeof(tmp_buffer)); #endif - } + } - return true; + return true; } #if DEBUG_LINK -bool msg_debug_write(MessageType msg_id, const void *msg) -{ - const pb_field_t *fields = message_fields(DEBUG_MSG, msg_id, OUT_MSG); +bool msg_debug_write(MessageType msg_id, const void *msg) { + const pb_field_t *fields = message_fields(DEBUG_MSG, msg_id, OUT_MSG); - if (!fields) - return false; + if (!fields) return false; - TrezorFrameBuffer framebuf; - memset(&framebuf, 0, sizeof(framebuf)); - framebuf.frame.usb_header.hid_type = '?'; - framebuf.frame.header.pre1 = '#'; - framebuf.frame.header.pre2 = '#'; - framebuf.frame.header.id = __builtin_bswap16(msg_id); + TrezorFrameBuffer framebuf; + memset(&framebuf, 0, sizeof(framebuf)); + framebuf.frame.usb_header.hid_type = '?'; + framebuf.frame.header.pre1 = '#'; + framebuf.frame.header.pre2 = '#'; + framebuf.frame.header.id = __builtin_bswap16(msg_id); - pb_ostream_t os = pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); + pb_ostream_t os = + pb_ostream_from_buffer(framebuf.buffer, sizeof(framebuf.buffer)); - if (!pb_encode(&os, fields, msg)) - return false; + if (!pb_encode(&os, fields, msg)) return false; - framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); + framebuf.frame.header.len = __builtin_bswap32(os.bytes_written); - // Chunk out data - for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; pos += 64 - 1) { - uint8_t tmp_buffer[64] = { 0 }; + // Chunk out data + for (uint32_t pos = 1; pos < sizeof(framebuf.frame) + os.bytes_written; + pos += 64 - 1) { + uint8_t tmp_buffer[64] = {0}; - tmp_buffer[0] = '?'; + tmp_buffer[0] = '?'; - memcpy(tmp_buffer + 1, ((const uint8_t*)&framebuf) + pos, 64 - 1); + memcpy(tmp_buffer + 1, ((const uint8_t *)&framebuf) + pos, 64 - 1); #ifndef EMULATOR - while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, tmp_buffer, 64) == 0) {}; + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, tmp_buffer, + 64) == 0) { + }; #else - emulatorSocketWrite(1, tmp_buffer, sizeof(tmp_buffer)); + emulatorSocketWrite(1, tmp_buffer, sizeof(tmp_buffer)); #endif - } + } - return true; + return true; } #endif -void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) -{ +void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) { #ifndef EMULATOR - while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, u2f_pkt, 64) == 0) {}; + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, u2f_pkt, 64) == + 0) { + }; #else - assert(false && "Emulator does not support FIDO u2f"); + assert(false && "Emulator does not support FIDO u2f"); #endif } -void usb_set_rx_callback(usb_rx_callback_t callback) -{ - user_rx_callback = callback; +void usb_set_rx_callback(usb_rx_callback_t callback) { + user_rx_callback = callback; } #if DEBUG_LINK -void usb_set_debug_rx_callback(usb_rx_callback_t callback) -{ - user_debug_rx_callback = callback; +void usb_set_debug_rx_callback(usb_rx_callback_t callback) { + user_debug_rx_callback = callback; } #endif -void usb_set_u2f_rx_callback(usb_u2f_rx_callback_t callback) -{ - user_u2f_rx_callback = callback; -} - -bool usbInitialized(void) { - return usb_inited; +void usb_set_u2f_rx_callback(usb_u2f_rx_callback_t callback) { + user_u2f_rx_callback = callback; } +bool usbInitialized(void) { return usb_inited; } diff --git a/lib/board/usb21_standard.c b/lib/board/usb21_standard.c index 51df53f4b..47b32b777 100644 --- a/lib/board/usb21_standard.c +++ b/lib/board/usb21_standard.c @@ -24,75 +24,71 @@ #include static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, - uint8_t *buf, uint16_t len) -{ - uint8_t *tmpbuf = buf; - uint16_t count, total = 0, totallen = 0; - uint16_t i; - - memcpy(buf, bos, count = MIN(len, bos->bLength)); - buf += count; - len -= count; - total += count; - totallen += bos->bLength; - - /* For each device capability */ - for (i = 0; i < bos->bNumDeviceCaps; i++) { - /* Copy device capability descriptor. */ - const struct usb_device_capability_descriptor *cap = - bos->capabilities[i]; - - memcpy(buf, cap, count = MIN(len, cap->bLength)); - buf += count; - len -= count; - total += count; - totallen += cap->bLength; - } - - /* Fill in wTotalLength. */ - *(uint16_t *)(tmpbuf + 2) = totallen; - - return total; + uint8_t *buf, uint16_t len) { + uint8_t *tmpbuf = buf; + uint16_t count, total = 0, totallen = 0; + uint16_t i; + + memcpy(buf, bos, count = MIN(len, bos->bLength)); + buf += count; + len -= count; + total += count; + totallen += bos->bLength; + + /* For each device capability */ + for (i = 0; i < bos->bNumDeviceCaps; i++) { + /* Copy device capability descriptor. */ + const struct usb_device_capability_descriptor *cap = bos->capabilities[i]; + + memcpy(buf, cap, count = MIN(len, cap->bLength)); + buf += count; + len -= count; + total += count; + totallen += cap->bLength; + } + + /* Fill in wTotalLength. */ + *(uint16_t *)(tmpbuf + 2) = totallen; + + return total; } -static const struct usb_bos_descriptor* usb21_bos; - -static enum usbd_request_return_codes -usb21_standard_get_descriptor(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) -{ - (void)complete; - (void)usbd_dev; - - if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { - int descr_type = req->wValue >> 8; - if (descr_type == USB_DT_BOS) { - if (!usb21_bos) { - return USBD_REQ_NOTSUPP; - } - *len = MIN(*len, build_bos_descriptor(usb21_bos, *buf, *len)); - return USBD_REQ_HANDLED; - } - } - - return USBD_REQ_NEXT_CALLBACK; +static const struct usb_bos_descriptor *usb21_bos; + +static enum usbd_request_return_codes usb21_standard_get_descriptor( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *, struct usb_setup_data *)) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { + int descr_type = req->wValue >> 8; + if (descr_type == USB_DT_BOS) { + if (!usb21_bos) { + return USBD_REQ_NOTSUPP; + } + *len = MIN(*len, build_bos_descriptor(usb21_bos, *buf, *len)); + return USBD_REQ_HANDLED; + } + } + + return USBD_REQ_NEXT_CALLBACK; } -static void usb21_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; +static void usb21_set_config(usbd_device *usbd_dev, uint16_t wValue) { + (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - &usb21_standard_get_descriptor); + usbd_register_control_callback( + usbd_dev, USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + &usb21_standard_get_descriptor); } -void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store) { - usb21_bos = binary_object_store; +void usb21_setup(usbd_device *usbd_dev, + const struct usb_bos_descriptor *binary_object_store) { + usb21_bos = binary_object_store; - /* Register the control request handler _before_ the config is set */ - usb21_set_config(usbd_dev, 0x0000); - usbd_register_set_config_callback(usbd_dev, usb21_set_config); + /* Register the control request handler _before_ the config is set */ + usb21_set_config(usbd_dev, 0x0000); + usbd_register_set_config_callback(usbd_dev, usb21_set_config); } diff --git a/lib/board/util.c b/lib/board/util.c index 1ad2eb2c3..ab9a58901 100644 --- a/lib/board/util.c +++ b/lib/board/util.c @@ -17,9 +17,8 @@ * along with this library. If not, see . */ - #ifndef EMULATOR -# include +#include #endif #include "keepkey/board/util.h" @@ -28,87 +27,78 @@ static const char *hexdigits = "0123456789ABCDEF"; -void uint32hex(uint32_t num, char *str) -{ - uint32_t i; - for (i = 0; i < 8; i++) { - str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; - } +void uint32hex(uint32_t num, char *str) { + uint32_t i; + for (i = 0; i < 8; i++) { + str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; + } } // converts data to hexa -void data2hex(const void *data, uint32_t len, char *str) -{ - uint32_t i; - const uint8_t *cdata = (uint8_t *)data; - for (i = 0; i < len; i++) { - str[i * 2 ] = hexdigits[(cdata[i] >> 4) & 0xF]; - str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; - } - str[len * 2] = 0; +void data2hex(const void *data, uint32_t len, char *str) { + uint32_t i; + const uint8_t *cdata = (uint8_t *)data; + for (i = 0; i < len; i++) { + str[i * 2] = hexdigits[(cdata[i] >> 4) & 0xF]; + str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; + } + str[len * 2] = 0; } -uint32_t readprotobufint(uint8_t **ptr) -{ - uint32_t result = (**ptr & 0x7F); - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128 * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128 * 128 * 128; - } - } - } - } - (*ptr)++; - return result; +uint32_t readprotobufint(uint8_t **ptr) { + uint32_t result = (**ptr & 0x7F); + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128 * 128; + } + } + } + } + (*ptr)++; + return result; } -void rev_byte_order(uint8_t *bfr, size_t len) -{ - size_t i; - uint8_t tempdata; +void rev_byte_order(uint8_t *bfr, size_t len) { + size_t i; + uint8_t tempdata; - for(i = 0; i < len/2; i++) - { - tempdata = bfr[i]; - bfr[i] = bfr[len - i - 1]; - bfr[len - i - 1] = tempdata; - } + for (i = 0; i < len / 2; i++) { + tempdata = bfr[i]; + bfr[i] = bfr[len - i - 1]; + bfr[len - i - 1] = tempdata; + } } /*convert 64bit decimal to string (itoa)*/ -void dec64_to_str(uint64_t dec64_val, char *str) -{ - unsigned int b = 0; - static char *sbfr; +void dec64_to_str(uint64_t dec64_val, char *str) { + unsigned int b = 0; + static char *sbfr; - sbfr = str; - b = dec64_val %10; - dec64_val = dec64_val / 10; + sbfr = str; + b = dec64_val % 10; + dec64_val = dec64_val / 10; - if(dec64_val) - { - dec64_to_str(dec64_val, sbfr); - } - *sbfr = '0' + b; - sbfr++; + if (dec64_val) { + dec64_to_str(dec64_val, sbfr); + } + *sbfr = '0' + b; + sbfr++; } -bool is_valid_ascii(const uint8_t *data, uint32_t size) -{ - for (uint32_t i = 0; i < size; i++) { - if (data[i] < ' ' || data[i] > '~') { - return false; - } - } - return true; +bool is_valid_ascii(const uint8_t *data, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + if (data[i] < ' ' || data[i] > '~') { + return false; + } + } + return true; } - diff --git a/lib/board/variant.c b/lib/board/variant.c index 1b5291a38..d996858ab 100644 --- a/lib/board/variant.c +++ b/lib/board/variant.c @@ -10,7 +10,7 @@ #include -#define SIGNEDVARIANTINFO_FLASH (SignedVariantInfo*)(0x8010000) +#define SIGNEDVARIANTINFO_FLASH (SignedVariantInfo *)(0x8010000) static const VariantAnimation *screensaver; static const VariantAnimation *logo; @@ -19,132 +19,146 @@ static const char *name; // Retrieves model information from storage Model getModel(void) { - const char *model = flash_getModel(); - if (!model) - return MODEL_UNKNOWN; -#define MODEL_ENTRY_KK(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_KEEPKEY; \ - } + const char *model = flash_getModel(); + if (!model) return MODEL_UNKNOWN; +#define MODEL_ENTRY_KK(STRING, ENUM) \ + if (0 == strcmp(model, (STRING))) { \ + return MODEL_KEEPKEY; \ + } #define MODEL_ENTRY_SALT(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_SALT; \ - } + if (0 == strcmp(model, (STRING))) { \ + return MODEL_SALT; \ + } #define MODEL_ENTRY_FOX(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_FOX; \ - } + if (0 == strcmp(model, (STRING))) { \ + return MODEL_FOX; \ + } #define MODEL_ENTRY_KASPERSKY(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_KASPERSKY; \ - } + if (0 == strcmp(model, (STRING))) { \ + return MODEL_KASPERSKY; \ + } #define MODEL_ENTRY_BLOCKPIT(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_BLOCKPIT; \ - } + if (0 == strcmp(model, (STRING))) { \ + return MODEL_BLOCKPIT; \ + } #define MODEL_ENTRY_DASH(STRING, ENUM) \ - if (0 == strcmp(model, (STRING))) { \ - return MODEL_DASH; \ - } + if (0 == strcmp(model, (STRING))) { \ + return MODEL_DASH; \ + } #include "keepkey/board/models.def" - return MODEL_UNKNOWN; + return MODEL_UNKNOWN; } #if !defined(EMULATOR) static int variant_signature_check(const SignedVariantInfo *svi) { - uint8_t sigindex1 = svi->meta.sig_index1; - uint8_t sigindex2 = svi->meta.sig_index2; - uint8_t sigindex3 = svi->meta.sig_index3; + uint8_t sigindex1 = svi->meta.sig_index1; + uint8_t sigindex2 = svi->meta.sig_index2; + uint8_t sigindex3 = svi->meta.sig_index3; - if(sigindex1 < 1 || sigindex1 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ + if (sigindex1 < 1 || sigindex1 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ - if(sigindex2 < 1 || sigindex2 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ + if (sigindex2 < 1 || sigindex2 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ - if(sigindex3 < 1 || sigindex3 > PUBKEYS) { return SIG_FAIL; } /* Invalid index */ + if (sigindex3 < 1 || sigindex3 > PUBKEYS) { + return SIG_FAIL; + } /* Invalid index */ - if(sigindex1 == sigindex2) { return SIG_FAIL; } /* Duplicate use */ + if (sigindex1 == sigindex2) { + return SIG_FAIL; + } /* Duplicate use */ - if(sigindex1 == sigindex3) { return SIG_FAIL; } /* Duplicate use */ + if (sigindex1 == sigindex3) { + return SIG_FAIL; + } /* Duplicate use */ - if(sigindex2 == sigindex3) { return SIG_FAIL; } /* Duplicate use */ + if (sigindex2 == sigindex3) { + return SIG_FAIL; + } /* Duplicate use */ - uint8_t info_fingerprint[32]; - sha256_Raw((void *)&svi->info, svi->meta.code_len, info_fingerprint); + uint8_t info_fingerprint[32]; + sha256_Raw((void *)&svi->info, svi->meta.code_len, info_fingerprint); - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], &svi->meta.sig1[0], - info_fingerprint) != 0) - return SIG_FAIL; + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], &svi->meta.sig1[0], + info_fingerprint) != 0) + return SIG_FAIL; - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], &svi->meta.sig2[0], - info_fingerprint) != 0) - return SIG_FAIL; + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], &svi->meta.sig2[0], + info_fingerprint) != 0) + return SIG_FAIL; - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], &svi->meta.sig3[0], - info_fingerprint) != 0) - return SIG_FAIL; + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], &svi->meta.sig3[0], + info_fingerprint) != 0) + return SIG_FAIL; - return SIG_OK; + return SIG_OK; } #endif -const VariantInfo * __attribute__((weak)) variant_getInfo(void) { +const VariantInfo *__attribute__((weak)) variant_getInfo(void) { #ifndef EMULATOR - const SignedVariantInfo *flash = SIGNEDVARIANTINFO_FLASH; - if (memcmp(&flash->meta.magic, VARIANTINFO_MAGIC, - sizeof(flash->meta.magic)) == 0) { - if (SIG_OK == variant_signature_check(flash)) - { - return &flash->info; - } + const SignedVariantInfo *flash = SIGNEDVARIANTINFO_FLASH; + if (memcmp(&flash->meta.magic, VARIANTINFO_MAGIC, + sizeof(flash->meta.magic)) == 0) { + if (SIG_OK == variant_signature_check(flash)) { + return &flash->info; + } #ifdef DEBUG_ON - return &flash->info; + return &flash->info; #endif - } + } #endif - switch (getModel()) { - case MODEL_KEEPKEY: return &variant_keepkey; - case MODEL_SALT: return &variant_salt; - case MODEL_FOX: return &variant_keepkey; - case MODEL_KASPERSKY: return &variant_keepkey; - case MODEL_BLOCKPIT: return &variant_keepkey; - case MODEL_DASH: return &variant_keepkey; - case MODEL_UNKNOWN: return &variant_keepkey; - } - return &variant_keepkey; + switch (getModel()) { + case MODEL_KEEPKEY: + return &variant_keepkey; + case MODEL_SALT: + return &variant_salt; + case MODEL_FOX: + return &variant_keepkey; + case MODEL_KASPERSKY: + return &variant_keepkey; + case MODEL_BLOCKPIT: + return &variant_keepkey; + case MODEL_DASH: + return &variant_keepkey; + case MODEL_UNKNOWN: + return &variant_keepkey; + } + return &variant_keepkey; } const VariantAnimation *variant_getScreensaver(void) { - if (screensaver) - return screensaver; + if (screensaver) return screensaver; - screensaver = variant_getInfo()->screensaver; - return screensaver; + screensaver = variant_getInfo()->screensaver; + return screensaver; } const VariantAnimation *variant_getLogo(bool reversed) { - if (reversed && logo_reversed) - return logo_reversed; - if (!reversed && logo) - return logo; + if (reversed && logo_reversed) return logo_reversed; + if (!reversed && logo) return logo; - logo = variant_getInfo()->logo; - logo_reversed = variant_getInfo()->logo_reversed; + logo = variant_getInfo()->logo; + logo_reversed = variant_getInfo()->logo_reversed; - return reversed ? logo_reversed : logo; + return reversed ? logo_reversed : logo; } const char *variant_getName(void) { #ifdef EMULATOR - return "Emulator"; + return "Emulator"; #else - if (name) { - return name; - } - - name = variant_getInfo()->name; + if (name) { return name; + } + + name = variant_getInfo()->name; + return name; #endif } diff --git a/lib/board/variant/keepkey/resources.c b/lib/board/variant/keepkey/resources.c index ab4df2ceb..8c8623819 100644 --- a/lib/board/variant/keepkey/resources.c +++ b/lib/board/variant/keepkey/resources.c @@ -1,2 +1 @@ #include "keepkey/board/variant.h" - diff --git a/lib/board/webusb.c b/lib/board/webusb.c index 260cf4b23..2a9b78316 100644 --- a/lib/board/webusb.c +++ b/lib/board/webusb.c @@ -22,85 +22,82 @@ #include -const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { - .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DC_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = WEBUSB_UUID, - .bcdVersion = 0x0100, - .bVendorCode = WEBUSB_VENDOR_CODE, - .iLandingPage = 1 -}; +const struct webusb_platform_descriptor webusb_platform_capability_descriptor = + {.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 1}; -const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page = { - .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DC_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = WEBUSB_UUID, - .bcdVersion = 0x0100, - .bVendorCode = WEBUSB_VENDOR_CODE, - .iLandingPage = 0 -}; +const struct webusb_platform_descriptor + webusb_platform_capability_descriptor_no_landing_page = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 0}; -static const char* webusb_https_url; +static const char *webusb_https_url; -static enum usbd_request_return_codes -webusb_control_vendor_request(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) -{ - (void)complete; - (void)usbd_dev; +static enum usbd_request_return_codes webusb_control_vendor_request( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *, struct usb_setup_data *)) { + (void)complete; + (void)usbd_dev; - if (req->bRequest != WEBUSB_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } + if (req->bRequest != WEBUSB_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } - int status = USBD_REQ_NOTSUPP; - switch (req->wIndex) { - case WEBUSB_REQ_GET_URL: { - struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); - uint16_t index = req->wValue; - if (index == 0) { - return USBD_REQ_NOTSUPP; - } + int status = USBD_REQ_NOTSUPP; + switch (req->wIndex) { + case WEBUSB_REQ_GET_URL: { + struct webusb_url_descriptor *url = + (struct webusb_url_descriptor *)(*buf); + uint16_t index = req->wValue; + if (index == 0) { + return USBD_REQ_NOTSUPP; + } - if (index == 1) { - size_t url_len = strlen(webusb_https_url); - url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; - url->bDescriptorType = WEBUSB_DT_URL; - url->bScheme = WEBUSB_URL_SCHEME_HTTPS; - memcpy(&url->URL, webusb_https_url, url_len); - *len = MIN(*len, url->bLength); - status = USBD_REQ_HANDLED; - } else { - // TODO: stall instead? - status = USBD_REQ_NOTSUPP; - } - break; - } - default: { - status = USBD_REQ_NOTSUPP; - break; - } - } + if (index == 1) { + size_t url_len = strlen(webusb_https_url); + url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; + url->bDescriptorType = WEBUSB_DT_URL; + url->bScheme = WEBUSB_URL_SCHEME_HTTPS; + memcpy(&url->URL, webusb_https_url, url_len); + *len = MIN(*len, url->bLength); + status = USBD_REQ_HANDLED; + } else { + // TODO: stall instead? + status = USBD_REQ_NOTSUPP; + } + break; + } + default: { + status = USBD_REQ_NOTSUPP; + break; + } + } - return status; + return status; } -static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - webusb_control_vendor_request); +static void webusb_set_config(usbd_device *usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback(usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + webusb_control_vendor_request); } -void webusb_setup(usbd_device* usbd_dev, const char* https_url) { - webusb_https_url = https_url; +void webusb_setup(usbd_device *usbd_dev, const char *https_url) { + webusb_https_url = https_url; - usbd_register_set_config_callback(usbd_dev, webusb_set_config); + usbd_register_set_config_callback(usbd_dev, webusb_set_config); } diff --git a/lib/board/winusb.c b/lib/board/winusb.c index c8d6fe47e..a20b82753 100644 --- a/lib/board/winusb.c +++ b/lib/board/winusb.c @@ -22,144 +22,134 @@ #include -static int usb_descriptor_type(uint16_t wValue) { - return wValue >> 8; -} +static int usb_descriptor_type(uint16_t wValue) { return wValue >> 8; } -static int usb_descriptor_index(uint16_t wValue) { - return wValue & 0xFF; -} +static int usb_descriptor_index(uint16_t wValue) { return wValue & 0xFF; } static struct winusb_compatible_id_descriptor winusb_wcid = { - .header = { - .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + - 1 * sizeof(struct winusb_compatible_id_function_section), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, - .bNumSections = 1, - .reserved = { 0, 0, 0, 0, 0, 0, 0 }, - }, - .functions = { - { - // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number - .bInterfaceNumber = 0, - .reserved0 = { 1 }, - .compatibleId = "WINUSB", - .subCompatibleId = "", - .reserved1 = { 0, 0, 0, 0, 0, 0} - }, - } -}; + .header = + { + .dwLength = + sizeof(struct winusb_compatible_id_descriptor_header) + + 1 * sizeof(struct winusb_compatible_id_function_section), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, + .bNumSections = 1, + .reserved = {0, 0, 0, 0, 0, 0, 0}, + }, + .functions = { + {// note - bInterfaceNumber is rewritten in winusb_setup with the + // correct interface number + .bInterfaceNumber = 0, + .reserved0 = {1}, + .compatibleId = "WINUSB", + .subCompatibleId = "", + .reserved1 = {0, 0, 0, 0, 0, 0}}, + }}; static const struct usb_string_descriptor winusb_string_descriptor = { - .bLength = 0x12, - .bDescriptorType = USB_DT_STRING, - .wData = WINUSB_EXTRA_STRING -}; + .bLength = 0x12, + .bDescriptorType = USB_DT_STRING, + .wData = WINUSB_EXTRA_STRING}; static const struct winusb_extended_properties_descriptor guid = { - .header = { - .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) - + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, - .wNumFeatures = 1, - }, - .features = { - { - .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), - .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, - .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, - .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, - .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, - .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, - }, - } -}; - -static enum usbd_request_return_codes -winusb_descriptor_request(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) -{ - (void)complete; - (void)usbd_dev; - - if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { - return USBD_REQ_NEXT_CALLBACK; - } - - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { - if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { - *buf = (uint8_t*)(&winusb_string_descriptor); - *len = MIN(*len, winusb_string_descriptor.bLength); - return USBD_REQ_HANDLED; - } - } - return USBD_REQ_NEXT_CALLBACK; + .header = + { + .dwLength = + sizeof(struct winusb_extended_properties_descriptor_header) + + 1 * sizeof( + struct winusb_extended_properties_feature_descriptor), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, + .wNumFeatures = 1, + }, + .features = { + { + .dwLength = + sizeof(struct winusb_extended_properties_feature_descriptor), + .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, + .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, + .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, + .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, + .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, + }, + }}; + +static enum usbd_request_return_codes winusb_descriptor_request( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *, struct usb_setup_data *)) { + (void)complete; + (void)usbd_dev; + + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return USBD_REQ_NEXT_CALLBACK; + } + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && + usb_descriptor_type(req->wValue) == USB_DT_STRING) { + if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { + *buf = (uint8_t *)(&winusb_string_descriptor); + *len = MIN(*len, winusb_string_descriptor.bLength); + return USBD_REQ_HANDLED; + } + } + return USBD_REQ_NEXT_CALLBACK; } -static enum usbd_request_return_codes -winusb_control_vendor_request(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) -{ - (void)complete; - (void)usbd_dev; - - if (req->bRequest != WINUSB_MS_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } - - int status = USBD_REQ_NOTSUPP; - if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && - (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { - *buf = (uint8_t*)(&winusb_wcid); - *len = MIN(*len, winusb_wcid.header.dwLength); - status = USBD_REQ_HANDLED; - - } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && - (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && - (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { - - *buf = (uint8_t*)(&guid); - *len = MIN(*len, guid.header.dwLength); - status = USBD_REQ_HANDLED; - - } else { - status = USBD_REQ_NOTSUPP; - } - - return status; +static enum usbd_request_return_codes winusb_control_vendor_request( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *, struct usb_setup_data *)) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && + (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { + *buf = (uint8_t *)(&winusb_wcid); + *len = MIN(*len, winusb_wcid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == + USB_REQ_TYPE_INTERFACE) && + (req->wIndex == + WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && + (usb_descriptor_index(req->wValue) == + winusb_wcid.functions[0].bInterfaceNumber)) { + *buf = (uint8_t *)(&guid); + *len = MIN(*len, guid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else { + status = USBD_REQ_NOTSUPP; + } + + return status; } -static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); +static void winusb_set_config(usbd_device *usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); } -void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { - winusb_wcid.functions[0].bInterfaceNumber = interface; +void winusb_setup(usbd_device *usbd_dev, uint8_t interface) { + winusb_wcid.functions[0].bInterfaceNumber = interface; - usbd_register_set_config_callback(usbd_dev, winusb_set_config); + usbd_register_set_config_callback(usbd_dev, winusb_set_config); - /* Windows probes the compatible ID before setting the configuration, - so also register the callback now */ + /* Windows probes the compatible ID before setting the configuration, + so also register the callback now */ - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_RECIPIENT, - winusb_descriptor_request); + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_RECIPIENT, + winusb_descriptor_request); } - diff --git a/lib/emulator/oled.c b/lib/emulator/oled.c index 29c6bc5a1..9552b3d25 100644 --- a/lib/emulator/oled.c +++ b/lib/emulator/oled.c @@ -21,4 +21,3 @@ void oledInit(void) {} void oledRefresh(void) {} void emulatorPoll(void) {} - diff --git a/lib/emulator/setup.c b/lib/emulator/setup.c index f70c9e719..45f601c31 100644 --- a/lib/emulator/setup.c +++ b/lib/emulator/setup.c @@ -39,52 +39,53 @@ static void setup_urandom(void); static void setup_flash(void); void setup(void) { - setup_urandom(); - setup_flash(); + setup_urandom(); + setup_flash(); } void emulatorRandom(void *buffer, size_t size) { - ssize_t n = read(urandom, buffer, size); - if (n < 0 || ((size_t) n) != size) { - perror("Failed to read /dev/urandom"); - exit(1); - } + ssize_t n = read(urandom, buffer, size); + if (n < 0 || ((size_t)n) != size) { + perror("Failed to read /dev/urandom"); + exit(1); + } } static void setup_urandom(void) { - urandom = open("/dev/urandom", O_RDONLY); - if (urandom < 0) { - perror("Failed to open /dev/urandom"); - exit(1); - } + urandom = open("/dev/urandom", O_RDONLY); + if (urandom < 0) { + perror("Failed to open /dev/urandom"); + exit(1); + } } static void setup_flash(void) { - int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); - if (fd < 0) { - perror("Failed to open flash emulation file"); - exit(1); - } + int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); + if (fd < 0) { + perror("Failed to open flash emulation file"); + exit(1); + } - off_t length = lseek(fd, 0, SEEK_END); - if (length < 0) { - perror("Failed to read length of flash emulation file"); - exit(1); - } + off_t length = lseek(fd, 0, SEEK_END); + if (length < 0) { + perror("Failed to read length of flash emulation file"); + exit(1); + } - emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (emulator_flash_base == MAP_FAILED) { - perror("Failed to map flash emulation file"); - exit(1); - } + emulator_flash_base = + mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (emulator_flash_base == MAP_FAILED) { + perror("Failed to map flash emulation file"); + exit(1); + } - if (length < FLASH_TOTAL_SIZE) { - if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { - perror("Failed to initialize flash emulation file"); - exit(1); - } + if (length < FLASH_TOTAL_SIZE) { + if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { + perror("Failed to initialize flash emulation file"); + exit(1); + } - /* Initialize the flash */ - memset(emulator_flash_base, 0xff, FLASH_TOTAL_SIZE); - } + /* Initialize the flash */ + memset(emulator_flash_base, 0xff, FLASH_TOTAL_SIZE); + } } diff --git a/lib/emulator/udp.c b/lib/emulator/udp.c index b79b1ae7f..8615dfbc3 100644 --- a/lib/emulator/udp.c +++ b/lib/emulator/udp.c @@ -27,98 +27,102 @@ #define TREZOR_UDP_PORT 21324 struct usb_socket { - int fd; - struct sockaddr_in from; - socklen_t fromlen; + int fd; + struct sockaddr_in from; + socklen_t fromlen; }; static struct usb_socket usb_main; static struct usb_socket usb_debug; static int socket_setup(int port) { - int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) { - perror("Failed to create socket"); - exit(1); - } - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { - perror("Failed to bind socket"); - exit(1); - } - - return fd; + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + perror("Failed to create socket"); + exit(1); + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + // addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + perror("Failed to bind socket"); + exit(1); + } + + return fd; } -static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t size) { - if (sock->fromlen > 0) { - ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &sock->from, sock->fromlen); - if (n < 0 || ((size_t) n) != size) { - perror("Failed to write socket"); - return 0; - } - } - - return size; +static size_t socket_write(struct usb_socket *sock, const void *buffer, + size_t size) { + if (sock->fromlen > 0) { + ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, + (const struct sockaddr *)&sock->from, sock->fromlen); + if (n < 0 || ((size_t)n) != size) { + perror("Failed to write socket"); + return 0; + } + } + + return size; } static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) { - sock->fromlen = sizeof(sock->from); - ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &sock->from, &sock->fromlen); - - if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - perror("Failed to read socket"); - } - return 0; - } - - static const char msg_ping[] = { 'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G' }; - static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; - - if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { - socket_write(sock, msg_pong, sizeof(msg_pong)); - return 0; - } - - return n; + sock->fromlen = sizeof(sock->from); + ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, + (struct sockaddr *)&sock->from, &sock->fromlen); + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("Failed to read socket"); + } + return 0; + } + + static const char msg_ping[] = {'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G'}; + static const char msg_pong[] = {'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G'}; + + if (n == sizeof(msg_ping) && + memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { + socket_write(sock, msg_pong, sizeof(msg_pong)); + return 0; + } + + return n; } void emulatorSocketInit(void) { - usb_main.fd = socket_setup(TREZOR_UDP_PORT); - usb_main.fromlen = 0; - usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); - usb_debug.fromlen = 0; + usb_main.fd = socket_setup(TREZOR_UDP_PORT); + usb_main.fromlen = 0; + usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); + usb_debug.fromlen = 0; } size_t emulatorSocketRead(int *iface, void *buffer, size_t size) { - size_t n = socket_read(&usb_main, buffer, size); - if (n > 0) { - *iface = 0; - return n; - } - - n = socket_read(&usb_debug, buffer, size); - if (n > 0) { - *iface = 1; - return n; - } - - return 0; + size_t n = socket_read(&usb_main, buffer, size); + if (n > 0) { + *iface = 0; + return n; + } + + n = socket_read(&usb_debug, buffer, size); + if (n > 0) { + *iface = 1; + return n; + } + + return 0; } size_t emulatorSocketWrite(int iface, const void *buffer, size_t size) { - if (iface == 0) { - return socket_write(&usb_main, buffer, size); - } - if (iface == 1) { - return socket_write(&usb_debug, buffer, size); - } - return 0; + if (iface == 0) { + return socket_write(&usb_main, buffer, size); + } + if (iface == 1) { + return socket_write(&usb_debug, buffer, size); + } + return 0; } diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index 74e871648..d66a955f4 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -27,6 +27,7 @@ set(sources storage.c tendermint.c transaction.c + txin_check.c u2f.c) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_revision.h.in" diff --git a/lib/firmware/app_confirm.c b/lib/firmware/app_confirm.c index 16ea22608..83cf1d59e 100644 --- a/lib/firmware/app_confirm.c +++ b/lib/firmware/app_confirm.c @@ -19,9 +19,9 @@ #if !defined(EMULATOR) // FIXME: cortex.h should really have these includes inside it. -# include -# include -# include +#include +#include +#include #endif #include "keepkey/board/keepkey_display.h" @@ -59,22 +59,18 @@ * OUTPUT * true/false of confirmation */ -bool confirm_cipher(bool encrypt, const char *key) -{ - bool ret_stat; - - if(encrypt) - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, - "Encrypt Key Value", "%s", key); - } - else - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, - "Decrypt Key Value", "%s", key); - } - - return(ret_stat); +bool confirm_cipher(bool encrypt, const char *key) { + bool ret_stat; + + if (encrypt) { + ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, + "Encrypt Key Value", "%s", key); + } else { + ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, + "Decrypt Key Value", "%s", key); + } + + return (ret_stat); } /* @@ -86,22 +82,18 @@ bool confirm_cipher(bool encrypt, const char *key) * OUTPUT * true/false of confirmation */ -bool confirm_encrypt_msg(const char *msg, bool signing) -{ - bool ret_stat; - - if(signing) - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_EncryptAndSignMessage, - "Encrypt and Sign Message", "%s", msg); - } - else - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_EncryptMessage, - "Encrypt Message", "%s", msg); - } - - return(ret_stat); +bool confirm_encrypt_msg(const char *msg, bool signing) { + bool ret_stat; + + if (signing) { + ret_stat = confirm(ButtonRequestType_ButtonRequest_EncryptAndSignMessage, + "Encrypt and Sign Message", "%s", msg); + } else { + ret_stat = confirm(ButtonRequestType_ButtonRequest_EncryptMessage, + "Encrypt Message", "%s", msg); + } + + return (ret_stat); } /* @@ -114,22 +106,18 @@ bool confirm_encrypt_msg(const char *msg, bool signing) * true/false of confirmation * */ -bool confirm_decrypt_msg(const char *msg, const char *address) -{ - bool ret_stat; - - if(address) - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, - "Decrypted Signed Message", "%s", msg); - } - else - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, - "Decrypted Message", "%s", msg); - } - - return(ret_stat); +bool confirm_decrypt_msg(const char *msg, const char *address) { + bool ret_stat; + + if (address) { + ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, + "Decrypted Signed Message", "%s", msg); + } else { + ret_stat = confirm(ButtonRequestType_ButtonRequest_Other, + "Decrypted Message", "%s", msg); + } + + return (ret_stat); } /* @@ -142,14 +130,11 @@ bool confirm_decrypt_msg(const char *msg, const char *address) * true/false of confirmation * */ -bool confirm_exchange_output(const char *dep_amt, - const char *wit_amt) -{ - return confirm_with_custom_layout(&layout_standard_notification, - ButtonRequestType_ButtonRequest_SignExchange, - "ShapeShift", - "Trade %s with ShapeShift in exchange for %s?", - dep_amt, wit_amt); +bool confirm_exchange_output(const char *dep_amt, const char *wit_amt) { + return confirm_with_custom_layout( + &layout_standard_notification, + ButtonRequestType_ButtonRequest_SignExchange, "ShapeShift", + "Trade %s with ShapeShift in exchange for %s?", dep_amt, wit_amt); } /* @@ -163,13 +148,11 @@ bool confirm_exchange_output(const char *dep_amt, * true/false of confirmation * */ -bool confirm_transfer_output(ButtonRequestType button_request, const char *amount, - const char *to) -{ - return confirm_with_custom_layout(&layout_notification_no_title_bold, - button_request, - "", - "Transfer %s\nto %s", amount, to); +bool confirm_transfer_output(ButtonRequestType button_request, + const char *amount, const char *to) { + return confirm_with_custom_layout(&layout_notification_no_title_bold, + button_request, "", "Transfer %s\nto %s", + amount, to); } /* @@ -183,18 +166,16 @@ bool confirm_transfer_output(ButtonRequestType button_request, const char *amoun * true/false of confirmation * */ -bool confirm_transaction_output(ButtonRequestType button_request, const char *amount, - const char *to) -{ - return confirm_with_custom_layout(&layout_notification_no_title_bold, - button_request, - "", - "Send %s to\n%s", amount, to); +bool confirm_transaction_output(ButtonRequestType button_request, + const char *amount, const char *to) { + return confirm_with_custom_layout(&layout_notification_no_title_bold, + button_request, "", "Send %s to\n%s", + amount, to); } - /* - * confirm_erc_token_transfer() - Show transaction output confirmation without bold + * confirm_erc_token_transfer() - Show transaction output confirmation without + * bold * * INPUT - * - button_request: button request type @@ -205,20 +186,14 @@ bool confirm_transaction_output(ButtonRequestType button_request, const char *am * */ bool confirm_erc_token_transfer(ButtonRequestType button_request, - const char *msg_body) -{ - return confirm_with_custom_layout(&layout_notification_no_title_no_bold, - button_request, - "", - "Send %s", msg_body); + const char *msg_body) { + return confirm_with_custom_layout(&layout_notification_no_title_no_bold, + button_request, "", "Send %s", msg_body); } - - - - /* - * confirm_transaction_output_no_bold() - Show transaction output confirmation without bold + * confirm_transaction_output_no_bold() - Show transaction output confirmation + * without bold * * INPUT - * - button_request: button request type @@ -229,12 +204,10 @@ bool confirm_erc_token_transfer(ButtonRequestType button_request, * */ bool confirm_transaction_output_no_bold(ButtonRequestType button_request, - const char *amount, const char *to) -{ - return confirm_with_custom_layout(&layout_notification_no_title_no_bold, - button_request, - "", - "Send %s to\n%s", amount, to); + const char *amount, const char *to) { + return confirm_with_custom_layout(&layout_notification_no_title_no_bold, + button_request, "", "Send %s to\n%s", + amount, to); } /* @@ -247,19 +220,16 @@ bool confirm_transaction_output_no_bold(ButtonRequestType button_request, * true/false of confirmation * */ -bool confirm_transaction(const char *total_amount, const char *fee) -{ - if (!fee || strcmp(fee, "0.0 BTC") == 0) { - return confirm(ButtonRequestType_ButtonRequest_SignTx, - "Transaction", - "Do you want to send %s from your wallet?", - total_amount); - } else { - return confirm(ButtonRequestType_ButtonRequest_SignTx, - "Transaction", - "Do you want to send %s from your wallet? This includes a transaction fee of %s.", - total_amount, fee); - } +bool confirm_transaction(const char *total_amount, const char *fee) { + if (!fee || strcmp(fee, "0.0 BTC") == 0) { + return confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", + "Do you want to send %s from your wallet?", total_amount); + } else { + return confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", + "Do you want to send %s from your wallet? This includes a " + "transaction fee of %s.", + total_amount, fee); + } } /* @@ -271,24 +241,22 @@ bool confirm_transaction(const char *total_amount, const char *fee) * true/false of confirmation * */ -bool confirm_load_device(bool is_node) -{ - bool ret_stat; - - if(is_node) - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_ImportPrivateKey, - "Import Private Key", - "Importing is not recommended unless you understand the risks. Do you want to import private key?"); - } - else - { - ret_stat = confirm(ButtonRequestType_ButtonRequest_ImportRecoverySentence, - "Import Recovery Sentence", - "Importing is not recommended unless you understand the risks. Do you want to import recovery sentence?"); - } - - return(ret_stat); +bool confirm_load_device(bool is_node) { + bool ret_stat; + + if (is_node) { + ret_stat = confirm(ButtonRequestType_ButtonRequest_ImportPrivateKey, + "Import Private Key", + "Importing is not recommended unless you understand the " + "risks. Do you want to import private key?"); + } else { + ret_stat = confirm(ButtonRequestType_ButtonRequest_ImportRecoverySentence, + "Import Recovery Sentence", + "Importing is not recommended unless you understand the " + "risks. Do you want to import recovery sentence?"); + } + + return (ret_stat); } /* @@ -300,11 +268,10 @@ bool confirm_load_device(bool is_node) * true/false of confirmation * */ -bool confirm_xpub(const char *node_str, const char *xpub) -{ - return confirm_with_custom_layout(&layout_xpub_notification, - ButtonRequestType_ButtonRequest_Address, node_str, "%s", xpub); - +bool confirm_xpub(const char *node_str, const char *xpub) { + return confirm_with_custom_layout(&layout_xpub_notification, + ButtonRequestType_ButtonRequest_Address, + node_str, "%s", xpub); } /* @@ -317,10 +284,10 @@ bool confirm_xpub(const char *node_str, const char *xpub) * true/false of confirmation * */ -bool confirm_ethereum_address(const char *desc, const char *address) -{ - return confirm_with_custom_layout(&layout_ethereum_address_notification, - ButtonRequestType_ButtonRequest_Address, desc, "%s", address); +bool confirm_ethereum_address(const char *desc, const char *address) { + return confirm_with_custom_layout(&layout_ethereum_address_notification, + ButtonRequestType_ButtonRequest_Address, + desc, "%s", address); } /* @@ -333,10 +300,10 @@ bool confirm_ethereum_address(const char *desc, const char *address) * true/false of confirmation * */ -bool confirm_nano_address(const char *desc, const char *address) -{ - return confirm_with_custom_layout(&layout_nano_address_notification, - ButtonRequestType_ButtonRequest_Address, desc, "%s", address); +bool confirm_nano_address(const char *desc, const char *address) { + return confirm_with_custom_layout(&layout_nano_address_notification, + ButtonRequestType_ButtonRequest_Address, + desc, "%s", address); } /* @@ -349,10 +316,10 @@ bool confirm_nano_address(const char *desc, const char *address) * true/false of confirmation * */ -bool confirm_address(const char *desc, const char *address) -{ - return confirm_with_custom_layout(&layout_address_notification, - ButtonRequestType_ButtonRequest_Address, desc, "%s", address); +bool confirm_address(const char *desc, const char *address) { + return confirm_with_custom_layout(&layout_address_notification, + ButtonRequestType_ButtonRequest_Address, + desc, "%s", address); } /* @@ -365,106 +332,97 @@ bool confirm_address(const char *desc, const char *address) * true/false of confirmation * */ -bool confirm_sign_identity(const IdentityType *identity, const char *challenge) -{ - char title[CONFIRM_SIGN_IDENTITY_TITLE], body[CONFIRM_SIGN_IDENTITY_BODY]; - - /* Format protocol */ - if(identity->has_proto && identity->proto[0]) - { - strlcpy(title, identity->proto, sizeof(title)); - kk_strupr(title); - strlcat(title, " login to: ", sizeof(title)); - } - else - { - strlcpy(title, "Login to: ", sizeof(title)); - } - - /* Format host and port */ - if(identity->has_host && identity->host[0]) - { - strlcpy(body, "host: ", sizeof(body)); - strlcat(body, identity->host, sizeof(body)); - - if(identity->has_port && identity->port[0]) - { - strlcat(body, ":", sizeof(body)); - strlcat(body, identity->port, sizeof(body)); - } - - strlcat(body, "\n", sizeof(body)); - } - else - { - body[0] = 0; - } - - /* Format user */ - if(identity->has_user && identity->user[0]) - { - strlcat(body, "user: ", sizeof(body)); - strlcat(body, identity->user, sizeof(body)); - strlcat(body, "\n", sizeof(body)); - } - - /* Format challenge */ - if (challenge && strlen(challenge) != 0) - { - strlcat(body, challenge, sizeof(body)); +bool confirm_sign_identity(const IdentityType *identity, + const char *challenge) { + char title[CONFIRM_SIGN_IDENTITY_TITLE], body[CONFIRM_SIGN_IDENTITY_BODY]; + + /* Format protocol */ + if (identity->has_proto && identity->proto[0]) { + strlcpy(title, identity->proto, sizeof(title)); + kk_strupr(title); + strlcat(title, " login to: ", sizeof(title)); + } else { + strlcpy(title, "Login to: ", sizeof(title)); + } + + /* Format host and port */ + if (identity->has_host && identity->host[0]) { + strlcpy(body, "host: ", sizeof(body)); + strlcat(body, identity->host, sizeof(body)); + + if (identity->has_port && identity->port[0]) { + strlcat(body, ":", sizeof(body)); + strlcat(body, identity->port, sizeof(body)); } - return confirm(ButtonRequestType_ButtonRequest_SignIdentity, title, "%s", body); + strlcat(body, "\n", sizeof(body)); + } else { + body[0] = 0; + } + + /* Format user */ + if (identity->has_user && identity->user[0]) { + strlcat(body, "user: ", sizeof(body)); + strlcat(body, identity->user, sizeof(body)); + strlcat(body, "\n", sizeof(body)); + } + + /* Format challenge */ + if (challenge && strlen(challenge) != 0) { + strlcat(body, challenge, sizeof(body)); + } + + return confirm(ButtonRequestType_ButtonRequest_SignIdentity, title, "%s", + body); } -bool confirm_omni(ButtonRequestType button_request, const char *title, const uint8_t *data, uint32_t size) -{ - uint32_t tx_type, currency; - REVERSE32(*(const uint32_t *)(data + 4), tx_type); - if (tx_type == 0x00000000 && size == 20) { // OMNI simple send - char str_out[32]; - REVERSE32(*(const uint32_t *)(data + 8), currency); - const char *suffix = "UNKN"; - switch (currency) { - case 1: - suffix = " OMNI"; - break; - case 2: - suffix = " tOMNI"; - break; - case 3: - suffix = " MAID"; - break; - case 31: - suffix = " USDT"; - break; - } - uint64_t amount_be, amount; - memcpy(&amount_be, data + 12, sizeof(uint64_t)); - REVERSE64(amount_be, amount); - bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); - return confirm(button_request, title, _("Do you want to send %s?"), str_out); - } else { - return confirm(button_request, title, _("Unknown Transaction")); - } +bool confirm_omni(ButtonRequestType button_request, const char *title, + const uint8_t *data, uint32_t size) { + uint32_t tx_type, currency; + REVERSE32(*(const uint32_t *)(data + 4), tx_type); + if (tx_type == 0x00000000 && size == 20) { // OMNI simple send + char str_out[32]; + REVERSE32(*(const uint32_t *)(data + 8), currency); + const char *suffix = "UNKN"; + switch (currency) { + case 1: + suffix = " OMNI"; + break; + case 2: + suffix = " tOMNI"; + break; + case 3: + suffix = " MAID"; + break; + case 31: + suffix = " USDT"; + break; + } + uint64_t amount_be, amount; + memcpy(&amount_be, data + 12, sizeof(uint64_t)); + REVERSE64(amount_be, amount); + bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, + str_out, sizeof(str_out)); + return confirm(button_request, title, _("Do you want to send %s?"), + str_out); + } else { + return confirm(button_request, title, _("Unknown Transaction")); + } } bool confirm_data(ButtonRequestType button_request, const char *title, - const uint8_t *data, uint32_t size) -{ - const char *str = (const char *)data; - char hex[50 * 2 + 1]; - if (!is_valid_ascii(data, size)) { - if (size > 50) - size = 50; - memset(hex, 0, sizeof(hex)); - data2hex(data, size, hex); - if (size > 50) { - hex[50 * 2 - 1] = '.'; - hex[50 * 2 - 2] = '.'; - } - str = hex; - } - return confirm(button_request, title, "%s", str); + const uint8_t *data, uint32_t size) { + const char *str = (const char *)data; + char hex[50 * 2 + 1]; + if (!is_valid_ascii(data, size)) { + if (size > 50) size = 50; + memset(hex, 0, sizeof(hex)); + data2hex(data, size, hex); + if (size > 50) { + hex[50 * 2 - 1] = '.'; + hex[50 * 2 - 2] = '.'; + } + str = hex; + } + return confirm(button_request, title, "%s", str); } - diff --git a/lib/firmware/app_layout.c b/lib/firmware/app_layout.c index a31da0af2..e9c5c6887 100644 --- a/lib/firmware/app_layout.c +++ b/lib/firmware/app_layout.c @@ -49,135 +49,134 @@ * OUTPUT * none */ -static void layout_animate_pin(void *data, uint32_t duration, uint32_t elapsed) -{ - (void)duration; - BoxDrawableParams box_params = {{0x00, 0, 0}, 64, 256}; - DrawableParams sp; - Canvas *canvas = layout_get_canvas(); - char *pin = (char *)data; - const uint8_t color_stepping[] = {PIN_MATRIX_STEP1, PIN_MATRIX_STEP2, PIN_MATRIX_STEP3, PIN_MATRIX_STEP4, PIN_MATRIX_FOREGROUND}; - - const Font *pin_font = get_pin_font(); - - /* Draw matrix */ - box_params.base.color = PIN_MATRIX_BACKGROUND; - - for(uint8_t row = 0; row < 3; row++) - { - for(uint8_t col = 0; col < 3; col++) - { - box_params.base.y = 5 + row * 19; - box_params.base.x = PIN_LEFT_MARGIN + col * 19; - box_params.height = 18; - box_params.width = 18; - draw_box(canvas, &box_params); - } +static void layout_animate_pin(void *data, uint32_t duration, + uint32_t elapsed) { + (void)duration; + BoxDrawableParams box_params = {{0x00, 0, 0}, 64, 256}; + DrawableParams sp; + Canvas *canvas = layout_get_canvas(); + char *pin = (char *)data; + const uint8_t color_stepping[] = {PIN_MATRIX_STEP1, PIN_MATRIX_STEP2, + PIN_MATRIX_STEP3, PIN_MATRIX_STEP4, + PIN_MATRIX_FOREGROUND}; + + const Font *pin_font = get_pin_font(); + + /* Draw matrix */ + box_params.base.color = PIN_MATRIX_BACKGROUND; + + for (uint8_t row = 0; row < 3; row++) { + for (uint8_t col = 0; col < 3; col++) { + box_params.base.y = 5 + row * 19; + box_params.base.x = PIN_LEFT_MARGIN + col * 19; + box_params.height = 18; + box_params.width = 18; + draw_box(canvas, &box_params); } + } + + /* Configure each PIN digit animation settings */ + const PINAnimationConfig pin_animation_cfg[] = { + {SLIDE_RIGHT, 8 * PIN_SLIDE_DELAY}, // 1 + {SLIDE_UP, 7 * PIN_SLIDE_DELAY}, // 2 + {SLIDE_DOWN, 6 * PIN_SLIDE_DELAY}, // 3 + {SLIDE_LEFT, 5 * PIN_SLIDE_DELAY}, // 4 + {SLIDE_UP, 4 * PIN_SLIDE_DELAY}, // 5 + {SLIDE_RIGHT, 3 * PIN_SLIDE_DELAY}, // 6 + {SLIDE_UP, 0 * PIN_SLIDE_DELAY}, // 7 + {SLIDE_RIGHT, 1 * PIN_SLIDE_DELAY}, // 8 + {SLIDE_DOWN, 2 * PIN_SLIDE_DELAY} // 9 + }; + + /* Draw each pin digit individually base on animation config on matrix + * position */ + for (uint8_t row = 0; row < 3; row++) { + for (uint8_t col = 0; col < 3; col++) { + uint8_t cur_pos = col + (2 - row) * 3; + const PINAnimationConfig *cur_pos_cfg = &pin_animation_cfg[cur_pos]; + uint32_t cur_pos_elapsed = elapsed - cur_pos_cfg->elapsed_start_ms; + + /* Skip position is enough time has not passed */ + if (cur_pos_cfg->elapsed_start_ms > elapsed) { + continue; + } + + /* Determine color */ + sp.color = PIN_MATRIX_FOREGROUND; + + for (uint8_t color_index = 0; + color_index < sizeof(color_stepping) / sizeof(color_stepping[0]); + color_index++) { + if (cur_pos_elapsed < + (color_index * PIN_MATRIX_ANIMATION_FREQUENCY_MS)) { + sp.color = color_stepping[color_index]; + break; + } + } + + uint8_t pad = 7; + + /* Adjust pad */ + if (pin[cur_pos] == '1') { + pad++; + } - /* Configure each PIN digit animation settings */ - const PINAnimationConfig pin_animation_cfg[] = - { - {SLIDE_RIGHT, 8 * PIN_SLIDE_DELAY}, // 1 - {SLIDE_UP, 7 * PIN_SLIDE_DELAY}, // 2 - {SLIDE_DOWN, 6 * PIN_SLIDE_DELAY}, // 3 - {SLIDE_LEFT, 5 * PIN_SLIDE_DELAY}, // 4 - {SLIDE_UP, 4 * PIN_SLIDE_DELAY}, // 5 - {SLIDE_RIGHT, 3 * PIN_SLIDE_DELAY}, // 6 - {SLIDE_UP, 0 * PIN_SLIDE_DELAY}, // 7 - {SLIDE_RIGHT, 1 * PIN_SLIDE_DELAY}, // 8 - {SLIDE_DOWN, 2 * PIN_SLIDE_DELAY} // 9 - }; - - /* Draw each pin digit individually base on animation config on matrix position */ - for(uint8_t row = 0; row < 3; row++) - { - for(uint8_t col = 0; col < 3; col++) - { - - uint8_t cur_pos = col + (2 - row) * 3; - const PINAnimationConfig *cur_pos_cfg = &pin_animation_cfg[cur_pos]; - uint32_t cur_pos_elapsed = elapsed - cur_pos_cfg->elapsed_start_ms; - - /* Skip position is enough time has not passed */ - if(cur_pos_cfg->elapsed_start_ms > elapsed) - { - continue; - } - - /* Determine color */ - sp.color = PIN_MATRIX_FOREGROUND; - - for(uint8_t color_index = 0; - color_index < sizeof(color_stepping) / sizeof(color_stepping[0]); color_index++) - { - if(cur_pos_elapsed < (color_index * PIN_MATRIX_ANIMATION_FREQUENCY_MS)) - { - sp.color = color_stepping[color_index]; - break; - } - } - - uint8_t pad = 7; - - /* Adjust pad */ - if(pin[cur_pos] == '1') - { - pad++; - } - - sp.y = 8 + row * 19; - sp.x = (PIN_LEFT_MARGIN - 2) + pad + col * 19; - - uint8_t adj_pos = cur_pos_elapsed / 40; - - if(adj_pos <= 5) - { - adj_pos = 5 - adj_pos; - - switch(cur_pos_cfg->direction) - { - case SLIDE_DOWN: - sp.y -= adj_pos; - break; - - case SLIDE_LEFT: - sp.x += adj_pos; - break; - - case SLIDE_UP: - sp.y += adj_pos; - break; - - case SLIDE_RIGHT: - default: - sp.x -= adj_pos; - break; - } - } - - draw_char(canvas, pin_font, pin[cur_pos], &sp); + sp.y = 8 + row * 19; + sp.x = (PIN_LEFT_MARGIN - 2) + pad + col * 19; + + uint8_t adj_pos = cur_pos_elapsed / 40; + + if (adj_pos <= 5) { + adj_pos = 5 - adj_pos; + + switch (cur_pos_cfg->direction) { + case SLIDE_DOWN: + sp.y -= adj_pos; + break; + + case SLIDE_LEFT: + sp.x += adj_pos; + break; + + case SLIDE_UP: + sp.y += adj_pos; + break; + + case SLIDE_RIGHT: + default: + sp.x -= adj_pos; + break; } - } + } - /* Mask horizontally */ - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN -3, 2, PIN_MATRIX_GRID_SIZE * 3 + 8, - MATRIX_MASK_MARGIN); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN -3, 5 + PIN_MATRIX_GRID_SIZE, - PIN_MATRIX_GRID_SIZE * 3 + 8, 1); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN -3, 6 + PIN_MATRIX_GRID_SIZE * 2, - PIN_MATRIX_GRID_SIZE * 3 + 8, 1); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, 7 + PIN_MATRIX_GRID_SIZE * 3, - PIN_MATRIX_GRID_SIZE * 3 + 8, MATRIX_MASK_MARGIN); - - /* Mask vertically */ - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, 2, MATRIX_MASK_MARGIN, 18 * 3 + 8); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN + PIN_MATRIX_GRID_SIZE, 2, 1, - PIN_MATRIX_GRID_SIZE * 3 + 8); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN + 1 + PIN_MATRIX_GRID_SIZE * 2, 2, 1, - PIN_MATRIX_GRID_SIZE * 3 + 8); - draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN + 2 + PIN_MATRIX_GRID_SIZE * 3, 2, - MATRIX_MASK_MARGIN, PIN_MATRIX_GRID_SIZE * 3 + 8); + draw_char(canvas, pin_font, pin[cur_pos], &sp); + } + } + + /* Mask horizontally */ + draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, 2, + PIN_MATRIX_GRID_SIZE * 3 + 8, MATRIX_MASK_MARGIN); + draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, + 5 + PIN_MATRIX_GRID_SIZE, PIN_MATRIX_GRID_SIZE * 3 + 8, 1); + draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, + 6 + PIN_MATRIX_GRID_SIZE * 2, PIN_MATRIX_GRID_SIZE * 3 + 8, + 1); + draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, + 7 + PIN_MATRIX_GRID_SIZE * 3, PIN_MATRIX_GRID_SIZE * 3 + 8, + MATRIX_MASK_MARGIN); + + /* Mask vertically */ + draw_box_simple(canvas, MATRIX_MASK_COLOR, PIN_LEFT_MARGIN - 3, 2, + MATRIX_MASK_MARGIN, 18 * 3 + 8); + draw_box_simple(canvas, MATRIX_MASK_COLOR, + PIN_LEFT_MARGIN + PIN_MATRIX_GRID_SIZE, 2, 1, + PIN_MATRIX_GRID_SIZE * 3 + 8); + draw_box_simple(canvas, MATRIX_MASK_COLOR, + PIN_LEFT_MARGIN + 1 + PIN_MATRIX_GRID_SIZE * 2, 2, 1, + PIN_MATRIX_GRID_SIZE * 3 + 8); + draw_box_simple(canvas, MATRIX_MASK_COLOR, + PIN_LEFT_MARGIN + 2 + PIN_MATRIX_GRID_SIZE * 3, 2, + MATRIX_MASK_MARGIN, PIN_MATRIX_GRID_SIZE * 3 + 8); } /* @@ -190,133 +189,117 @@ static void layout_animate_pin(void *data, uint32_t duration, uint32_t elapsed) * OUTPUT * none */ -static void layout_animate_cipher(void *data, uint32_t duration, uint32_t elapsed) -{ - (void)duration; - Canvas *canvas = layout_get_canvas(); - int row, letter, x_padding, cur_pos_elapsed, adj_pos, adj_x, adj_y, cur_index; - char *cipher = (char *)data; - char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; - char *current_letter = alphabet; - - DrawableParams sp; - const Font *title_font = get_title_font(); - const Font *cipher_font = get_body_font(); - - /* Clear area behind cipher */ - draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X, 0, - KEEPKEY_DISPLAY_WIDTH - CIPHER_START_X, KEEPKEY_DISPLAY_HEIGHT); +static void layout_animate_cipher(void *data, uint32_t duration, + uint32_t elapsed) { + (void)duration; + Canvas *canvas = layout_get_canvas(); + int row, letter, x_padding, cur_pos_elapsed, adj_pos, adj_x, adj_y, cur_index; + char *cipher = (char *)data; + char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; + char *current_letter = alphabet; + + DrawableParams sp; + const Font *title_font = get_title_font(); + const Font *cipher_font = get_body_font(); + + /* Clear area behind cipher */ + draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X, 0, + KEEPKEY_DISPLAY_WIDTH - CIPHER_START_X, + KEEPKEY_DISPLAY_HEIGHT); + + /* Draw grid */ + sp.y = CIPHER_START_Y; + sp.x = CIPHER_START_X; + + for (row = 0; row < CIPHER_ROWS; row++) { + for (letter = 0; letter < CIPHER_LETTER_BY_ROW; letter++) { + cur_index = (row * CIPHER_LETTER_BY_ROW) + letter; + cur_pos_elapsed = elapsed - cur_index * CIPHER_ANIMATION_FREQUENCY_MS; + sp.x = + CIPHER_START_X + (letter * (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING)); + x_padding = 0; + + /* Draw grid */ + draw_box_simple(canvas, CIPHER_STEP_1, sp.x - 4, sp.y + CIPHER_GRID_SIZE, + CIPHER_GRID_SIZE, CIPHER_GRID_SIZE); + + x_padding = 0; + + if (*current_letter == 'i' || *current_letter == 'l') { + x_padding = 2; + } else if (*current_letter == 'm' || *current_letter == 'w') { + x_padding = -1; + } + + /* Draw map */ + draw_char_simple(canvas, title_font, *current_letter++, + CIPHER_MAP_FONT_COLOR, sp.x + x_padding, sp.y); + + x_padding = 0; + + if (*cipher == 'i' || *cipher == 'l') { + x_padding = 2; + } else if (*cipher == 'k' || *cipher == 'j' || *cipher == 'r' || + *cipher == 'f') { + x_padding = 1; + } else if (*cipher == 'm' || *cipher == 'w') { + x_padding = -1; + } + + /* Draw cipher */ + if (cur_pos_elapsed > 0) { + adj_pos = cur_pos_elapsed / CIPHER_ANIMATION_FREQUENCY_MS; + + adj_x = 0; + adj_y = 0; + + if (adj_pos < 5) { + if (cur_index % 4 == 0) { + adj_y = -(5 - adj_pos); + } else if (cur_index % 4 == 1) { + adj_x = 5 - adj_pos; + } else if (cur_index % 4 == 2) { + adj_y = 5 - adj_pos; + } else { + adj_x = -(5 - adj_pos); + } + } - /* Draw grid */ - sp.y = CIPHER_START_Y; - sp.x = CIPHER_START_X; + draw_char_simple( + canvas, cipher_font, *cipher, CIPHER_FONT_COLOR, + sp.x + x_padding + adj_x, + sp.y + (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING) + adj_y); + } - for(row = 0; row < CIPHER_ROWS; row++) - { - for(letter = 0; letter < CIPHER_LETTER_BY_ROW; letter++) - { - cur_index = (row * CIPHER_LETTER_BY_ROW) + letter; - cur_pos_elapsed = elapsed - cur_index * CIPHER_ANIMATION_FREQUENCY_MS; - sp.x = CIPHER_START_X + (letter * (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING)); - x_padding = 0; - - /* Draw grid */ - draw_box_simple(canvas, CIPHER_STEP_1, sp.x - 4, sp.y + CIPHER_GRID_SIZE, - CIPHER_GRID_SIZE, CIPHER_GRID_SIZE); - - x_padding = 0; - - if(*current_letter == 'i' || *current_letter == 'l') - { - x_padding = 2; - } - else if(*current_letter == 'm' || *current_letter == 'w') - { - x_padding = -1; - } - - /* Draw map */ - draw_char_simple(canvas, title_font, *current_letter++, CIPHER_MAP_FONT_COLOR, - sp.x + x_padding, sp.y); - - x_padding = 0; - - if(*cipher == 'i' || *cipher == 'l') - { - x_padding = 2; - } - else if(*cipher == 'k' || *cipher == 'j' || - *cipher == 'r' || *cipher == 'f') - { - x_padding = 1; - } - else if(*cipher == 'm' || *cipher == 'w') - { - x_padding = -1; - } - - /* Draw cipher */ - if(cur_pos_elapsed > 0) - { - adj_pos = cur_pos_elapsed / CIPHER_ANIMATION_FREQUENCY_MS; - - adj_x = 0; - adj_y = 0; - - if(adj_pos < 5) - { - if(cur_index % 4 == 0) - { - adj_y = -(5 - adj_pos); - } - else if(cur_index % 4 == 1) - { - adj_x = 5 - adj_pos; - } - else if(cur_index % 4 == 2) - { - adj_y = 5 - adj_pos; - } - else - { - adj_x = -(5 - adj_pos); - } - } - - draw_char_simple(canvas, cipher_font, *cipher, CIPHER_FONT_COLOR, - sp.x + x_padding + adj_x, sp.y + (CIPHER_GRID_SIZE + CIPHER_GRID_SPACING) + adj_y); - } - - /* Draw grid mask between boxes */ - draw_box_simple(canvas, CIPHER_MASK_COLOR, sp.x - 5, sp.y + CIPHER_GRID_SIZE, 1, - CIPHER_GRID_SIZE); - - cipher++; - } + /* Draw grid mask between boxes */ + draw_box_simple(canvas, CIPHER_MASK_COLOR, sp.x - 5, + sp.y + CIPHER_GRID_SIZE, 1, CIPHER_GRID_SIZE); - sp.x = CIPHER_START_X; - sp.y += 31; + cipher++; } - /* Draw mask */ - draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 14, - CIPHER_HORIZONTAL_MASK_WIDTH, - CIPHER_HORIZONTAL_MASK_HEIGHT_2); - draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 45, - CIPHER_HORIZONTAL_MASK_WIDTH, - CIPHER_HORIZONTAL_MASK_HEIGHT_2); - draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 29, - CIPHER_HORIZONTAL_MASK_WIDTH, - CIPHER_HORIZONTAL_MASK_HEIGHT_3); - draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 59, - CIPHER_HORIZONTAL_MASK_WIDTH, - CIPHER_HORIZONTAL_MASK_HEIGHT_4); - draw_box_simple(canvas, CIPHER_MASK_COLOR, - KEEPKEY_DISPLAY_WIDTH - CIPHER_HORIZONTAL_MASK_WIDTH_3, 0, - CIPHER_HORIZONTAL_MASK_WIDTH_3, KEEPKEY_DISPLAY_HEIGHT); + sp.x = CIPHER_START_X; + sp.y += 31; + } + + /* Draw mask */ + draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 14, + CIPHER_HORIZONTAL_MASK_WIDTH, + CIPHER_HORIZONTAL_MASK_HEIGHT_2); + draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 45, + CIPHER_HORIZONTAL_MASK_WIDTH, + CIPHER_HORIZONTAL_MASK_HEIGHT_2); + draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 29, + CIPHER_HORIZONTAL_MASK_WIDTH, + CIPHER_HORIZONTAL_MASK_HEIGHT_3); + draw_box_simple(canvas, CIPHER_MASK_COLOR, CIPHER_START_X - 4, 59, + CIPHER_HORIZONTAL_MASK_WIDTH, + CIPHER_HORIZONTAL_MASK_HEIGHT_4); + draw_box_simple(canvas, CIPHER_MASK_COLOR, + KEEPKEY_DISPLAY_WIDTH - CIPHER_HORIZONTAL_MASK_WIDTH_3, 0, + CIPHER_HORIZONTAL_MASK_WIDTH_3, KEEPKEY_DISPLAY_HEIGHT); } - /* * layout_screen_test() - Display screen test * @@ -325,9 +308,9 @@ static void layout_animate_cipher(void *data, uint32_t duration, uint32_t elapse * OUTPUT * none */ -void layout_screen_test(void) -{ - draw_box_simple(layout_get_canvas(), TEST_COLOR, TEST_X, TEST_Y, TEST_WIDTH, TEST_HEIGHT); +void layout_screen_test(void) { + draw_box_simple(layout_get_canvas(), TEST_COLOR, TEST_X, TEST_Y, TEST_WIDTH, + TEST_HEIGHT); } /* @@ -338,14 +321,11 @@ void layout_screen_test(void) * OUTPUT * none */ -void layout_screensaver(void) -{ - layout_clear(); +void layout_screensaver(void) { + layout_clear(); - layout_add_animation( - &layout_animate_images, - (void *)variant_getScreensaver(), - 0); + layout_add_animation(&layout_animate_images, (void *)variant_getScreensaver(), + 0); } /* @@ -358,33 +338,33 @@ void layout_screensaver(void) * none */ void layout_notification_no_title(const char *title, const char *body, - NotificationType type, bool bold) -{ - (void)title; - call_leaving_handler(); - layout_clear(); + NotificationType type, bool bold) { + (void)title; + call_leaving_handler(); + layout_clear(); - Canvas *canvas = layout_get_canvas(); - DrawableParams sp; - const Font *font = get_title_font(); + Canvas *canvas = layout_get_canvas(); + DrawableParams sp; + const Font *font = get_title_font(); - if (!bold) { - font = get_body_font(); - } + if (!bold) { + font = get_body_font(); + } - /* Determine vertical alignment and body width */ - sp.y = TOP_MARGIN_FOR_ONE_LINE; + /* Determine vertical alignment and body width */ + sp.y = TOP_MARGIN_FOR_ONE_LINE; - /* Draw */ - sp.x = LEFT_MARGIN; - sp.color = TITLE_COLOR; - draw_string(canvas, font, body, &sp, NO_TITLE_WIDTH, font_height(font)); + /* Draw */ + sp.x = LEFT_MARGIN; + sp.color = TITLE_COLOR; + draw_string(canvas, font, body, &sp, NO_TITLE_WIDTH, font_height(font)); - layout_notification_icon(type, &sp); + layout_notification_icon(type, &sp); } /* - * layout_notification_no_title_bold() - Display notification without title in bold + * layout_notification_no_title_bold() - Display notification without title in + * bold * * INPUT * - title @@ -393,13 +373,13 @@ void layout_notification_no_title(const char *title, const char *body, * none */ void layout_notification_no_title_bold(const char *title, const char *body, - NotificationType type) -{ - layout_notification_no_title(title, body, type, true); + NotificationType type) { + layout_notification_no_title(title, body, type, true); } /* - * layout_notification_no_title_no_bold() - Display notification without title without bold + * layout_notification_no_title_no_bold() - Display notification without title + * without bold * * INPUT * - title @@ -408,13 +388,13 @@ void layout_notification_no_title_bold(const char *title, const char *body, * none */ void layout_notification_no_title_no_bold(const char *title, const char *body, - NotificationType type) -{ - layout_notification_no_title(title, body, type, false); + NotificationType type) { + layout_notification_no_title(title, body, type, false); } /* - * layout_xpub_notification() - Display extended public address (xpub) notification + * layout_xpub_notification() - Display extended public address (xpub) + * notification * * INPUT * - xpub: address to display both as string @@ -423,38 +403,37 @@ void layout_notification_no_title_no_bold(const char *title, const char *body, * none */ void layout_xpub_notification(const char *desc, const char *xpub, - NotificationType type) -{ - (void)desc; - call_leaving_handler(); - layout_clear(); + NotificationType type) { + (void)desc; + call_leaving_handler(); + layout_clear(); - Canvas *canvas = layout_get_canvas(); - DrawableParams sp; - const Font *xpub_font = get_body_font(); - - if (strcmp(desc, "") != 0) - { - const Font *title_font = get_title_font(); - sp.y = TOP_MARGIN_FOR_THREE_LINES; - sp.x = LEFT_MARGIN; - sp.color = BODY_COLOR; - draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, - font_height(title_font) + BODY_FONT_LINE_PADDING); - } + Canvas *canvas = layout_get_canvas(); + DrawableParams sp; + const Font *xpub_font = get_body_font(); - /* Determine vertical alignment and body width */ - sp.y = TOP_MARGIN_FOR_THREE_LINES + ADDRESS_XPUB_TOP_MARGIN; + if (strcmp(desc, "") != 0) { + const Font *title_font = get_title_font(); + sp.y = TOP_MARGIN_FOR_THREE_LINES; sp.x = LEFT_MARGIN; sp.color = BODY_COLOR; - draw_string(canvas, xpub_font, xpub, &sp, TRANSACTION_WIDTH - 25, - font_height(xpub_font) + BODY_FONT_LINE_PADDING); - - layout_notification_icon(type, &sp); + draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, + font_height(title_font) + BODY_FONT_LINE_PADDING); + } + + /* Determine vertical alignment and body width */ + sp.y = TOP_MARGIN_FOR_THREE_LINES + ADDRESS_XPUB_TOP_MARGIN; + sp.x = LEFT_MARGIN; + sp.color = BODY_COLOR; + draw_string(canvas, xpub_font, xpub, &sp, TRANSACTION_WIDTH - 25, + font_height(xpub_font) + BODY_FONT_LINE_PADDING); + + layout_notification_icon(type, &sp); } /* - * layout_ethereum_address_notification() - Display ethereum address notification + * layout_ethereum_address_notification() - Display ethereum address + * notification * * INPUT * - desc: description of address being shown (normal or multisig) @@ -464,34 +443,34 @@ void layout_xpub_notification(const char *desc, const char *xpub, * none */ void layout_ethereum_address_notification(const char *desc, const char *address, - NotificationType type) -{ - DrawableParams sp; - const Font *address_font = get_body_font();; - Canvas *canvas = layout_get_canvas(); - - call_leaving_handler(); - layout_clear(); + NotificationType type) { + DrawableParams sp; + const Font *address_font = get_body_font(); + ; + Canvas *canvas = layout_get_canvas(); - if (strcmp(desc, "") != 0) { - const Font *title_font = get_title_font(); - sp.y = TOP_MARGIN_FOR_TWO_LINES; - sp.x = LEFT_MARGIN + 65; - sp.color = BODY_COLOR; - draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, - font_height(title_font) + BODY_FONT_LINE_PADDING); - } + call_leaving_handler(); + layout_clear(); - /* Body */ - sp.y = TOP_MARGIN_FOR_TWO_LINES + TOP_MARGIN + TOP_MARGIN; + if (strcmp(desc, "") != 0) { + const Font *title_font = get_title_font(); + sp.y = TOP_MARGIN_FOR_TWO_LINES; sp.x = LEFT_MARGIN + 65; sp.color = BODY_COLOR; + draw_string(canvas, title_font, desc, &sp, TRANSACTION_WIDTH - 2, + font_height(title_font) + BODY_FONT_LINE_PADDING); + } - draw_string(canvas, address_font, address, &sp, 140, - font_height(address_font) + BODY_FONT_LINE_PADDING); + /* Body */ + sp.y = TOP_MARGIN_FOR_TWO_LINES + TOP_MARGIN + TOP_MARGIN; + sp.x = LEFT_MARGIN + 65; + sp.color = BODY_COLOR; - layout_address(address, QR_LARGE); - layout_notification_icon(type, &sp); + draw_string(canvas, address_font, address, &sp, 140, + font_height(address_font) + BODY_FONT_LINE_PADDING); + + layout_address(address, QR_LARGE); + layout_notification_icon(type, &sp); } /* @@ -505,37 +484,35 @@ void layout_ethereum_address_notification(const char *desc, const char *address, * none */ void layout_nano_address_notification(const char *desc, const char *address, - NotificationType type) -{ - call_leaving_handler(); - layout_clear(); - - Canvas *canvas = layout_get_canvas(); - DrawableParams sp; - const Font *font = NULL; - - /* Title */ - if(strcmp(desc, "") != 0) - { - font = get_title_font(); - sp.y = TOP_MARGIN; - sp.x = LEFT_MARGIN + 65; - sp.color = BODY_COLOR; - draw_string(canvas, font, desc, &sp, 140, - font_height(font) + BODY_FONT_LINE_PADDING); - } - - /* Body */ - font = get_body_font(); - sp.y = TOP_MARGIN_FOR_TWO_LINES + TOP_MARGIN; + NotificationType type) { + call_leaving_handler(); + layout_clear(); + + Canvas *canvas = layout_get_canvas(); + DrawableParams sp; + const Font *font = NULL; + + /* Title */ + if (strcmp(desc, "") != 0) { + font = get_title_font(); + sp.y = TOP_MARGIN; sp.x = LEFT_MARGIN + 65; sp.color = BODY_COLOR; - - draw_string(canvas, font, address, &sp, 140, + draw_string(canvas, font, desc, &sp, 140, font_height(font) + BODY_FONT_LINE_PADDING); + } + + /* Body */ + font = get_body_font(); + sp.y = TOP_MARGIN_FOR_TWO_LINES + TOP_MARGIN; + sp.x = LEFT_MARGIN + 65; + sp.color = BODY_COLOR; - layout_address(address, QR_LARGE); - layout_notification_icon(type, &sp); + draw_string(canvas, font, address, &sp, 140, + font_height(font) + BODY_FONT_LINE_PADDING); + + layout_address(address, QR_LARGE); + layout_notification_icon(type, &sp); } /* @@ -549,50 +526,49 @@ void layout_nano_address_notification(const char *desc, const char *address, * none */ void layout_address_notification(const char *desc, const char *address, - NotificationType type) -{ - call_leaving_handler(); - layout_clear(); - - Canvas *canvas = layout_get_canvas(); - DrawableParams sp; - const Font *address_font = get_title_font(); - - /* Unbold fonts if address becomes too long */ - if(calc_str_width(address_font, address) > TRANSACTION_WIDTH) - { - address_font = get_body_font(); + NotificationType type) { + call_leaving_handler(); + layout_clear(); + + Canvas *canvas = layout_get_canvas(); + DrawableParams sp; + const Font *address_font = get_title_font(); + + /* Unbold fonts if address becomes too long */ + if (calc_str_width(address_font, address) > TRANSACTION_WIDTH) { + address_font = get_body_font(); + } + + /* Determine vertical alignment and body width */ + sp.y = TOP_MARGIN_FOR_ONE_LINE; + + /* Draw address */ + sp.y += font_height(address_font) + ADDRESS_TOP_MARGIN; + sp.x = LEFT_MARGIN; + sp.color = BODY_COLOR; + draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH, + font_height(address_font) + BODY_FONT_LINE_PADDING); + + /* Draw description */ + if (strcmp(desc, "") != 0) { + const uint32_t title_line_count = + calc_str_line(address_font, desc, BODY_WIDTH); + + sp.y = TOP_MARGIN; + if (title_line_count == ONE_LINE) { + sp.y = TOP_MARGIN_FOR_ONE_LINE; + } else if (title_line_count == TWO_LINES) { + sp.y = TOP_MARGIN_FOR_TWO_LINES; } - /* Determine vertical alignment and body width */ - sp.y = TOP_MARGIN_FOR_ONE_LINE; - - /* Draw address */ - sp.y += font_height(address_font) + ADDRESS_TOP_MARGIN; - sp.x = LEFT_MARGIN; + sp.x = MULTISIG_LEFT_MARGIN; sp.color = BODY_COLOR; - draw_string(canvas, address_font, address, &sp, TRANSACTION_WIDTH, + draw_string(canvas, address_font, desc, &sp, TRANSACTION_WIDTH - 2, font_height(address_font) + BODY_FONT_LINE_PADDING); + } - /* Draw description */ - if (strcmp(desc, "") != 0) { - const uint32_t title_line_count = calc_str_line(address_font, desc, BODY_WIDTH); - - sp.y = TOP_MARGIN; - if (title_line_count == ONE_LINE) { - sp.y = TOP_MARGIN_FOR_ONE_LINE; - } else if(title_line_count == TWO_LINES) { - sp.y = TOP_MARGIN_FOR_TWO_LINES; - } - - sp.x = MULTISIG_LEFT_MARGIN; - sp.color = BODY_COLOR; - draw_string(canvas, address_font, desc, &sp, TRANSACTION_WIDTH - 2, - font_height(address_font) + BODY_FONT_LINE_PADDING); - } - - layout_address(address, QR_SMALL); - layout_notification_icon(type, &sp); + layout_address(address, QR_SMALL); + layout_notification_icon(type, &sp); } /* @@ -612,10 +588,12 @@ void layout_pin(const char *str, char pin[]) call_leaving_handler(); layout_clear(); + display_constant_power(true); + /* Draw prompt */ const Font *font = get_body_font(); - sp.y = 29; - sp.x = (140 - calc_str_width(font, str)) / 2; + sp.y = 24; + sp.x = 128 + 10; sp.color = BODY_COLOR; draw_string(canvas, font, str, &sp, TITLE_WIDTH, font_height(font)); display_refresh(); @@ -628,36 +606,38 @@ void layout_pin(const char *str, char pin[]) * layout_cipher() - Draws recover cipher * * INPUT - * - current_word: current word that is being typed in at this point in recovery + * - current_word: current word that is being typed in at this point in + * recovery * - cipher: randomized cipher * OUTPUT * none */ -void layout_cipher(const char *current_word, const char *cipher) -{ - DrawableParams sp; - const Font *title_font = get_body_font(); - Canvas *canvas = layout_get_canvas(); - - call_leaving_handler(); - layout_clear(); - - /* Draw prompt */ - sp.y = 11; - sp.x = 4; - sp.color = BODY_COLOR; - draw_string(canvas, title_font, "Recovery Cipher:", &sp, 58, font_height(title_font) + 3); - - /* Draw current word */ - sp.y = 46; - sp.x = 4; - sp.color = BODY_COLOR; - draw_string(canvas, title_font, current_word, &sp, 68, font_height(title_font)); - display_refresh(); - - /* Animate cipher */ - layout_add_animation(&layout_animate_cipher, (void *)cipher, - CIPHER_ANIMATION_FREQUENCY_MS * 30); +void layout_cipher(const char *current_word, const char *cipher) { + DrawableParams sp; + const Font *title_font = get_body_font(); + Canvas *canvas = layout_get_canvas(); + + call_leaving_handler(); + layout_clear(); + + /* Draw prompt */ + sp.y = 11; + sp.x = 4; + sp.color = BODY_COLOR; + draw_string(canvas, title_font, "Recovery Cipher:", &sp, 58, + font_height(title_font) + 3); + + /* Draw current word */ + sp.y = 46; + sp.x = 4; + sp.color = BODY_COLOR; + draw_string(canvas, title_font, current_word, &sp, 68, + font_height(title_font)); + display_refresh(); + + /* Animate cipher */ + layout_add_animation(&layout_animate_cipher, (void *)cipher, + CIPHER_ANIMATION_FREQUENCY_MS * 30); } /* @@ -668,65 +648,58 @@ void layout_cipher(const char *current_word, const char *cipher) * OUTPUT * none */ -void layout_address(const char *address, QRSize qr_size) -{ - Canvas *canvas = layout_get_canvas(); - - uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; - uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; - - int y_pos = qr_size == QR_SMALL - ? QR_DISPLAY_Y - : QR_DISPLAY_Y - 4; - - int side = 0; - if (qrcodegen_encodeText(address, tempdata, codedata, qrcodegen_Ecc_LOW, - qr_size == QR_SMALL - ? qrcodegen_VERSION_MIN - : QR_LARGE_VERSION, - QR_MAX_VERSION, - qrcodegen_Mask_AUTO, true)) { - side = qrcodegen_getSize(codedata); - } - - // Limit QR to version 1-9 - if (side < 0 || 53 < side) - return; - - // Draw QR background - draw_box_simple(canvas, 0xFF, QR_DISPLAY_X, y_pos, - (side + 2) * QR_DISPLAY_SCALE, (side + 2) * QR_DISPLAY_SCALE); - - // Fill in QR - for (int i = 0; i < side; i++) { - for (int j = 0; j < side; j++) { - if (qrcodegen_getModule(codedata, i, j)) { - draw_box_simple(canvas, 0x00, - QR_DISPLAY_SCALE + (i + QR_DISPLAY_X) * QR_DISPLAY_SCALE, - QR_DISPLAY_SCALE + (j + y_pos) * QR_DISPLAY_SCALE, - QR_DISPLAY_SCALE, QR_DISPLAY_SCALE); - } - } +void layout_address(const char *address, QRSize qr_size) { + Canvas *canvas = layout_get_canvas(); + + uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + + int y_pos = qr_size == QR_SMALL ? QR_DISPLAY_Y : QR_DISPLAY_Y - 4; + + int side = 0; + if (qrcodegen_encodeText( + address, tempdata, codedata, qrcodegen_Ecc_LOW, + qr_size == QR_SMALL ? qrcodegen_VERSION_MIN : QR_LARGE_VERSION, + QR_MAX_VERSION, qrcodegen_Mask_AUTO, true)) { + side = qrcodegen_getSize(codedata); + } + + // Limit QR to version 1-9 + if (side < 0 || 53 < side) return; + + // Draw QR background + draw_box_simple(canvas, 0xFF, QR_DISPLAY_X, y_pos, + (side + 2) * QR_DISPLAY_SCALE, (side + 2) * QR_DISPLAY_SCALE); + + // Fill in QR + for (int i = 0; i < side; i++) { + for (int j = 0; j < side; j++) { + if (qrcodegen_getModule(codedata, i, j)) { + draw_box_simple( + canvas, 0x00, + QR_DISPLAY_SCALE + (i + QR_DISPLAY_X) * QR_DISPLAY_SCALE, + QR_DISPLAY_SCALE + (j + y_pos) * QR_DISPLAY_SCALE, QR_DISPLAY_SCALE, + QR_DISPLAY_SCALE); + } } + } } -void layoutU2FDialog(bool request, const char *title, const char *body, ...) -{ - char strbuf[BODY_CHAR_MAX]; +void layoutU2FDialog(bool request, const char *title, const char *body, ...) { + char strbuf[BODY_CHAR_MAX]; - va_list vl; - va_start(vl, body); - vsnprintf(strbuf, BODY_CHAR_MAX, body, vl); - va_end(vl); + va_list vl; + va_start(vl, body); + vsnprintf(strbuf, BODY_CHAR_MAX, body, vl); + va_end(vl); - layout_standard_notification(title, strbuf, - request - ? NOTIFICATION_REQUEST_NO_ANIMATION - : NOTIFICATION_CONFIRM_ANIMATION); - display_refresh(); + layout_standard_notification(title, strbuf, + request ? NOTIFICATION_REQUEST_NO_ANIMATION + : NOTIFICATION_CONFIRM_ANIMATION); + display_refresh(); - while (!request && is_animating()) { - animate(); - display_refresh(); - } + while (!request && is_animating()) { + animate(); + display_refresh(); + } } diff --git a/lib/firmware/binance.c b/lib/firmware/binance.c index bb382833d..410de1a69 100644 --- a/lib/firmware/binance.c +++ b/lib/firmware/binance.c @@ -14,136 +14,126 @@ static bool initialized; static uint32_t msgs_remaining; static BinanceSignTx msg; -const BinanceSignTx *binance_getBinanceSignTx(void) -{ - return &msg; -} +const BinanceSignTx *binance_getBinanceSignTx(void) { return &msg; } -bool binance_signTxInit(const HDNode *_node, const BinanceSignTx *_msg) -{ - initialized = true; - msgs_remaining = _msg->msg_count; - has_message = false; +bool binance_signTxInit(const HDNode *_node, const BinanceSignTx *_msg) { + initialized = true; + msgs_remaining = _msg->msg_count; + has_message = false; - memzero(&node, sizeof(node)); - memcpy(&node, _node, sizeof(node)); - memcpy(&msg, _msg, sizeof(msg)); + memzero(&node, sizeof(node)); + memcpy(&node, _node, sizeof(node)); + memcpy(&msg, _msg, sizeof(msg)); - bool success = true; - char buffer[64 + 1]; + bool success = true; + char buffer[64 + 1]; - sha256_Init(&ctx); + sha256_Init(&ctx); - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "{\"account_number\":\"%" PRIu64 "\"", msg.account_number); + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"account_number\":\"%" PRIu64 "\"", + msg.account_number); - const char *const chainid_prefix = ",\"chain_id\":\""; - sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix)); - tendermint_sha256UpdateEscaped(&ctx, msg.chain_id, strlen(msg.chain_id)); + const char *const chainid_prefix = ",\"chain_id\":\""; + sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix)); + tendermint_sha256UpdateEscaped(&ctx, msg.chain_id, strlen(msg.chain_id)); - const char *const data_memo = "\",\"data\":null,\"memo\":\""; - sha256_Update(&ctx, (uint8_t *)data_memo, strlen(data_memo)); - if (msg.has_memo) { - tendermint_sha256UpdateEscaped(&ctx, msg.memo, strlen(msg.memo)); - } + const char *const data_memo = "\",\"data\":null,\"memo\":\""; + sha256_Update(&ctx, (uint8_t *)data_memo, strlen(data_memo)); + if (msg.has_memo) { + tendermint_sha256UpdateEscaped(&ctx, msg.memo, strlen(msg.memo)); + } - sha256_Update(&ctx, (const uint8_t *)"\",\"msgs\":[", 10); - return success; + sha256_Update(&ctx, (const uint8_t *)"\",\"msgs\":[", 10); + return success; } -bool binance_serializeCoin(const BinanceCoin *coin) -{ - bool success = true; - char buffer[64 + 1]; +bool binance_serializeCoin(const BinanceCoin *coin) { + bool success = true; + char buffer[64 + 1]; - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "{\"amount\":%" PRIu64 ",\"denom\":\"%s\"}", - coin->amount, coin->denom); + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"amount\":%" PRIu64 ",\"denom\":\"%s\"}", + coin->amount, coin->denom); - return success; + return success; } -bool binance_serializeInputOutput(const BinanceInputOutput *io) -{ - size_t decoded_len; - char hrp[45]; - uint8_t decoded[38]; - if (!bech32_decode(hrp, decoded, &decoded_len, io->address)) { - return false; - } - - sha256_Update(&ctx, (const uint8_t*)"{\"address\":\"", 12); - sha256_Update(&ctx, (const uint8_t*)io->address, strlen(io->address)); - sha256_Update(&ctx, (const uint8_t*)"\",\"coins\":[", 11); - - bool success = true; - for (int i = 0; i < io->coins_count; i++) { - success &= binance_serializeCoin(&io->coins[i]); - if (i + 1 != io->coins_count) - sha256_Update(&ctx, (const uint8_t*)",", 1); - } - - sha256_Update(&ctx, (const uint8_t*)"]}", 2); - - return success; +bool binance_serializeInputOutput(const BinanceInputOutput *io) { + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + if (!bech32_decode(hrp, decoded, &decoded_len, io->address)) { + return false; + } + + sha256_Update(&ctx, (const uint8_t *)"{\"address\":\"", 12); + sha256_Update(&ctx, (const uint8_t *)io->address, strlen(io->address)); + sha256_Update(&ctx, (const uint8_t *)"\",\"coins\":[", 11); + + bool success = true; + for (int i = 0; i < io->coins_count; i++) { + success &= binance_serializeCoin(&io->coins[i]); + if (i + 1 != io->coins_count) sha256_Update(&ctx, (const uint8_t *)",", 1); + } + + sha256_Update(&ctx, (const uint8_t *)"]}", 2); + + return success; } -bool binance_signTxUpdateTransfer(const BinanceTransferMsg *_msg) -{ - bool success = true; +bool binance_signTxUpdateTransfer(const BinanceTransferMsg *_msg) { + bool success = true; - sha256_Update(&ctx, (const uint8_t*)"{\"inputs\":[", 11); + sha256_Update(&ctx, (const uint8_t *)"{\"inputs\":[", 11); - for (int i = 0; i < _msg->inputs_count; i++) { - success &= binance_serializeInputOutput(&_msg->inputs[i]); - if (i + 1 != _msg->inputs_count) - sha256_Update(&ctx, (const uint8_t*)",", 1); - } + for (int i = 0; i < _msg->inputs_count; i++) { + success &= binance_serializeInputOutput(&_msg->inputs[i]); + if (i + 1 != _msg->inputs_count) + sha256_Update(&ctx, (const uint8_t *)",", 1); + } - sha256_Update(&ctx, (const uint8_t*)"],\"outputs\":[", 13); + sha256_Update(&ctx, (const uint8_t *)"],\"outputs\":[", 13); - for (int i = 0; i < _msg->outputs_count; i++) { - success &= binance_serializeInputOutput(&_msg->outputs[i]); - if (i + 1 != _msg->outputs_count) - sha256_Update(&ctx, (const uint8_t*)",", 1); - } + for (int i = 0; i < _msg->outputs_count; i++) { + success &= binance_serializeInputOutput(&_msg->outputs[i]); + if (i + 1 != _msg->outputs_count) + sha256_Update(&ctx, (const uint8_t *)",", 1); + } - sha256_Update(&ctx, (const uint8_t*)"]}", 2); + sha256_Update(&ctx, (const uint8_t *)"]}", 2); - has_message = true; - msgs_remaining--; - return success; + has_message = true; + msgs_remaining--; + return success; } -bool binance_signTxFinalize(uint8_t *public_key, uint8_t *signature) -{ - char buffer[64 + 1]; +bool binance_signTxFinalize(uint8_t *public_key, uint8_t *signature) { + char buffer[64 + 1]; - if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "],\"sequence\":\"%" PRIu64 "\",\"source\":\"%" PRIu64 "\"}", - msg.sequence, msg.source)) - return false; + if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "],\"sequence\":\"%" PRIu64 + "\",\"source\":\"%" PRIu64 "\"}", + msg.sequence, msg.source)) + return false; - hdnode_fill_public_key(&node); - memcpy(public_key, node.public_key, 33); + hdnode_fill_public_key(&node); + memcpy(public_key, node.public_key, 33); - uint8_t hash[SHA256_DIGEST_LENGTH]; - sha256_Final(&ctx, hash); - return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0; + uint8_t hash[SHA256_DIGEST_LENGTH]; + sha256_Final(&ctx, hash); + return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, + NULL) == 0; } -bool binance_signingIsInited(void) { - return initialized; -} +bool binance_signingIsInited(void) { return initialized; } -bool binance_signingIsFinished(void) { - return msgs_remaining == 0; -} +bool binance_signingIsFinished(void) { return msgs_remaining == 0; } void binance_signAbort(void) { - initialized = false; - has_message = false; - msgs_remaining = 0; - memzero(&msg, sizeof(msg)); - memzero(&node, sizeof(node)); + initialized = false; + has_message = false; + msgs_remaining = 0; + memzero(&msg, sizeof(msg)); + memzero(&node, sizeof(node)); } diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 04f2dae74..bf25cae03 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -26,77 +26,106 @@ #include #define SECP256K1_STRING "secp256k1" -#define ED25519_BLAKE2B_NANO_STRING "ed25519-blake2b-nano" +#define ED25519_BLAKE2B_NANO_STRING "ed25519-blake2b-nano" const CoinType coins[COINS_COUNT] = { -#define X(\ -HAS_COIN_NAME, COIN_NAME, \ -HAS_COIN_SHORTCUT, COIN_SHORTCUT, \ -HAS_ADDRESS_TYPE, ADDRESS_TYPE, \ -HAS_MAXFEE_KB, MAXFEE_KB, \ -HAS_ADDRESS_TYPE_P2SH, ADDRESS_TYPE_P2SH, \ -HAS_SIGNED_MESSAGE_HEADER, SIGNED_MESSAGE_HEADER, \ -HAS_BIP44_ACCOUNT_PATH, BIP44_ACCOUNT_PATH, \ -HAS_FORKID, FORKID, \ -HAS_DECIMALS, DECIMALS, \ -HAS_CONTRACT_ADDRESS, CONTRACT_ADDRESS, \ -HAS_XPUB_MAGIC, XPUB_MAGIC, \ -HAS_SEGWIT, SEGWIT , \ -HAS_FORCE_BIP143, FORCE_BIP143, \ -HAS_CURVE_NAME, CURVE_NAME, \ -HAS_CASHADDR_PREFIX, CASHADDR_PREFIX, \ -HAS_BECH32_PREFIX, BECH32_PREFIX, \ -HAS_DECRED, DECRED, \ -HAS_XPUB_MAGIC_SEGWIT_P2SH, XPUB_MAGIC_SEGWIT_P2SH, \ -HAS_XPUB_MAGIC_SEGWIT_NATIVE, XPUB_MAGIC_SEGWIT_NATIVE, \ -HAS_NANOADDR_PREFIX, NANOADDR_PREFIX \ -) \ - { HAS_COIN_NAME, COIN_NAME, \ - HAS_COIN_SHORTCUT, COIN_SHORTCUT, \ - HAS_ADDRESS_TYPE, ADDRESS_TYPE, \ - HAS_MAXFEE_KB, MAXFEE_KB, \ - HAS_ADDRESS_TYPE_P2SH, ADDRESS_TYPE_P2SH, \ - HAS_SIGNED_MESSAGE_HEADER, SIGNED_MESSAGE_HEADER, \ - HAS_BIP44_ACCOUNT_PATH, BIP44_ACCOUNT_PATH, \ - HAS_FORKID, FORKID, \ - HAS_DECIMALS, DECIMALS, \ - HAS_CONTRACT_ADDRESS, CONTRACT_ADDRESS, \ - HAS_XPUB_MAGIC, XPUB_MAGIC, \ - HAS_SEGWIT, SEGWIT , \ - HAS_FORCE_BIP143, FORCE_BIP143, \ - HAS_CURVE_NAME, CURVE_NAME, \ - HAS_CASHADDR_PREFIX, CASHADDR_PREFIX, \ - HAS_BECH32_PREFIX, BECH32_PREFIX, \ - HAS_DECRED, DECRED, \ - HAS_XPUB_MAGIC_SEGWIT_P2SH, XPUB_MAGIC_SEGWIT_P2SH, \ - HAS_XPUB_MAGIC_SEGWIT_NATIVE, XPUB_MAGIC_SEGWIT_NATIVE, \ - HAS_NANOADDR_PREFIX, NANOADDR_PREFIX }, - #include "keepkey/firmware/coins.def" - -#define X(INDEX, NAME, SYMBOL, DECIMALS, CONTRACT_ADDRESS) \ - { \ - true, (#NAME), /* has_coin_name, coin_name*/ \ - true, (#SYMBOL), /* has_coin_shortcut, coin_shortcut*/ \ - false, NA, /* has_address_type, address_type*/ \ - true, 100000, /* has_maxfee_kb, maxfee_kb*/ \ - false, NA, /* has_address_type_p2sh, address_type_p2sh*/ \ - false, "", /* has_signed_message_header, signed_message_header*/ \ - true, 0x8000003C, /* has_bip44_account_path, bip44_account_path*/ \ - true, 1, /* has_forkid, forkid*/ \ - true, (DECIMALS), /* has_decimals, decimals*/ \ - true, {20, {(CONTRACT_ADDRESS)}}, /* has_contract_address, contract_address*/ \ - false, 0, /* has_xpub_magic, xpub_magic*/ \ - false, false, /* has_segwit, segwit */ \ - false, false, /* has_force_bip143, force_bip143*/ \ - true, SECP256K1_STRING, /* has_curve_name, curve_name*/ \ - false, "", /* has_cashaddr_prefix, cashaddr_prefix*/ \ - false, "", /* has_bech32_prefix, bech32_prefix*/ \ - false, false, /* has_decred, decred */ \ - false, 0, /* has_xpub_magic_segwit_p2sh, xpub_magic_segwit_p2sh*/ \ - false, 0, /* has_xpub_magic_segwit_native, xpub_magic_segwit_native*/ \ - false, "", /* has_nanoaddr_prefix, nanoaddr_prefix*/ \ - }, - #include "keepkey/firmware/tokens.def" +#define X(HAS_COIN_NAME, COIN_NAME, HAS_COIN_SHORTCUT, COIN_SHORTCUT, \ + HAS_ADDRESS_TYPE, ADDRESS_TYPE, HAS_MAXFEE_KB, MAXFEE_KB, \ + HAS_ADDRESS_TYPE_P2SH, ADDRESS_TYPE_P2SH, HAS_SIGNED_MESSAGE_HEADER, \ + SIGNED_MESSAGE_HEADER, HAS_BIP44_ACCOUNT_PATH, BIP44_ACCOUNT_PATH, \ + HAS_FORKID, FORKID, HAS_DECIMALS, DECIMALS, HAS_CONTRACT_ADDRESS, \ + CONTRACT_ADDRESS, HAS_XPUB_MAGIC, XPUB_MAGIC, HAS_SEGWIT, SEGWIT, \ + HAS_FORCE_BIP143, FORCE_BIP143, HAS_CURVE_NAME, CURVE_NAME, \ + HAS_CASHADDR_PREFIX, CASHADDR_PREFIX, HAS_BECH32_PREFIX, \ + BECH32_PREFIX, HAS_DECRED, DECRED, HAS_XPUB_MAGIC_SEGWIT_P2SH, \ + XPUB_MAGIC_SEGWIT_P2SH, HAS_XPUB_MAGIC_SEGWIT_NATIVE, \ + XPUB_MAGIC_SEGWIT_NATIVE, HAS_NANOADDR_PREFIX, NANOADDR_PREFIX) \ + {HAS_COIN_NAME, \ + COIN_NAME, \ + HAS_COIN_SHORTCUT, \ + COIN_SHORTCUT, \ + HAS_ADDRESS_TYPE, \ + ADDRESS_TYPE, \ + HAS_MAXFEE_KB, \ + MAXFEE_KB, \ + HAS_ADDRESS_TYPE_P2SH, \ + ADDRESS_TYPE_P2SH, \ + HAS_SIGNED_MESSAGE_HEADER, \ + SIGNED_MESSAGE_HEADER, \ + HAS_BIP44_ACCOUNT_PATH, \ + BIP44_ACCOUNT_PATH, \ + HAS_FORKID, \ + FORKID, \ + HAS_DECIMALS, \ + DECIMALS, \ + HAS_CONTRACT_ADDRESS, \ + CONTRACT_ADDRESS, \ + HAS_XPUB_MAGIC, \ + XPUB_MAGIC, \ + HAS_SEGWIT, \ + SEGWIT, \ + HAS_FORCE_BIP143, \ + FORCE_BIP143, \ + HAS_CURVE_NAME, \ + CURVE_NAME, \ + HAS_CASHADDR_PREFIX, \ + CASHADDR_PREFIX, \ + HAS_BECH32_PREFIX, \ + BECH32_PREFIX, \ + HAS_DECRED, \ + DECRED, \ + HAS_XPUB_MAGIC_SEGWIT_P2SH, \ + XPUB_MAGIC_SEGWIT_P2SH, \ + HAS_XPUB_MAGIC_SEGWIT_NATIVE, \ + XPUB_MAGIC_SEGWIT_NATIVE, \ + HAS_NANOADDR_PREFIX, \ + NANOADDR_PREFIX}, +#include "keepkey/firmware/coins.def" + +#define X(INDEX, NAME, SYMBOL, DECIMALS, CONTRACT_ADDRESS) \ + { \ + true, \ + (#NAME), /* has_coin_name, coin_name*/ \ + true, \ + (#SYMBOL), /* has_coin_shortcut, coin_shortcut*/ \ + false, \ + NA, /* has_address_type, address_type*/ \ + true, \ + 100000, /* has_maxfee_kb, maxfee_kb*/ \ + false, \ + NA, /* has_address_type_p2sh, address_type_p2sh*/ \ + false, \ + "", /* has_signed_message_header, signed_message_header*/ \ + true, \ + 0x8000003C, /* has_bip44_account_path, bip44_account_path*/ \ + true, \ + 1, /* has_forkid, forkid*/ \ + true, \ + (DECIMALS), /* has_decimals, decimals*/ \ + true, \ + {20, {(CONTRACT_ADDRESS)}}, /* has_contract_address, contract_address*/ \ + false, \ + 0, /* has_xpub_magic, xpub_magic*/ \ + false, \ + false, /* has_segwit, segwit */ \ + false, \ + false, /* has_force_bip143, force_bip143*/ \ + true, \ + SECP256K1_STRING, /* has_curve_name, curve_name*/ \ + false, \ + "", /* has_cashaddr_prefix, cashaddr_prefix*/ \ + false, \ + "", /* has_bech32_prefix, bech32_prefix*/ \ + false, \ + false, /* has_decred, decred */ \ + false, \ + 0, /* has_xpub_magic_segwit_p2sh, xpub_magic_segwit_p2sh*/ \ + false, \ + 0, /* has_xpub_magic_segwit_native, xpub_magic_segwit_native*/ \ + false, \ + "", /* has_nanoaddr_prefix, nanoaddr_prefix*/ \ + }, +#include "keepkey/firmware/tokens.def" }; _Static_assert(sizeof(coins) / sizeof(coins[0]) == COINS_COUNT, @@ -105,219 +134,199 @@ _Static_assert(sizeof(coins) / sizeof(coins[0]) == COINS_COUNT, // Borrowed from fsm_msg_coin.h // PLEASE keep these in sync. static bool path_mismatched(const CoinType *coin, const uint32_t *address_n, - uint32_t address_n_count, bool whole_account) -{ - bool mismatch = false; - - // m : no path - if (address_n_count == 0) { - return false; - } - - // Special case (not needed in the other copy of this function): - // KeepKey only puts ETH-like coins on m/44'/coin'/account'/0/0 paths - if (address_n_count == 5 && - (strncmp(coin->coin_name, ETHEREUM, strlen(ETHEREUM)) == 0 || - strncmp(coin->coin_name, ETHEREUM_CLS, sizeof(ETHEREUM_CLS)) == 0 || - strncmp(coin->coin_name, ETHEREUM_TST, sizeof(ETHEREUM_TST)) == 0 || - coin->has_contract_address)) { - if (whole_account) - return true; - // Check that the path is m/44'/bip44_account_path/y/0/0 - if (address_n[3] != 0) - return true; - if (address_n[4] != 0) - return true; - } - - // m/44' : BIP44 Legacy - // m / purpose' / bip44_account_path' / account' / change / address_index - if (address_n[0] == (0x80000000 + 44)) { - mismatch |= (address_n_count != (whole_account ? 3 : 5)); - mismatch |= (address_n[1] != coin->bip44_account_path); - mismatch |= (address_n[2] & 0x80000000) == 0; - if (!whole_account) { - mismatch |= (address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (address_n[4] & 0x80000000) == 0x80000000; - } - return mismatch; - } - - // m/45' - BIP45 Copay Abandoned Multisig P2SH - // m / purpose' / cosigner_index / change / address_index - if (address_n[0] == (0x80000000 + 45)) { - mismatch |= (address_n_count != 4); - mismatch |= (address_n[1] & 0x80000000) == 0x80000000; - mismatch |= (address_n[2] & 0x80000000) == 0x80000000; - mismatch |= (address_n[3] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/48' - BIP48 Copay Multisig P2SH - // m / purpose' / bip44_account_path' / account' / change / address_index - if (address_n[0] == (0x80000000 + 48)) { - mismatch |= (address_n_count != (whole_account ? 3 : 5)); - mismatch |= (address_n[1] != coin->bip44_account_path); - mismatch |= (address_n[2] & 0x80000000) == 0; - if (!whole_account) { - mismatch |= (address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (address_n[4] & 0x80000000) == 0x80000000; - } - return mismatch; - } - - // m/49' : BIP49 SegWit - // m / purpose' / bip44_account_path' / account' / change / address_index - if (address_n[0] == (0x80000000 + 49)) { - mismatch |= !coin->has_segwit || !coin->segwit; - mismatch |= !coin->has_address_type_p2sh; - mismatch |= (address_n_count != (whole_account ? 3 : 5)); - mismatch |= (address_n[1] != coin->bip44_account_path); - mismatch |= (address_n[2] & 0x80000000) == 0; - if (!whole_account) { - mismatch |= (address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (address_n[4] & 0x80000000) == 0x80000000; - } - return mismatch; - } - - // m/84' : BIP84 Native SegWit - // m / purpose' / bip44_account_path' / account' / change / address_index - if (address_n[0] == (0x80000000 + 84)) { - mismatch |= !coin->has_segwit || !coin->segwit; - mismatch |= !coin->has_bech32_prefix; - mismatch |= (address_n_count != (whole_account ? 3 : 5)); - mismatch |= (address_n[1] != coin->bip44_account_path); - mismatch |= (address_n[2] & 0x80000000) == 0; - if (!whole_account) { - mismatch |= (address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (address_n[4] & 0x80000000) == 0x80000000; - } - return mismatch; - } - - return false; + uint32_t address_n_count, bool whole_account) { + bool mismatch = false; + + // m : no path + if (address_n_count == 0) { + return false; + } + + // Special case (not needed in the other copy of this function): + // KeepKey only puts ETH-like coins on m/44'/coin'/account'/0/0 paths + if (address_n_count == 5 && + (strncmp(coin->coin_name, ETHEREUM, strlen(ETHEREUM)) == 0 || + strncmp(coin->coin_name, ETHEREUM_CLS, sizeof(ETHEREUM_CLS)) == 0 || + strncmp(coin->coin_name, ETHEREUM_TST, sizeof(ETHEREUM_TST)) == 0 || + coin->has_contract_address)) { + if (whole_account) return true; + // Check that the path is m/44'/bip44_account_path/y/0/0 + if (address_n[3] != 0) return true; + if (address_n[4] != 0) return true; + } + + // m/44' : BIP44 Legacy + // m / purpose' / bip44_account_path' / account' / change / address_index + if (address_n[0] == (0x80000000 + 44)) { + mismatch |= (address_n_count != (whole_account ? 3 : 5)); + mismatch |= (address_n[1] != coin->bip44_account_path); + mismatch |= (address_n[2] & 0x80000000) == 0; + if (!whole_account) { + mismatch |= (address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (address_n[4] & 0x80000000) == 0x80000000; + } + return mismatch; + } + + // m/45' - BIP45 Copay Abandoned Multisig P2SH + // m / purpose' / cosigner_index / change / address_index + if (address_n[0] == (0x80000000 + 45)) { + mismatch |= (address_n_count != 4); + mismatch |= (address_n[1] & 0x80000000) == 0x80000000; + mismatch |= (address_n[2] & 0x80000000) == 0x80000000; + mismatch |= (address_n[3] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/48' - BIP48 Copay Multisig P2SH + // m / purpose' / bip44_account_path' / account' / change / address_index + if (address_n[0] == (0x80000000 + 48)) { + mismatch |= (address_n_count != (whole_account ? 3 : 5)); + mismatch |= (address_n[1] != coin->bip44_account_path); + mismatch |= (address_n[2] & 0x80000000) == 0; + if (!whole_account) { + mismatch |= (address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (address_n[4] & 0x80000000) == 0x80000000; + } + return mismatch; + } + + // m/49' : BIP49 SegWit + // m / purpose' / bip44_account_path' / account' / change / address_index + if (address_n[0] == (0x80000000 + 49)) { + mismatch |= !coin->has_segwit || !coin->segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= (address_n_count != (whole_account ? 3 : 5)); + mismatch |= (address_n[1] != coin->bip44_account_path); + mismatch |= (address_n[2] & 0x80000000) == 0; + if (!whole_account) { + mismatch |= (address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (address_n[4] & 0x80000000) == 0x80000000; + } + return mismatch; + } + + // m/84' : BIP84 Native SegWit + // m / purpose' / bip44_account_path' / account' / change / address_index + if (address_n[0] == (0x80000000 + 84)) { + mismatch |= !coin->has_segwit || !coin->segwit; + mismatch |= !coin->has_bech32_prefix; + mismatch |= (address_n_count != (whole_account ? 3 : 5)); + mismatch |= (address_n[1] != coin->bip44_account_path); + mismatch |= (address_n[2] & 0x80000000) == 0; + if (!whole_account) { + mismatch |= (address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (address_n[4] & 0x80000000) == 0x80000000; + } + return mismatch; + } + + return false; } bool bip32_path_to_string(char *str, size_t len, const uint32_t *address_n, size_t address_n_count) { - memset(str, 0, len); + memset(str, 0, len); + + int cx = snprintf(str, len, address_n_count == 0 ? "m/" : "m"); + if (cx < 0 || len <= (size_t)cx) return false; + str += cx; + len -= cx; - int cx = snprintf(str, len, address_n_count == 0 ? "m/" : "m"); - if (cx < 0 || len <= (size_t)cx) - return false; + for (size_t i = 0; i < address_n_count; i++) { + cx = snprintf(str, len, "/%" PRIu32, address_n[i] & 0x7fffffff); + if (cx < 0 || len <= (size_t)cx) return false; str += cx; len -= cx; - for (size_t i = 0; i < address_n_count; i++) { - cx = snprintf(str, len, "/%" PRIu32, address_n[i] & 0x7fffffff); - if (cx < 0 || len <= (size_t)cx) - return false; - str += cx; - len -= cx; - - if ((address_n[i] & 0x80000000) == 0x80000000) { - cx = snprintf(str, len, "'"); - if (cx < 0 || len <= (size_t)cx) - return false; - str += cx; - len -= cx; - } + if ((address_n[i] & 0x80000000) == 0x80000000) { + cx = snprintf(str, len, "'"); + if (cx < 0 || len <= (size_t)cx) return false; + str += cx; + len -= cx; } + } - return true; + return true; } -const CoinType *coinByShortcut(const char *shortcut) -{ - if(!shortcut) { return 0; } +const CoinType *coinByShortcut(const char *shortcut) { + if (!shortcut) { + return 0; + } - int i; + int i; - for(i = 0; i < COINS_COUNT; i++) - { - if(strncasecmp(shortcut, coins[i].coin_shortcut, - sizeof(coins[i].coin_shortcut)) == 0) - { - return &coins[i]; - } + for (i = 0; i < COINS_COUNT; i++) { + if (strncasecmp(shortcut, coins[i].coin_shortcut, + sizeof(coins[i].coin_shortcut)) == 0) { + return &coins[i]; } + } - return 0; + return 0; } -const CoinType *coinByName(const char *name) -{ - if(!name) { return 0; } +const CoinType *coinByName(const char *name) { + if (!name) { + return 0; + } - int i; + int i; - for(i = 0; i < COINS_COUNT; i++) - { - if(strncasecmp(name, coins[i].coin_name, - sizeof(coins[i].coin_name)) == 0) - { - return &coins[i]; - } + for (i = 0; i < COINS_COUNT; i++) { + if (strncasecmp(name, coins[i].coin_name, sizeof(coins[i].coin_name)) == + 0) { + return &coins[i]; } + } - return 0; + return 0; } -const CoinType *coinByNameOrTicker(const char *name) -{ - const CoinType *coin = coinByName(name); - if (coin) - return coin; +const CoinType *coinByNameOrTicker(const char *name) { + const CoinType *coin = coinByName(name); + if (coin) return coin; - return coinByShortcut(name); + return coinByShortcut(name); } -const CoinType *coinByChainAddress(uint8_t chain_id, const uint8_t *address) -{ - if (chain_id != 1) - return NULL; +const CoinType *coinByChainAddress(uint8_t chain_id, const uint8_t *address) { + if (chain_id != 1) return NULL; - if (!address) - return NULL; + if (!address) return NULL; - for (int i = 0; i < COINS_COUNT; i++) { - if (!coins[i].has_contract_address) - continue; + for (int i = 0; i < COINS_COUNT; i++) { + if (!coins[i].has_contract_address) continue; - if (coins[i].contract_address.size != 20) - continue; + if (coins[i].contract_address.size != 20) continue; - if (memcmp(address, coins[i].contract_address.bytes, 20) == 0) - return &coins[i]; - } + if (memcmp(address, coins[i].contract_address.bytes, 20) == 0) + return &coins[i]; + } - return NULL; + return NULL; } -const CoinType *coinByAddressType(uint32_t address_type) -{ - int i; +const CoinType *coinByAddressType(uint32_t address_type) { + int i; - for(i = 0; i < COINS_COUNT; i++) - { - if(address_type == coins[i].address_type) - { - return &coins[i]; - } + for (i = 0; i < COINS_COUNT; i++) { + if (address_type == coins[i].address_type) { + return &coins[i]; } + } - return 0; + return 0; } -const CoinType *coinBySlip44(uint32_t bip44_account_path) -{ - for (int i = 0; i < COINS_COUNT; i++) { - if (bip44_account_path == coins[i].bip44_account_path) { - return &coins[i]; - } +const CoinType *coinBySlip44(uint32_t bip44_account_path) { + for (int i = 0; i < COINS_COUNT; i++) { + if (bip44_account_path == coins[i].bip44_account_path) { + return &coins[i]; } - return 0; + } + return 0; } /* @@ -332,156 +341,136 @@ const CoinType *coinBySlip44(uint32_t bip44_account_path) * none * */ -void coin_amnt_to_str(const CoinType *coin, uint64_t amnt, char *buf, int len) -{ - uint64_t coin_fraction_part, coin_whole_part; - int i; - char buf_fract[10]; - - memset(buf, 0, len); - memset(buf_fract, 0, 10); - - /*Seperate amount to whole and fraction (amount = whole.fraction)*/ - coin_whole_part = amnt / COIN_FRACTION ; - coin_fraction_part = amnt % COIN_FRACTION; - - /* Convert whole value to string */ - if(coin_whole_part > 0) - { - dec64_to_str(coin_whole_part, buf); - buf[strlen(buf)] = '.'; - } - else - { - strncpy(buf, "0.", len); - } - - /* Convert Fraction value to string */ - if(coin_fraction_part > 0) - { - dec64_to_str(coin_fraction_part, buf_fract); - - /* Add zeros after decimal */ - i = 8 - strlen(buf_fract); - while(i) - { - buf[strlen(buf)+i-1] = '0'; - i--; - } - /*concantenate whole and fraction part of string */ - strncpy(buf+strlen(buf), buf_fract, strlen(buf_fract)); - - /* Drop least significant zeros in fraction part to shorten display*/ - i = strlen(buf); - while(buf[i-1] == '0') - { - buf[i-1] = 0; - i--; - } +void coin_amnt_to_str(const CoinType *coin, uint64_t amnt, char *buf, int len) { + uint64_t coin_fraction_part, coin_whole_part; + int i; + char buf_fract[10]; + + memset(buf, 0, len); + memset(buf_fract, 0, 10); + + /*Seperate amount to whole and fraction (amount = whole.fraction)*/ + coin_whole_part = amnt / COIN_FRACTION; + coin_fraction_part = amnt % COIN_FRACTION; + + /* Convert whole value to string */ + if (coin_whole_part > 0) { + dec64_to_str(coin_whole_part, buf); + buf[strlen(buf)] = '.'; + } else { + strncpy(buf, "0.", len); + } + + /* Convert Fraction value to string */ + if (coin_fraction_part > 0) { + dec64_to_str(coin_fraction_part, buf_fract); + + /* Add zeros after decimal */ + i = 8 - strlen(buf_fract); + while (i) { + buf[strlen(buf) + i - 1] = '0'; + i--; } - else - { - buf[strlen(buf)] = '0'; - } - /* Added coin type to amount */ - if(coin->has_coin_shortcut) - { - buf[strlen(buf)] = ' '; - strncpy(buf + strlen(buf), coin->coin_shortcut, strlen(coin->coin_shortcut)); + /*concantenate whole and fraction part of string */ + strncpy(buf + strlen(buf), buf_fract, strlen(buf_fract)); + + /* Drop least significant zeros in fraction part to shorten display*/ + i = strlen(buf); + while (buf[i - 1] == '0') { + buf[i - 1] = 0; + i--; } + } else { + buf[strlen(buf)] = '0'; + } + /* Added coin type to amount */ + if (coin->has_coin_shortcut) { + buf[strlen(buf)] = ' '; + strncpy(buf + strlen(buf), coin->coin_shortcut, + strlen(coin->coin_shortcut)); + } } static const char *account_prefix(const CoinType *coin, const uint32_t *address_n, - size_t address_n_count, - bool whole_account) { - if (!coin->has_segwit || !coin->segwit) - return ""; + size_t address_n_count, bool whole_account) { + if (!coin->has_segwit || !coin->segwit) return ""; - if (address_n_count < (whole_account ? 3 : 5)) - return NULL; + if (address_n_count < (whole_account ? 3 : 5)) return NULL; - uint32_t purpose = address_n[address_n_count - (whole_account ? 3 : 5)]; + uint32_t purpose = address_n[address_n_count - (whole_account ? 3 : 5)]; - if (purpose == (0x80000000 | 44)) - return ""; + if (purpose == (0x80000000 | 44)) return ""; - if (purpose == (0x80000000 | 49)) - return "\x01 "; + if (purpose == (0x80000000 | 49)) return "\x01 "; - if (purpose == (0x80000000 | 84)) - return "\x01 "; + if (purpose == (0x80000000 | 84)) return "\x01 "; - return NULL; + return NULL; } -bool isEthereumLike(const char *coin_name) -{ - if (strcmp(coin_name, ETHEREUM) == 0) - return true; +bool isEthereumLike(const char *coin_name) { + if (strcmp(coin_name, ETHEREUM) == 0) return true; - if (strcmp(coin_name, ETHEREUM_CLS) == 0) - return true; + if (strcmp(coin_name, ETHEREUM_CLS) == 0) return true; - if (strcmp(coin_name, ETHEREUM_TST) == 0) - return true; + if (strcmp(coin_name, ETHEREUM_TST) == 0) return true; - return false; + return false; } static bool isEOS(const char *coin_name) { - if (strcmp(coin_name, "EOS") == 0) - return true; + if (strcmp(coin_name, "EOS") == 0) return true; - return false; + return false; } -static bool isAccountBased(const char* coin_name) -{ - if (strcmp(coin_name, "Cosmos") == 0) { return true; } - if (isEthereumLike(coin_name)) { return true; } - if (isEOS(coin_name)) { return true; } - return false; +static bool isAccountBased(const char *coin_name) { + if (strcmp(coin_name, "Cosmos") == 0) { + return true; + } + if (isEthereumLike(coin_name)) { + return true; + } + if (isEOS(coin_name)) { + return true; + } + return false; } bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, const uint32_t *address_n, size_t address_n_count, - bool whole_account, bool show_addridx) -{ - if (address_n_count != 3 && address_n_count != 5) - return false; + bool whole_account, bool show_addridx) { + if (address_n_count != 3 && address_n_count != 5) return false; - // If it is a token, we still refer to the destination as an Ethereum account. - bool is_token = coin->has_contract_address; - const char *coin_name = is_token ? "Ethereum" : coin->coin_name; + // If it is a token, we still refer to the destination as an Ethereum account. + bool is_token = coin->has_contract_address; + const char *coin_name = is_token ? "Ethereum" : coin->coin_name; - if (!whole_account) { - if (address_n_count != 5) - return false; + if (!whole_account) { + if (address_n_count != 5) return false; - // Only 0/1 for internal/external are valid paths on UTXO coins. - if (!isAccountBased(coin_name) && - address_n[3] != 0 && address_n[3] != 1) - return false; - } + // Only 0/1 for internal/external are valid paths on UTXO coins. + if (!isAccountBased(coin_name) && address_n[3] != 0 && address_n[3] != 1) + return false; + } - if (path_mismatched(coin, address_n, address_n_count, whole_account)) - return false; - - const char *prefix = account_prefix(coin, address_n, address_n_count, whole_account); - if (!prefix) - return false; - - if (whole_account || isAccountBased(coin_name) || !show_addridx) { - snprintf(node_str, len, "%s%s Account #%" PRIu32, prefix, coin_name, - address_n[2] & 0x7fffffff); - } else { - bool is_change = address_n[3] == 1; - snprintf(node_str, len, "%s%s Account #%" PRIu32 "\n%sAddress #%" PRIu32, - prefix, coin_name, address_n[2] & 0x7fffffff, - is_change ? "Change " : "", address_n[4]); - } + if (path_mismatched(coin, address_n, address_n_count, whole_account)) + return false; - return true; + const char *prefix = + account_prefix(coin, address_n, address_n_count, whole_account); + if (!prefix) return false; + + if (whole_account || isAccountBased(coin_name) || !show_addridx) { + snprintf(node_str, len, "%s%s Account #%" PRIu32, prefix, coin_name, + address_n[2] & 0x7fffffff); + } else { + bool is_change = address_n[3] == 1; + snprintf(node_str, len, "%s%s Account #%" PRIu32 "\n%sAddress #%" PRIu32, + prefix, coin_name, address_n[2] & 0x7fffffff, + is_change ? "Change " : "", address_n[4]); + } + + return true; } - diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 5378358a1..cf5843049 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -20,129 +20,124 @@ static bool initialized; static uint32_t msgs_remaining; static CosmosSignTx msg; -const CosmosSignTx *cosmos_getCosmosSignTx(void) -{ - return &msg; +const CosmosSignTx *cosmos_getCosmosSignTx(void) { return &msg; } + +bool cosmos_signTxInit(const HDNode *_node, const CosmosSignTx *_msg) { + initialized = true; + msgs_remaining = _msg->msg_count; + has_message = false; + + memzero(&node, sizeof(node)); + memcpy(&node, _node, sizeof(node)); + memcpy(&msg, _msg, sizeof(msg)); + + bool success = true; + char buffer[64 + 1]; + + sha256_Init(&ctx); + + // Each segment guaranteed to be less than or equal to 64 bytes + // 19 + ^20 + 1 = ^40 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "{\"account_number\":\"%" PRIu64 "\"", + msg.account_number); + + // + const char *const chainid_prefix = ",\"chain_id\":\""; + sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix)); + tendermint_sha256UpdateEscaped(&ctx, msg.chain_id, strlen(msg.chain_id)); + + // 30 + ^10 + 19 = ^59 + success &= + tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 + "\",\"denom\":\"uatom\"}]", + msg.fee_amount); + + // 8 + ^10 + 2 = ^20 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"gas\":\"%" PRIu32 "\"}", msg.gas); + + // + const char *const memo_prefix = ",\"memo\":\""; + sha256_Update(&ctx, (uint8_t *)memo_prefix, strlen(memo_prefix)); + if (msg.has_memo) { + tendermint_sha256UpdateEscaped(&ctx, msg.memo, strlen(msg.memo)); + } + + // 10 + sha256_Update(&ctx, (uint8_t *)"\",\"msgs\":[", 10); + + return success; } -bool cosmos_signTxInit(const HDNode* _node, const CosmosSignTx *_msg) -{ - initialized = true; - msgs_remaining = _msg->msg_count; - has_message = false; +bool cosmos_signTxUpdateMsgSend(const uint64_t amount, const char *to_address) { + char buffer[64 + 1]; - memzero(&node, sizeof(node)); - memcpy(&node, _node, sizeof(node)); - memcpy(&msg, _msg, sizeof(msg)); + size_t decoded_len; + char hrp[45]; + uint8_t decoded[38]; + if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { + return false; + } - bool success = true; - char buffer[64 + 1]; + char from_address[46]; + if (!tendermint_getAddress(&node, "cosmos", from_address)) { + return false; + } - sha256_Init(&ctx); + if (has_message) { + sha256_Update(&ctx, (uint8_t *)",", 1); + } - // Each segment guaranteed to be less than or equal to 64 bytes - // 19 + ^20 + 1 = ^40 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "{\"account_number\":\"%" PRIu64 "\"", - msg.account_number); + bool success = true; - // - const char *const chainid_prefix = ",\"chain_id\":\""; - sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix)); - tendermint_sha256UpdateEscaped(&ctx, msg.chain_id, strlen(msg.chain_id)); + const char *const prelude = "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{"; + sha256_Update(&ctx, (uint8_t *)prelude, strlen(prelude)); - // 30 + ^10 + 19 = ^59 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}]", - msg.fee_amount); + // 21 + ^20 + 19 = ^60 + success &= tendermint_snprintf( + &ctx, buffer, sizeof(buffer), + "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}]", amount); - // 8 + ^10 + 2 = ^20 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - ",\"gas\":\"%" PRIu32 "\"}", msg.gas); + // 17 + 45 + 1 = 63 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"from_address\":\"%s\"", from_address); - // - const char *const memo_prefix = ",\"memo\":\""; - sha256_Update(&ctx, (uint8_t *)memo_prefix, strlen(memo_prefix)); - if (msg.has_memo) { - tendermint_sha256UpdateEscaped(&ctx, msg.memo, strlen(msg.memo)); - } + // 15 + 45 + 3 = 63 + success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), + ",\"to_address\":\"%s\"}}", to_address); - // 10 - sha256_Update(&ctx, (uint8_t *)"\",\"msgs\":[", 10); - - return success; -} - -bool cosmos_signTxUpdateMsgSend(const uint64_t amount, - const char *to_address) -{ - char buffer[64 + 1]; - - size_t decoded_len; - char hrp[45]; - uint8_t decoded[38]; - if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } - - char from_address[46]; - if (!tendermint_getAddress(&node, "cosmos", from_address)) { return false; } - - if (has_message) { - sha256_Update(&ctx, (uint8_t*)",", 1); - } - - bool success = true; - - const char *const prelude = "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{"; - sha256_Update(&ctx, (uint8_t *)prelude, strlen(prelude)); - - // 21 + ^20 + 19 = ^60 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}]", - amount); - - // 17 + 45 + 1 = 63 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - ",\"from_address\":\"%s\"", - from_address); - - // 15 + 45 + 3 = 63 - success &= tendermint_snprintf(&ctx, buffer, sizeof(buffer), - ",\"to_address\":\"%s\"}}", to_address); - - has_message = true; - msgs_remaining--; - return success; + has_message = true; + msgs_remaining--; + return success; } -bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature) -{ - char buffer[64 + 1]; +bool cosmos_signTxFinalize(uint8_t *public_key, uint8_t *signature) { + char buffer[64 + 1]; - // 16 + ^20 = ^36 - if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer), - "],\"sequence\":\"%" PRIu64 "\"}", msg.sequence)) - return false; + // 16 + ^20 = ^36 + if (!tendermint_snprintf(&ctx, buffer, sizeof(buffer), + "],\"sequence\":\"%" PRIu64 "\"}", msg.sequence)) + return false; - hdnode_fill_public_key(&node); - memcpy(public_key, node.public_key, 33); + hdnode_fill_public_key(&node); + memcpy(public_key, node.public_key, 33); - uint8_t hash[SHA256_DIGEST_LENGTH]; - sha256_Final(&ctx, hash); - return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0; + uint8_t hash[SHA256_DIGEST_LENGTH]; + sha256_Final(&ctx, hash); + return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, + NULL) == 0; } -bool cosmos_signingIsInited(void) { - return initialized; -} +bool cosmos_signingIsInited(void) { return initialized; } -bool cosmos_signingIsFinished(void) { - return msgs_remaining == 0; -} +bool cosmos_signingIsFinished(void) { return msgs_remaining == 0; } void cosmos_signAbort(void) { - initialized = false; - has_message = false; - msgs_remaining = 0; - memzero(&msg, sizeof(msg)); - memzero(&node, sizeof(node)); + initialized = false; + has_message = false; + msgs_remaining = 0; + memzero(&msg, sizeof(msg)); + memzero(&node, sizeof(node)); } diff --git a/lib/firmware/crypto.c b/lib/firmware/crypto.c index 27046ebf2..92bec4a60 100644 --- a/lib/firmware/crypto.c +++ b/lib/firmware/crypto.c @@ -35,320 +35,349 @@ #include -uint32_t ser_length(uint32_t len, uint8_t *out) -{ - if (len < 253) { - out[0] = len & 0xFF; - return 1; - } - if (len < 0x10000) { - out[0] = 253; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - return 3; - } - out[0] = 254; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - out[3] = (len >> 16) & 0xFF; - out[4] = (len >> 24) & 0xFF; - return 5; +uint32_t ser_length(uint32_t len, uint8_t *out) { + if (len < 253) { + out[0] = len & 0xFF; + return 1; + } + if (len < 0x10000) { + out[0] = 253; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + return 3; + } + out[0] = 254; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + out[3] = (len >> 16) & 0xFF; + out[4] = (len >> 24) & 0xFF; + return 5; } -uint32_t ser_length_hash(Hasher *hasher, uint32_t len) -{ - if (len < 253) { - hasher_Update(hasher, (const uint8_t *)&len, 1); - return 1; - } - if (len < 0x10000) { - uint8_t d = 253; - hasher_Update(hasher, &d, 1); - hasher_Update(hasher, (const uint8_t *)&len, 2); - return 3; - } - uint8_t d = 254; - hasher_Update(hasher, &d, 1); - hasher_Update(hasher, (const uint8_t *)&len, 4); - return 5; +uint32_t ser_length_hash(Hasher *hasher, uint32_t len) { + if (len < 253) { + hasher_Update(hasher, (const uint8_t *)&len, 1); + return 1; + } + if (len < 0x10000) { + uint8_t d = 253; + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 2); + return 3; + } + uint8_t d = 254; + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 4); + return 5; } -uint32_t deser_length(const uint8_t *in, uint32_t *out) -{ - if (in[0] < 253) { - *out = in[0]; - return 1; - } - if (in[0] == 253) { - *out = in[1] + (in[2] << 8); - return 1 + 2; - } - if (in[0] == 254) { - *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t) in[4] << 24); - return 1 + 4; - } - *out = 0; // ignore 64 bit - return 1 + 8; +uint32_t deser_length(const uint8_t *in, uint32_t *out) { + if (in[0] < 253) { + *out = in[0]; + return 1; + } + if (in[0] == 253) { + *out = in[1] + (in[2] << 8); + return 1 + 2; + } + if (in[0] == 254) { + *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t)in[4] << 24); + return 1 + 4; + } + *out = 0; // ignore 64 bit + return 1 + 8; } -int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, NULL, NULL); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature) { + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, + NULL, NULL); } -int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); - if (ed25519_curve_info && node->curve == ed25519_curve_info) { - // GPG supports variable size digest for Ed25519 signatures - return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL); - } else { - // Ensure 256-bit digest before proceeding - if (message_len != 32) { - return 1; - } - return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); - } +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature) { + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); + if (ed25519_curve_info && node->curve == ed25519_curve_info) { + // GPG supports variable size digest for Ed25519 signatures + return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, + NULL); + } else { + // Ensure 256-bit digest before proceeding + if (message_len != 32) { + return 1; + } + return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); + } } -int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key) -{ - curve_point point; - const ecdsa_curve *curve = node->curve->params; - if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { - return 1; - } - bignum256 k; - bn_read_be(node->private_key, &k); - point_multiply(curve, &k, &point, &point); - memzero(&k, sizeof(k)); +int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, + uint8_t *session_key) { + curve_point point; + const ecdsa_curve *curve = node->curve->params; + if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { + return 1; + } + bignum256 k; + bn_read_be(node->private_key, &k); + point_multiply(curve, &k, &point, &point); + memzero(&k, sizeof(k)); - session_key[0] = 0x04; - bn_write_be(&point.x, session_key + 1); - bn_write_be(&point.y, session_key + 33); - memzero(&point, sizeof(point)); - return 0; + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + memzero(&point, sizeof(point)); + return 0; } -_Static_assert(sizeof(((CoinType*)0)->signed_message_header) < 256, "Message header too long"); +_Static_assert(sizeof(((CoinType *)0)->signed_message_header) < 256, + "Message header too long"); -static void cryptoMessageHash(const CoinType *coin, const curve_info *curve, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher; - hasher_Init(&hasher, curve->hasher_sign); - uint8_t header_len = strlen(coin->signed_message_header); - hasher_Update(&hasher, &header_len, 1); - hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); - uint8_t varint[5]; - uint32_t l = ser_length(message_len, varint); - hasher_Update(&hasher, varint, l); - hasher_Update(&hasher, message, message_len); - hasher_Final(&hasher, hash); +static void cryptoMessageHash(const CoinType *coin, const curve_info *curve, + const uint8_t *message, size_t message_len, + uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + hasher_Init(&hasher, curve->hasher_sign); + uint8_t header_len = strlen(coin->signed_message_header); + hasher_Update(&hasher, &header_len, 1); + hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, + strlen(coin->signed_message_header)); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + hasher_Update(&hasher, varint, l); + hasher_Update(&hasher, message, message_len); + hasher_Final(&hasher, hash); } -int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return 1; +int cryptoMessageSign(const CoinType *coin, HDNode *node, + InputScriptType script_type, const uint8_t *message, + size_t message_len, uint8_t *signature) { + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return 1; - if (!coin->has_signed_message_header) return 1; + if (!coin->has_signed_message_header) return 1; - uint8_t hash[HASHER_DIGEST_LENGTH]; - cryptoMessageHash(coin, curve, message, message_len, hash); + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, curve, message, message_len, hash); - uint8_t pby; - int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); - if (result == 0) { - switch (script_type) { - case InputScriptType_SPENDP2SHWITNESS: - // segwit-in-p2sh - signature[0] = 35 + pby; - break; - case InputScriptType_SPENDWITNESS: - // segwit - signature[0] = 39 + pby; - break; - default: - // p2pkh - signature[0] = 31 + pby; - break; - } - } - return result; + uint8_t pby; + int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); + if (result == 0) { + switch (script_type) { + case InputScriptType_SPENDP2SHWITNESS: + // segwit-in-p2sh + signature[0] = 35 + pby; + break; + case InputScriptType_SPENDWITNESS: + // segwit + signature[0] = 39 + pby; + break; + default: + // p2pkh + signature[0] = 31 + pby; + break; + } + } + return result; } -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) -{ - // check for invalid signature prefix - if (signature[0] < 27 || signature[0] > 43) { - return 1; - } +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, + size_t message_len, const char *address, + const uint8_t *signature) { + // check for invalid signature prefix + if (signature[0] < 27 || signature[0] > 43) { + return 1; + } - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return 1; + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return 1; - if (!coin->has_signed_message_header) return 1; + if (!coin->has_signed_message_header) return 1; - uint8_t hash[HASHER_DIGEST_LENGTH]; - cryptoMessageHash(coin, curve, message, message_len, hash); + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, curve, message, message_len, hash); - uint8_t recid = (signature[0] - 27) % 4; - bool compressed = signature[0] >= 31; + uint8_t recid = (signature[0] - 27) % 4; + bool compressed = signature[0] >= 31; - // check if signature verifies the digest and recover the public key - uint8_t pubkey[65]; - if (!curve->params || ecdsa_recover_pub_from_sig(curve->params, pubkey, signature + 1, hash, recid) != 0) { - return 3; - } - // convert public key to compressed pubkey if necessary - if (compressed) { - pubkey[0] = 0x02 | (pubkey[64] & 1); - } + // check if signature verifies the digest and recover the public key + uint8_t pubkey[65]; + if (!curve->params || + ecdsa_recover_pub_from_sig(curve->params, pubkey, signature + 1, hash, + recid) != 0) { + return 3; + } + // convert public key to compressed pubkey if necessary + if (compressed) { + pubkey[0] = 0x02 | (pubkey[64] & 1); + } - // check if the address is correct - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; + // check if the address is correct + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; - // p2pkh - if (signature[0] >= 27 && signature[0] <= 34) { - size_t len; - if (coin->has_cashaddr_prefix) { - if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { - return 2; - } - } else { - len = base58_decode_check(address, curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - } - ecdsa_get_address_raw(pubkey, coin->address_type, curve->hasher_pubkey, recovered_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || len != address_prefix_bytes_len(coin->address_type) + 20) { - return 2; - } - } else - // segwit-in-p2sh - if (signature[0] >= 35 && signature[0] <= 38) { - size_t len = base58_decode_check(address, curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, curve->hasher_pubkey, recovered_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { - return 2; - } - } else - // segwit - if (signature[0] >= 39 && signature[0] <= 42) { - int witver; - size_t len; - if (!coin->has_bech32_prefix - || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { - return 4; - } - ecdsa_get_pubkeyhash(pubkey, curve->hasher_pubkey, addr_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || witver != 0 || len != 20) { - return 2; - } - } else { - return 4; - } + // p2pkh + if (signature[0] >= 27 && signature[0] <= 34) { + size_t len; + if (coin->has_cashaddr_prefix) { + if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { + return 2; + } + } else { + len = base58_decode_check(address, curve->hasher_base58, addr_raw, + MAX_ADDR_RAW_SIZE); + } + ecdsa_get_address_raw(pubkey, coin->address_type, curve->hasher_pubkey, + recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || + len != address_prefix_bytes_len(coin->address_type) + 20) { + return 2; + } + } else + // segwit-in-p2sh + if (signature[0] >= 35 && signature[0] <= 38) { + size_t len = base58_decode_check(address, curve->hasher_base58, addr_raw, + MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, + curve->hasher_pubkey, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || + len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { + return 2; + } + } else + // segwit + if (signature[0] >= 39 && signature[0] <= 42) { + int witver; + size_t len; + if (!coin->has_bech32_prefix || + !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, + address)) { + return 4; + } + ecdsa_get_pubkeyhash(pubkey, curve->hasher_pubkey, addr_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) { + return 2; + } + } else { + return 4; + } - return 0; + return 0; } -uint8_t *cryptoHDNodePathToPubkey(const CoinType *coin, const HDNodePathType *hdnodepath) -{ - if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; - static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, coin->curve_name, &node) == 0) { - return 0; - } - animating_progress_handler("Deriving pubkey...", 0); - for (uint32_t i = 0; i < hdnodepath->address_n_count; i++) { - if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { - return 0; - } - animating_progress_handler("Deriving pubkey...", (i * 1000) / hdnodepath->address_n_count); - } - return node.public_key; +uint8_t *cryptoHDNodePathToPubkey(const CoinType *coin, + const HDNodePathType *hdnodepath) { + if (!hdnodepath->node.has_public_key || + hdnodepath->node.public_key.size != 33) + return 0; + static HDNode node; + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, + hdnodepath->node.chain_code.bytes, + hdnodepath->node.public_key.bytes, coin->curve_name, + &node) == 0) { + return 0; + } + animating_progress_handler("Deriving pubkey...", 0); + for (uint32_t i = 0; i < hdnodepath->address_n_count; i++) { + if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { + return 0; + } + animating_progress_handler("Deriving pubkey...", + (i * 1000) / hdnodepath->address_n_count); + } + return node.public_key; } -int cryptoMultisigPubkeyIndex(const CoinType *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) -{ - for (size_t i = 0; i < multisig->pubkeys_count; i++) { - const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { - return i; - } - } - return -1; +int cryptoMultisigPubkeyIndex(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + const uint8_t *pubkey) { + for (size_t i = 0; i < multisig->pubkeys_count; i++) { + const uint8_t *node_pubkey = + cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); + if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { + return i; + } + } + return -1; } -int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) -{ - static const HDNodePathType *ptr[15], *swap; - const uint32_t n = multisig->pubkeys_count; - if (n < 1 || n > 15) { - return 0; - } - // check sanity - if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; - for (uint32_t i = 0; i < n; i++) { - ptr[i] = &(multisig->pubkeys[i]); - if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; - if (ptr[i]->node.chain_code.size != 32) return 0; - } - animating_progress_handler("Calculating multisig fingerprint...", 0); - // minsort according to pubkey - for (uint32_t i = 0; i < n - 1; i++) { - for (uint32_t j = n - 1; j > i; j--) { - if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, 33) > 0) { - swap = ptr[i]; - ptr[i] = ptr[j]; - ptr[j] = swap; - } - } - } - // hash sorted nodes - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); - for (uint32_t i = 0; i < n; i++) { - animating_progress_handler("Calculating multisig fingerprint...", (i * 1000) / n); - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), sizeof(uint32_t)); - sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); - sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); - } - sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); - sha256_Final(&ctx, hash); - animating_progress_handler("Calculating multisig fingerprint...", 100 * 1000); - return 1; +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, + uint8_t *hash) { + static const HDNodePathType *ptr[15], *swap; + const uint32_t n = multisig->pubkeys_count; + if (n < 1 || n > 15) { + return 0; + } + // check sanity + if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; + for (uint32_t i = 0; i < n; i++) { + ptr[i] = &(multisig->pubkeys[i]); + if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) + return 0; + if (ptr[i]->node.chain_code.size != 32) return 0; + } + animating_progress_handler("Calculating multisig fingerprint...", 0); + // minsort according to pubkey + for (uint32_t i = 0; i < n - 1; i++) { + for (uint32_t j = n - 1; j > i; j--) { + if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, + 33) > 0) { + swap = ptr[i]; + ptr[i] = ptr[j]; + ptr[j] = swap; + } + } + } + // hash sorted nodes + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); + for (uint32_t i = 0; i < n; i++) { + animating_progress_handler("Calculating multisig fingerprint...", + (i * 1000) / n); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), + sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), + sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), + sizeof(uint32_t)); + sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); + sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); + } + sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); + sha256_Final(&ctx, hash); + animating_progress_handler("Calculating multisig fingerprint...", 100 * 1000); + return 1; } -int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) -{ - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); - if (identity->has_proto && identity->proto[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->proto), strlen(identity->proto)); - sha256_Update(&ctx, (const uint8_t *)"://", 3); - } - if (identity->has_user && identity->user[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->user), strlen(identity->user)); - sha256_Update(&ctx, (const uint8_t *)"@", 1); - } - if (identity->has_host && identity->host[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->host), strlen(identity->host)); - } - if (identity->has_port && identity->port[0]) { - sha256_Update(&ctx, (const uint8_t *)":", 1); - sha256_Update(&ctx, (const uint8_t *)(identity->port), strlen(identity->port)); - } - if (identity->has_path && identity->path[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); - } - sha256_Final(&ctx, hash); - return 1; +int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) { + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); + if (identity->has_proto && identity->proto[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->proto), + strlen(identity->proto)); + sha256_Update(&ctx, (const uint8_t *)"://", 3); + } + if (identity->has_user && identity->user[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->user), + strlen(identity->user)); + sha256_Update(&ctx, (const uint8_t *)"@", 1); + } + if (identity->has_host && identity->host[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->host), + strlen(identity->host)); + } + if (identity->has_port && identity->port[0]) { + sha256_Update(&ctx, (const uint8_t *)":", 1); + sha256_Update(&ctx, (const uint8_t *)(identity->port), + strlen(identity->port)); + } + if (identity->has_path && identity->path[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->path), + strlen(identity->path)); + } + sha256_Final(&ctx, hash); + return 1; } diff --git a/lib/firmware/eos-contracts/eosio.system.c b/lib/firmware/eos-contracts/eosio.system.c index 3de95b485..1e3d06fa7 100644 --- a/lib/firmware/eos-contracts/eosio.system.c +++ b/lib/firmware/eos-contracts/eosio.system.c @@ -35,835 +35,837 @@ #include #include -#define CHECK_COMMON(ACTION) \ - do { \ - CHECK_PARAM_RET(common->account == EOS_eosio || \ - common->account == EOS_eosio_token, \ - "Incorrect account name", false); \ - CHECK_PARAM_RET(common->name == (ACTION), \ - "Incorrect action name", false); \ - } while(0) +#define CHECK_COMMON(ACTION) \ + do { \ + CHECK_PARAM_RET( \ + common->account == EOS_eosio || common->account == EOS_eosio_token, \ + "Incorrect account name", false); \ + CHECK_PARAM_RET(common->name == (ACTION), "Incorrect action name", false); \ + } while (0) bool eos_compileActionDelegate(const EosActionCommon *common, const EosActionDelegate *action) { - CHECK_COMMON(EOS_DelegateBW); + CHECK_COMMON(EOS_DelegateBW); - CHECK_PARAM_RET(action->has_sender, "Required field missing", false); - CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); - CHECK_PARAM_RET(action->has_cpu_quantity, "Required field missing", false); - CHECK_PARAM_RET(action->has_net_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_sender, "Required field missing", false); + CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); + CHECK_PARAM_RET(action->has_cpu_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_net_quantity, "Required field missing", false); - char sender[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->sender, sender), - "Invalid name", false); + char sender[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->sender, sender), "Invalid name", + false); - char receiver[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), - "Invalid name", false); + char receiver[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), "Invalid name", + false); - char cpu[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->cpu_quantity, cpu), - "Invalid asset format", false); + char cpu[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->cpu_quantity, cpu), + "Invalid asset format", false); - char net[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->net_quantity, net), - "Invalid asset format", false); + char net[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->net_quantity, net), + "Invalid asset format", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Delegate", - ((action->has_transfer && action->transfer) - ? "Delegate %s CPU and %s RAM from %s to %s?" - : "Transfer %s CPU and %s RAM from %s to %s?"), - cpu, net, sender, receiver)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Delegate", + ((action->has_transfer && action->transfer) + ? "Delegate %s CPU and %s RAM from %s to %s?" + : "Transfer %s CPU and %s RAM from %s to %s?"), + cpu, net, sender, receiver)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8 + 8 + 16 + 16 + 1; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8 + 8 + 16 + 16 + 1; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->sender, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->receiver, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->sender, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->receiver, 8); - CHECK_PARAM_RET(eos_compileAsset(&action->net_quantity), - "Cannot compile asset: net_quantity", false); + CHECK_PARAM_RET(eos_compileAsset(&action->net_quantity), + "Cannot compile asset: net_quantity", false); - CHECK_PARAM_RET(eos_compileAsset(&action->cpu_quantity), - "Cannot compile asset: cpu_quantity", false); + CHECK_PARAM_RET(eos_compileAsset(&action->cpu_quantity), + "Cannot compile asset: cpu_quantity", false); - uint8_t is_transfer = (action->has_transfer && action->transfer) ? 1 : 0; - hasher_Update(&hasher_preimage, &is_transfer, 1); + uint8_t is_transfer = (action->has_transfer && action->transfer) ? 1 : 0; + hasher_Update(&hasher_preimage, &is_transfer, 1); - return true; + return true; } bool eos_compileActionUndelegate(const EosActionCommon *common, const EosActionUndelegate *action) { - CHECK_COMMON(EOS_UndelegateBW); + CHECK_COMMON(EOS_UndelegateBW); - CHECK_PARAM_RET(action->has_sender, "Required field missing", false); - CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); - CHECK_PARAM_RET(action->has_cpu_quantity, "Required field missing", false); - CHECK_PARAM_RET(action->has_net_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_sender, "Required field missing", false); + CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); + CHECK_PARAM_RET(action->has_cpu_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_net_quantity, "Required field missing", false); - char sender[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->sender, sender), - "Invalid name", false); + char sender[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->sender, sender), "Invalid name", + false); - char receiver[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), - "Invalid name", false); + char receiver[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), "Invalid name", + false); - char cpu[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->cpu_quantity, cpu), - "Invalid asset format", false); + char cpu[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->cpu_quantity, cpu), + "Invalid asset format", false); - char net[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->net_quantity, net), - "Invalid asset format", false); + char net[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->net_quantity, net), + "Invalid asset format", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Undelegate", "Revoke delegation of %s CPU and %s RAM from %s to %s?\n", - cpu, net, sender, receiver)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Undelegate", + "Revoke delegation of %s CPU and %s RAM from %s to %s?\n", cpu, + net, sender, receiver)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8 + 8 + 16 + 16; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8 + 8 + 16 + 16; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->sender, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->receiver, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->sender, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->receiver, 8); - CHECK_PARAM_RET(eos_compileAsset(&action->net_quantity), - "Cannot compile asset: net_quantity", false); + CHECK_PARAM_RET(eos_compileAsset(&action->net_quantity), + "Cannot compile asset: net_quantity", false); - CHECK_PARAM_RET(eos_compileAsset(&action->cpu_quantity), - "Cannot compile asset: cpu_quantity", false); + CHECK_PARAM_RET(eos_compileAsset(&action->cpu_quantity), + "Cannot compile asset: cpu_quantity", false); - return true; + return true; } bool eos_compileActionRefund(const EosActionCommon *common, const EosActionRefund *action) { - CHECK_COMMON(EOS_Refund); + CHECK_COMMON(EOS_Refund); - CHECK_PARAM_RET(action->has_owner, "Required field missing", false); + CHECK_PARAM_RET(action->has_owner, "Required field missing", false); - char owner[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->owner, owner), - "Invalid name", false); + char owner[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->owner, owner), "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Refund", "Do you want reclaim all pending unstaked tokens from your %s account?", - owner)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Refund", + "Do you want reclaim all pending unstaked tokens from your %s " + "account?", + owner)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->owner, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->owner, 8); - return true; + return true; } bool eos_compileActionBuyRam(const EosActionCommon *common, const EosActionBuyRam *action) { - CHECK_COMMON(EOS_BuyRam); + CHECK_COMMON(EOS_BuyRam); - CHECK_PARAM_RET(action->has_payer, "Required field missing", false); - CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); - CHECK_PARAM_RET(action->has_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_payer, "Required field missing", false); + CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); + CHECK_PARAM_RET(action->has_quantity, "Required field missing", false); - char payer[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->payer, payer), - "Invalid name", false); + char payer[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->payer, payer), "Invalid name", false); - char receiver[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), - "Invalid name", false); + char receiver[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), "Invalid name", + false); - char quantity[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->quantity, quantity), - "Invalid asset format", false); + char quantity[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->quantity, quantity), + "Invalid asset format", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Buy Ram", "Using your %s account, buy %s worth of RAM for %s at market price?", - payer, quantity, receiver)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm( + ButtonRequestType_ButtonRequest_ConfirmEosAction, "Buy Ram", + "Using your %s account, buy %s worth of RAM for %s at market price?", + payer, quantity, receiver)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8 + 8 + 16; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8 + 8 + 16; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->payer, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->receiver, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->payer, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->receiver, 8); - CHECK_PARAM_RET(eos_compileAsset(&action->quantity), - "Cannot compile asset: quantity", false); + CHECK_PARAM_RET(eos_compileAsset(&action->quantity), + "Cannot compile asset: quantity", false); - return true; + return true; } bool eos_compileActionBuyRamBytes(const EosActionCommon *common, const EosActionBuyRamBytes *action) { - CHECK_COMMON(EOS_BuyRamBytes); + CHECK_COMMON(EOS_BuyRamBytes); - CHECK_PARAM_RET(action->has_payer, "Required field missing", false); - CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); - CHECK_PARAM_RET(action->has_bytes, "Required field missing", false); + CHECK_PARAM_RET(action->has_payer, "Required field missing", false); + CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); + CHECK_PARAM_RET(action->has_bytes, "Required field missing", false); - char payer[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->payer, payer), - "Invalid name", false); + char payer[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->payer, payer), "Invalid name", false); - char receiver[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), - "Invalid name", false); + char receiver[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), "Invalid name", + false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Buy Ram Bytes", "Using your %s account, buy %" PRIu32 " bytes of RAM for %s?", - payer, action->bytes, receiver)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, + "Buy Ram Bytes", + "Using your %s account, buy %" PRIu32 " bytes of RAM for %s?", + payer, action->bytes, receiver)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8 + 8 + 4; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8 + 8 + 4; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->payer, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->receiver, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->bytes, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->payer, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->receiver, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->bytes, 4); - return true; + return true; } bool eos_compileActionSellRam(const EosActionCommon *common, const EosActionSellRam *action) { - CHECK_COMMON(EOS_SellRam); + CHECK_COMMON(EOS_SellRam); - CHECK_PARAM_RET(action->has_account, "Required field missing", false); - CHECK_PARAM_RET(action->has_bytes, "Required field missing", false); + CHECK_PARAM_RET(action->has_account, "Required field missing", false); + CHECK_PARAM_RET(action->has_bytes, "Required field missing", false); - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->account, account), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->account, account), "Invalid name", + false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Sell Ram", "Using your %s account, sell %" PRIu64 " bytes of RAM at market price?", - account, action->bytes)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Sell Ram", + "Using your %s account, sell %" PRIu64 + " bytes of RAM at market price?", + account, action->bytes)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - uint32_t size = 8 + 8; - eos_hashUInt(&hasher_preimage, size); + uint32_t size = 8 + 8; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->bytes, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->bytes, 8); - return true; + return true; } bool eos_compileActionVoteProducer(const EosActionCommon *common, const EosActionVoteProducer *action) { - CHECK_COMMON(EOS_VoteProducer); - - CHECK_PARAM_RET(action->has_voter, "Required field missing", false); + CHECK_COMMON(EOS_VoteProducer); - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(action->has_voter, "Required field missing", false); - if (action->has_proxy && action->proxy != 0) { - char voter[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->voter, voter), - "Invalid name", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - char proxy[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->proxy, proxy), - "Invalid name", false); + if (action->has_proxy && action->proxy != 0) { + char voter[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->voter, voter), "Invalid name", + false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Vote Producer", "Using your %s account, vote for %s as your proxy?", - voter, proxy)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + char proxy[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->proxy, proxy), "Invalid name", + false); - uint32_t size = 8 + 8 + eos_hashUInt(NULL, 0) + 0; - eos_hashUInt(&hasher_preimage, size); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, + "Vote Producer", + "Using your %s account, vote for %s as your proxy?", voter, + proxy)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - hasher_Update(&hasher_preimage, (const uint8_t*)&action->voter, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->proxy, 8); + uint32_t size = 8 + 8 + eos_hashUInt(NULL, 0) + 0; + eos_hashUInt(&hasher_preimage, size); - eos_hashUInt(&hasher_preimage, /*producers_count=*/0); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->voter, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->proxy, 8); - } else if (action->producers_count != 0) { - // Sanity check, which the contract also enforces - for (size_t i = 1; i < action->producers_count; i++) { - CHECK_PARAM_RET(action->producers[i - 1] < action->producers[i], - "Producer votes must be unique and sorted", false); - } + eos_hashUInt(&hasher_preimage, /*producers_count=*/0); - char voter[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->voter, voter), - "Invalid name", false); + } else if (action->producers_count != 0) { + // Sanity check, which the contract also enforces + for (size_t i = 1; i < action->producers_count; i++) { + CHECK_PARAM_RET(action->producers[i - 1] < action->producers[i], + "Producer votes must be unique and sorted", false); + } - const size_t chunk_size = 6; - char producers[(EOS_NAME_STR_SIZE + 2) * chunk_size + 1]; - const uint8_t pages = (uint8_t)((action->producers_count / chunk_size) + 1) + 1; - - uint8_t page_no = 1; - char title[SMALL_STR_BUF]; - snprintf(title, sizeof(title), - "Vote Producer %" PRIu8 "/%" PRIu8, - page_no, pages); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Using your %s account, vote for the following producers?", - voter)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + char voter[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->voter, voter), "Invalid name", + false); - for (size_t i = 0; i < action->producers_count; i += chunk_size) { - memset(producers, 0, sizeof(producers)); - for (size_t p = 0; p < chunk_size && p + i < action->producers_count; p++) { - char producer[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->producers[p + i], producer), - "Invalid name", false); - (void)strlcat(producers, producer, sizeof(producers)); - if (p + i + 1 != action->producers_count) { - (void)strlcat(producers, ", ", sizeof(producers)); - } - } - - page_no = (uint8_t)((i / chunk_size) + 1) + 1; - snprintf(title, sizeof(title), - "Vote Producer %" PRIu8 "/%" PRIu8, - page_no, pages); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "%s", producers)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } - } + const size_t chunk_size = 6; + char producers[(EOS_NAME_STR_SIZE + 2) * chunk_size + 1]; + const uint8_t pages = + (uint8_t)((action->producers_count / chunk_size) + 1) + 1; - uint32_t size = 8 + 8 + eos_hashUInt(NULL, action->producers_count) + - 8 * action->producers_count; - eos_hashUInt(&hasher_preimage, size); + uint8_t page_no = 1; + char title[SMALL_STR_BUF]; + snprintf(title, sizeof(title), "Vote Producer %" PRIu8 "/%" PRIu8, page_no, + pages); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->voter, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Using your %s account, vote for the following producers?", + voter)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - eos_hashUInt(&hasher_preimage, action->producers_count); - for (size_t p = 0; p < action->producers_count; p++) { - hasher_Update(&hasher_preimage, (const uint8_t*)&action->producers[p], 8); - } - } else { - char voter[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->voter, voter), + for (size_t i = 0; i < action->producers_count; i += chunk_size) { + memset(producers, 0, sizeof(producers)); + for (size_t p = 0; p < chunk_size && p + i < action->producers_count; + p++) { + char producer[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->producers[p + i], producer), "Invalid name", false); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Vote Producer", "Using your %s account, do you want to cancel your vote?", - voter)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; + (void)strlcat(producers, producer, sizeof(producers)); + if (p + i + 1 != action->producers_count) { + (void)strlcat(producers, ", ", sizeof(producers)); } + } + + page_no = (uint8_t)((i / chunk_size) + 1) + 1; + snprintf(title, sizeof(title), "Vote Producer %" PRIu8 "/%" PRIu8, + page_no, pages); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "%s", producers)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + } + + uint32_t size = 8 + 8 + eos_hashUInt(NULL, action->producers_count) + + 8 * action->producers_count; + eos_hashUInt(&hasher_preimage, size); - uint32_t size = 8 + 8 + eos_hashUInt(NULL, 0) + 0; - eos_hashUInt(&hasher_preimage, size); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->voter, 8); + hasher_Update(&hasher_preimage, + (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->voter, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); - eos_hashUInt(&hasher_preimage, /*producers_count=*/0); + eos_hashUInt(&hasher_preimage, action->producers_count); + for (size_t p = 0; p < action->producers_count; p++) { + hasher_Update(&hasher_preimage, (const uint8_t *)&action->producers[p], + 8); } + } else { + char voter[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->voter, voter), "Invalid name", + false); + + if (!confirm( + ButtonRequestType_ButtonRequest_ConfirmEosAction, "Vote Producer", + "Using your %s account, do you want to cancel your vote?", voter)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + + uint32_t size = 8 + 8 + eos_hashUInt(NULL, 0) + 0; + eos_hashUInt(&hasher_preimage, size); - return true; + hasher_Update(&hasher_preimage, (const uint8_t *)&action->voter, 8); + hasher_Update(&hasher_preimage, + (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); + eos_hashUInt(&hasher_preimage, /*producers_count=*/0); + } + + return true; } static size_t eos_hashAuthorization(Hasher *h, const EosAuthorization *auth) { - size_t count = 0; + size_t count = 0; - count += 4; - if (h) hasher_Update(h, (const uint8_t*)&auth->threshold, 4); - - count += eos_hashUInt(h, auth->keys_count); - for (size_t i = 0; i < auth->keys_count; i++) { - const EosAuthorizationKey *auth_key = &auth->keys[i]; - - count += eos_hashUInt(NULL, auth_key->type); - if (h) eos_hashUInt(h, auth_key->type); - - if (auth_key->address_n_count != 0) { - uint8_t public_key[33]; - if (!eos_derivePublicKey(auth_key->address_n, auth_key->address_n_count, - public_key, sizeof(public_key))) { - return 0; - } - - count += sizeof(public_key); - if (h) hasher_Update(h, public_key, sizeof(public_key)); - } else { - count += auth_key->key.size; - if (h) hasher_Update(h, auth_key->key.bytes, auth_key->key.size); - } + count += 4; + if (h) hasher_Update(h, (const uint8_t *)&auth->threshold, 4); - count += 2; - if (h) hasher_Update(h, (const uint8_t*)&auth_key->weight, 2); - } + count += eos_hashUInt(h, auth->keys_count); + for (size_t i = 0; i < auth->keys_count; i++) { + const EosAuthorizationKey *auth_key = &auth->keys[i]; - count += eos_hashUInt(h, auth->accounts_count); - for (size_t i = 0; i < auth->accounts_count; i++) { - count += 8; - if (h) hasher_Update(h, (const uint8_t*)&auth->accounts[i].account.actor, 8); + count += eos_hashUInt(NULL, auth_key->type); + if (h) eos_hashUInt(h, auth_key->type); - count += 8; - if (h) hasher_Update(h, (const uint8_t*)&auth->accounts[i].account.permission, 8); + if (auth_key->address_n_count != 0) { + uint8_t public_key[33]; + if (!eos_derivePublicKey(auth_key->address_n, auth_key->address_n_count, + public_key, sizeof(public_key))) { + return 0; + } - count += 2; - if (h) hasher_Update(h, (const uint8_t*)&auth->accounts[i].weight, 2); + count += sizeof(public_key); + if (h) hasher_Update(h, public_key, sizeof(public_key)); + } else { + count += auth_key->key.size; + if (h) hasher_Update(h, auth_key->key.bytes, auth_key->key.size); } - count += eos_hashUInt(h, auth->waits_count); - for (size_t i = 0; i < auth->accounts_count; i++) { - count += 4; - if (h) hasher_Update(h, (const uint8_t*)&auth->waits[i].wait_sec, 4); + count += 2; + if (h) hasher_Update(h, (const uint8_t *)&auth_key->weight, 2); + } - count += 2; - if (h) hasher_Update(h, (const uint8_t*)&auth->waits[i].weight, 2); - } + count += eos_hashUInt(h, auth->accounts_count); + for (size_t i = 0; i < auth->accounts_count; i++) { + count += 8; + if (h) + hasher_Update(h, (const uint8_t *)&auth->accounts[i].account.actor, 8); + + count += 8; + if (h) + hasher_Update(h, (const uint8_t *)&auth->accounts[i].account.permission, + 8); + + count += 2; + if (h) hasher_Update(h, (const uint8_t *)&auth->accounts[i].weight, 2); + } + + count += eos_hashUInt(h, auth->waits_count); + for (size_t i = 0; i < auth->accounts_count; i++) { + count += 4; + if (h) hasher_Update(h, (const uint8_t *)&auth->waits[i].wait_sec, 4); - return count; + count += 2; + if (h) hasher_Update(h, (const uint8_t *)&auth->waits[i].weight, 2); + } + + return count; } static bool isStandardAuthorization(const EosAuthorization *auth) { - if (!auth->has_threshold || auth->threshold != 1) - return false; + if (!auth->has_threshold || auth->threshold != 1) return false; - if (auth->keys_count != 1) - return false; + if (auth->keys_count != 1) return false; - if (auth->keys[0].key.size != 0) - return false; + if (auth->keys[0].key.size != 0) return false; - if (auth->keys[0].address_n_count == 0) - return false; + if (auth->keys[0].address_n_count == 0) return false; - if (auth->keys[0].weight != 1) - return false; + if (auth->keys[0].weight != 1) return false; - if (auth->waits_count != 0) - return false; + if (auth->waits_count != 0) return false; - return true; + return true; } -static bool confirmStandardAuthorization(const char *title, const EosAuthorization *auth) -{ - char node_str[NODE_STRING_LENGTH]; - const CoinType *coin; - const EosAuthorizationKey *auth_key = &auth->keys[0]; - if ((coin = coinByName("EOS")) && - !bip32_node_to_string(node_str, sizeof(node_str), coin, - auth_key->address_n, - auth_key->address_n_count, - /*whole_account=*/false, - /*show_addridx=*/true) && - !bip32_path_to_string(node_str, sizeof(node_str), - auth_key->address_n, auth_key->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Cannot encode derived pubkey"); - eos_signingAbort(); - layoutHome(); - return false; - } +static bool confirmStandardAuthorization(const char *title, + const EosAuthorization *auth) { + char node_str[NODE_STRING_LENGTH]; + const CoinType *coin; + const EosAuthorizationKey *auth_key = &auth->keys[0]; + if ((coin = coinByName("EOS")) && + !bip32_node_to_string(node_str, sizeof(node_str), coin, + auth_key->address_n, auth_key->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true) && + !bip32_path_to_string(node_str, sizeof(node_str), auth_key->address_n, + auth_key->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Cannot encode derived pubkey"); + eos_signingAbort(); + layoutHome(); + return false; + } + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Do you want to assign signing auth for\n%s to\n%s?", title, + node_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + + return true; +} - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Do you want to assign signing auth for\n%s to\n%s?", - title, node_str)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); +static bool confirmArbitraryAuthorization(const char *title, + const EosAuthorization *auth) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Require an authorization threshold of %" PRIu32 "?", + auth->threshold)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + + for (size_t i = 0; i < auth->keys_count; i++) { + const EosAuthorizationKey *auth_key = &auth->keys[i]; + + CHECK_PARAM_RET(auth_key->has_weight, "Required field missing", false); + CHECK_PARAM_RET( + (auth_key->key.size == 33) ^ (auth_key->address_n_count != 0), + "Required field missing", false); + + char pubkey[MAX(65, NODE_STRING_LENGTH)]; + if (auth_key->key.size != 0) { + if (!eos_publicKeyToWif(auth_key->key.bytes, EosPublicKeyKind_EOS, pubkey, + sizeof(pubkey))) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Cannot encode pubkey"); eos_signingAbort(); layoutHome(); return false; - } - - return true; -} - -static bool confirmArbitraryAuthorization(const char *title, const EosAuthorization *auth) -{ - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Require an authorization threshold of %" PRIu32 "?", - auth->threshold)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + } + } else { + const CoinType *coin; + if ((coin = coinByName("EOS")) && + !bip32_path_to_string(pubkey, sizeof(pubkey), auth_key->address_n, + auth_key->address_n_count)) { + memset(pubkey, 0, sizeof(pubkey)); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Cannot encode derived pubkey"); eos_signingAbort(); layoutHome(); return false; + } } - for (size_t i = 0; i < auth->keys_count; i++) { - const EosAuthorizationKey *auth_key = &auth->keys[i]; - - CHECK_PARAM_RET(auth_key->has_weight, "Required field missing", false); - CHECK_PARAM_RET((auth_key->key.size == 33) ^ (auth_key->address_n_count != 0), - "Required field missing", false); - - char pubkey[MAX(65, NODE_STRING_LENGTH)]; - if (auth_key->key.size != 0) { - if (!eos_publicKeyToWif(auth_key->key.bytes, EosPublicKeyKind_EOS, pubkey, sizeof(pubkey))) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Cannot encode pubkey"); - eos_signingAbort(); - layoutHome(); - return false; - } - } else { - const CoinType *coin; - if ((coin = coinByName("EOS")) && - !bip32_path_to_string(pubkey, sizeof(pubkey), - auth_key->address_n, auth_key->address_n_count)) { - memset(pubkey, 0, sizeof(pubkey)); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Cannot encode derived pubkey"); - eos_signingAbort(); - layoutHome(); - return false; - } - } - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Key #%" PRIu8 ":\n%s\nWeight: %" PRIu16, - (uint8_t)(i + 1), pubkey, (uint16_t)auth_key->weight)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Key #%" PRIu8 ":\n%s\nWeight: %" PRIu16, (uint8_t)(i + 1), + pubkey, (uint16_t)auth_key->weight)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; } + } - for (size_t i = 0; i < auth->accounts_count; i++) { - CHECK_PARAM_RET(auth->accounts[i].account.has_actor, "Required field missing", false); - CHECK_PARAM_RET(auth->accounts[i].account.has_permission, "Required field missing", false); - - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(auth->accounts[i].account.actor, account), - "Invalid name", false); + for (size_t i = 0; i < auth->accounts_count; i++) { + CHECK_PARAM_RET(auth->accounts[i].account.has_actor, + "Required field missing", false); + CHECK_PARAM_RET(auth->accounts[i].account.has_permission, + "Required field missing", false); - char permission[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(auth->accounts[i].account.permission, permission), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(auth->accounts[i].account.actor, account), + "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Account #%" PRIu8 ":\nDo you want to assign %s permission to %s with weight %" PRIu16 "?", - (uint8_t)(i + 1), permission, account, - (uint16_t)auth->accounts[i].weight)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + char permission[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET( + eos_formatName(auth->accounts[i].account.permission, permission), + "Invalid name", false); + + if (!confirm( + ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Account #%" PRIu8 + ":\nDo you want to assign %s permission to %s with weight %" PRIu16 + "?", + (uint8_t)(i + 1), permission, account, + (uint16_t)auth->accounts[i].weight)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; } + } - for (size_t i = 0; i < auth->waits_count; i++) { - CHECK_PARAM_RET(auth->waits[i].has_wait_sec, "Required field missing", false); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "Delay #%" PRIu8 ":\nDo you want to require a delay of %" PRIu32 "s with weight %" PRIu16 "?", - (uint8_t)(i + 1), auth->waits[i].wait_sec, - (uint16_t)auth->waits[i].weight)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + for (size_t i = 0; i < auth->waits_count; i++) { + CHECK_PARAM_RET(auth->waits[i].has_wait_sec, "Required field missing", + false); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Delay #%" PRIu8 + ":\nDo you want to require a delay of %" PRIu32 + "s with weight %" PRIu16 "?", + (uint8_t)(i + 1), auth->waits[i].wait_sec, + (uint16_t)auth->waits[i].weight)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; } + } - return true; + return true; } bool eos_compileAuthorization(const char *title, const EosAuthorization *auth) { - CHECK_PARAM_RET(auth->has_threshold, "Required field missing", false); + CHECK_PARAM_RET(auth->has_threshold, "Required field missing", false); - if (isStandardAuthorization(auth)) { - if (!confirmStandardAuthorization(title, auth)) - return false; - } else { - if (!confirmArbitraryAuthorization(title, auth)) - return false; - } + if (isStandardAuthorization(auth)) { + if (!confirmStandardAuthorization(title, auth)) return false; + } else { + if (!confirmArbitraryAuthorization(title, auth)) return false; + } - if (!eos_hashAuthorization(&hasher_preimage, auth)) - return false; + if (!eos_hashAuthorization(&hasher_preimage, auth)) return false; - return true; + return true; } bool eos_compileActionUpdateAuth(const EosActionCommon *common, const EosActionUpdateAuth *action) { - CHECK_COMMON(EOS_UpdateAuth); + CHECK_COMMON(EOS_UpdateAuth); - CHECK_PARAM_RET(action->has_account, "Required field missing", false); - CHECK_PARAM_RET(action->has_permission, "Required field missing", false); - CHECK_PARAM_RET(action->has_parent, "Required field missing", false); + CHECK_PARAM_RET(action->has_account, "Required field missing", false); + CHECK_PARAM_RET(action->has_permission, "Required field missing", false); + CHECK_PARAM_RET(action->has_parent, "Required field missing", false); - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->account, account), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->account, account), "Invalid name", + false); - char permission[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->permission, permission), - "Invalid name", false); + char permission[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->permission, permission), + "Invalid name", false); - char parent[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->parent, parent), - "Invalid name", false); + char parent[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->parent, parent), "Invalid name", + false); - char title[SMALL_STR_BUF]; - snprintf(title, sizeof(title), "Update Auth: %s", account); + char title[SMALL_STR_BUF]; + snprintf(title, sizeof(title), "Update Auth: %s", account); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, - "Update auth for %s with %s permission and %s parent?", - account, permission, parent)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "Update auth for %s with %s permission and %s parent?", account, + permission, parent)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - size_t auth_size = eos_hashAuthorization(NULL, &action->auth); - CHECK_PARAM_RET(0 < auth_size, "EosAuthorization hash failed", false); + size_t auth_size = eos_hashAuthorization(NULL, &action->auth); + CHECK_PARAM_RET(0 < auth_size, "EosAuthorization hash failed", false); - size_t size = 8 + 8 + 8 + auth_size; - eos_hashUInt(&hasher_preimage, size); + size_t size = 8 + 8 + 8 + auth_size; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->permission, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->parent, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->permission, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->parent, 8); - snprintf(title, sizeof(title), "%s@%s", account, permission); - if (!eos_compileAuthorization(title, &action->auth)) - return false; + snprintf(title, sizeof(title), "%s@%s", account, permission); + if (!eos_compileAuthorization(title, &action->auth)) return false; - return true; + return true; } bool eos_compileActionDeleteAuth(const EosActionCommon *common, const EosActionDeleteAuth *action) { - CHECK_COMMON(EOS_DeleteAuth); + CHECK_COMMON(EOS_DeleteAuth); - CHECK_PARAM_RET(action->has_account, "Required field missing", false); - CHECK_PARAM_RET(action->has_permission, "Required field missing", false); + CHECK_PARAM_RET(action->has_account, "Required field missing", false); + CHECK_PARAM_RET(action->has_permission, "Required field missing", false); - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->account, account), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->account, account), "Invalid name", + false); - char permission[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->permission, permission), - "Invalid name", false); + char permission[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->permission, permission), + "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Delete Auth", "Remove %s permission from %s?", - permission, account)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Delete Auth", + "Remove %s permission from %s?", permission, account)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - size_t size = 8 + 8; - eos_hashUInt(&hasher_preimage, size); + size_t size = 8 + 8; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->permission, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->permission, 8); - return true; + return true; } bool eos_compileActionLinkAuth(const EosActionCommon *common, const EosActionLinkAuth *action) { - CHECK_COMMON(EOS_LinkAuth); + CHECK_COMMON(EOS_LinkAuth); - CHECK_PARAM_RET(action->has_account, "Required field missing", false); - CHECK_PARAM_RET(action->has_code, "Required field missing", false); - CHECK_PARAM_RET(action->has_type, "Required field missing", false); - CHECK_PARAM_RET(action->has_requirement, "Required field missing", false); + CHECK_PARAM_RET(action->has_account, "Required field missing", false); + CHECK_PARAM_RET(action->has_code, "Required field missing", false); + CHECK_PARAM_RET(action->has_type, "Required field missing", false); + CHECK_PARAM_RET(action->has_requirement, "Required field missing", false); - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->account, account), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->account, account), "Invalid name", + false); - char code[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->code, code), - "Invalid name", false); + char code[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->code, code), "Invalid name", false); - char type[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->type, type), - "Invalid name", false); + char type[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->type, type), "Invalid name", false); - char requirement[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->requirement, requirement), - "Invalid name", false); + char requirement[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->requirement, requirement), + "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Link Auth", "Grant %s permission for the %s contract to %s@%s?", - type, code, account, requirement)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Link Auth", + "Grant %s permission for the %s contract to %s@%s?", type, code, + account, requirement)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - size_t size = 8 + 8 + 8 + 8; - eos_hashUInt(&hasher_preimage, size); + size_t size = 8 + 8 + 8 + 8; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->code, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->type, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->requirement, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->code, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->type, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->requirement, 8); - return true; + return true; } bool eos_compileActionUnlinkAuth(const EosActionCommon *common, const EosActionUnlinkAuth *action) { - CHECK_COMMON(EOS_UnlinkAuth); + CHECK_COMMON(EOS_UnlinkAuth); - CHECK_PARAM_RET(action->has_account, "Required field missing", false); - CHECK_PARAM_RET(action->has_code, "Required field missing", false); - CHECK_PARAM_RET(action->has_type, "Required field missing", false); + CHECK_PARAM_RET(action->has_account, "Required field missing", false); + CHECK_PARAM_RET(action->has_code, "Required field missing", false); + CHECK_PARAM_RET(action->has_type, "Required field missing", false); - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->account, account), - "Invalid name", false); + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->account, account), "Invalid name", + false); - char code[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->code, code), - "Invalid name", false); + char code[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->code, code), "Invalid name", false); - char type[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->type, type), - "Invalid name", false); + char type[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->type, type), "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Unlink Auth", "Unlink %s from auth to %s for %s?", - account, code, type)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Unlink Auth", + "Unlink %s from auth to %s for %s?", account, code, type)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - size_t size = 8 + 8 + 8; - eos_hashUInt(&hasher_preimage, size); + size_t size = 8 + 8 + 8; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->code, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->type, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->code, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->type, 8); - return true; + return true; } bool eos_compileActionNewAccount(const EosActionCommon *common, const EosActionNewAccount *action) { - CHECK_COMMON(EOS_NewAccount); + CHECK_COMMON(EOS_NewAccount); - CHECK_PARAM_RET(action->has_creator, "Required field missing", false); - CHECK_PARAM_RET(action->has_name, "Required field missing", false); - CHECK_PARAM_RET(action->has_owner, "Required field missing", false); - CHECK_PARAM_RET(action->has_active, "Required field missing", false); + CHECK_PARAM_RET(action->has_creator, "Required field missing", false); + CHECK_PARAM_RET(action->has_name, "Required field missing", false); + CHECK_PARAM_RET(action->has_owner, "Required field missing", false); + CHECK_PARAM_RET(action->has_active, "Required field missing", false); - char creator[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->creator, creator), - "Invalid name", false); + char creator[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->creator, creator), "Invalid name", + false); - char name[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->name, name), - "Invalid name", false); + char name[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->name, name), "Invalid name", false); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "New Account", "Using your %s account, create a new account named %s?", - creator, name)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "New Account", + "Using your %s account, create a new account named %s?", creator, + name)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - size_t owner_size = eos_hashAuthorization(NULL, &action->owner); - CHECK_PARAM_RET(0 < owner_size, "EosAuthorization hash failed", false); + size_t owner_size = eos_hashAuthorization(NULL, &action->owner); + CHECK_PARAM_RET(0 < owner_size, "EosAuthorization hash failed", false); - size_t active_size = eos_hashAuthorization(NULL, &action->active); - CHECK_PARAM_RET(0 < active_size, "EosAuthorization hash failed", false); + size_t active_size = eos_hashAuthorization(NULL, &action->active); + CHECK_PARAM_RET(0 < active_size, "EosAuthorization hash failed", false); - size_t size = 8 + 8 + owner_size + active_size; - eos_hashUInt(&hasher_preimage, size); + size_t size = 8 + 8 + owner_size + active_size; + eos_hashUInt(&hasher_preimage, size); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->creator, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->name, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->creator, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->name, 8); - char title[SMALL_STR_BUF]; - snprintf(title, sizeof(title), "%s@owner", name); - if (!eos_compileAuthorization(title, &action->owner)) - return false; + char title[SMALL_STR_BUF]; + snprintf(title, sizeof(title), "%s@owner", name); + if (!eos_compileAuthorization(title, &action->owner)) return false; - snprintf(title, sizeof(title), "%s@active", name); - if (!eos_compileAuthorization(title, &action->active)) - return false; + snprintf(title, sizeof(title), "%s@active", name); + if (!eos_compileAuthorization(title, &action->active)) return false; - return true; + return true; } diff --git a/lib/firmware/eos-contracts/eosio.token.c b/lib/firmware/eos-contracts/eosio.token.c index 06e7bdd1c..3cd1ec2d9 100644 --- a/lib/firmware/eos-contracts/eosio.token.c +++ b/lib/firmware/eos-contracts/eosio.token.c @@ -34,78 +34,77 @@ #include #include -#define CHECK_COMMON(ACTION) \ - do { \ - CHECK_PARAM_RET(common->account == EOS_eosio_token, \ - "Incorrect account name", false); \ - CHECK_PARAM_RET(common->name == (ACTION), \ - "Incorrect action name", false); \ - } while(0) +#define CHECK_COMMON(ACTION) \ + do { \ + CHECK_PARAM_RET(common->account == EOS_eosio_token, \ + "Incorrect account name", false); \ + CHECK_PARAM_RET(common->name == (ACTION), "Incorrect action name", false); \ + } while (0) bool eos_compileActionTransfer(const EosActionCommon *common, const EosActionTransfer *action) { - CHECK_COMMON(EOS_Transfer); - - CHECK_PARAM_RET(action->has_quantity, "Required field missing", false); - CHECK_PARAM_RET(action->has_sender, "Required field missing", false); - CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); - CHECK_PARAM_RET(action->has_memo, "Required field missing", false); - - size_t memo_len = strlen(action->memo); - - if (256 < memo_len) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Memo too long"); - eos_signingAbort(); - layoutHome(); - return false; - } - - char asset[EOS_ASSET_STR_SIZE]; - CHECK_PARAM_RET(eos_formatAsset(&action->quantity, asset), - "Invalid asset format", false); - - char sender[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->sender, sender), - "Invalid name", false); - - char receiver[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), - "Invalid name", false); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - "Transfer", "Do you want to send %s from %s to %s?", - asset, sender, receiver)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } - - char title[MEDIUM_STR_BUF]; - snprintf(title, sizeof(title), "Confirm Memo (%" PRIu32 " bytes)", (uint32_t)memo_len); - if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmMemo, - title, (const uint8_t*)action->memo, memo_len)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } - - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); - - uint32_t size = 8 + 8 + 16 + eos_hashUInt(NULL, memo_len) + memo_len; - eos_hashUInt(&hasher_preimage, size); - - hasher_Update(&hasher_preimage, (const uint8_t*)&action->sender, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&action->receiver, 8); - - CHECK_PARAM_RET(eos_compileAsset(&action->quantity), - "Cannot compile asset: quantity", false); - - eos_hashUInt(&hasher_preimage, memo_len); - hasher_Update(&hasher_preimage, (const uint8_t*)action->memo, memo_len); - - return true; + CHECK_COMMON(EOS_Transfer); + + CHECK_PARAM_RET(action->has_quantity, "Required field missing", false); + CHECK_PARAM_RET(action->has_sender, "Required field missing", false); + CHECK_PARAM_RET(action->has_receiver, "Required field missing", false); + CHECK_PARAM_RET(action->has_memo, "Required field missing", false); + + size_t memo_len = strlen(action->memo); + + if (256 < memo_len) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Memo too long"); + eos_signingAbort(); + layoutHome(); + return false; + } + + char asset[EOS_ASSET_STR_SIZE]; + CHECK_PARAM_RET(eos_formatAsset(&action->quantity, asset), + "Invalid asset format", false); + + char sender[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->sender, sender), "Invalid name", + false); + + char receiver[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(action->receiver, receiver), "Invalid name", + false); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, "Transfer", + "Do you want to send %s from %s to %s?", asset, sender, + receiver)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + + char title[MEDIUM_STR_BUF]; + snprintf(title, sizeof(title), "Confirm Memo (%" PRIu32 " bytes)", + (uint32_t)memo_len); + if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmMemo, title, + (const uint8_t *)action->memo, memo_len)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; + } + + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); + + uint32_t size = 8 + 8 + 16 + eos_hashUInt(NULL, memo_len) + memo_len; + eos_hashUInt(&hasher_preimage, size); + + hasher_Update(&hasher_preimage, (const uint8_t *)&action->sender, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&action->receiver, 8); + + CHECK_PARAM_RET(eos_compileAsset(&action->quantity), + "Cannot compile asset: quantity", false); + + eos_hashUInt(&hasher_preimage, memo_len); + hasher_Update(&hasher_preimage, (const uint8_t *)action->memo, memo_len); + + return true; } - diff --git a/lib/firmware/eos.c b/lib/firmware/eos.c index ce6c9ded1..f3c0cce80 100644 --- a/lib/firmware/eos.c +++ b/lib/firmware/eos.c @@ -52,472 +52,533 @@ static uint32_t unknown_total = 0; static uint32_t unknown_remaining = 0; bool eos_formatAsset(const EosAsset *asset, char str[EOS_ASSET_STR_SIZE]) { - memset(str, 0, EOS_ASSET_STR_SIZE); - char *s = str; - uint64_t v = (uint64_t)asset->amount; - - // Sign - if (asset->amount < 0) { *s++ = '-'; v = ~v + 1; } - - // Value. Precision stored in low 8 bits - uint8_t p = asset->symbol & 0xff; - if (v >= 10000000000000000000ULL || p >= 19) { *s++ = '0' + v / 10000000000000000000ULL % 10; } - if ( p == 19) { *s++ = '.'; } - if (v >= 1000000000000000000ULL || p >= 18) { *s++ = '0' + v / 1000000000000000000ULL % 10; } - if ( p == 18) { *s++ = '.'; } - if (v >= 100000000000000000ULL || p >= 17) { *s++ = '0' + v / 100000000000000000ULL % 10; } - if ( p == 17) { *s++ = '.'; } - if (v >= 10000000000000000ULL || p >= 16) { *s++ = '0' + v / 10000000000000000ULL % 10; } - if ( p == 16) { *s++ = '.'; } - if (v >= 1000000000000000ULL || p >= 15) { *s++ = '0' + v / 1000000000000000ULL % 10; } - if ( p == 15) { *s++ = '.'; } - if (v >= 100000000000000ULL || p >= 14) { *s++ = '0' + v / 100000000000000ULL % 10; } - if ( p == 14) { *s++ = '.'; } - if (v >= 10000000000000ULL || p >= 13) { *s++ = '0' + v / 10000000000000ULL % 10; } - if ( p == 13) { *s++ = '.'; } - if (v >= 1000000000000ULL || p >= 12) { *s++ = '0' + v / 1000000000000ULL % 10; } - if ( p == 12) { *s++ = '.'; } - if (v >= 100000000000ULL || p >= 11) { *s++ = '0' + v / 100000000000ULL % 10; } - if ( p == 11) { *s++ = '.'; } - if (v >= 10000000000ULL || p >= 10) { *s++ = '0' + v / 10000000000ULL % 10; } - if ( p == 10) { *s++ = '.'; } - if (v >= 1000000000ULL || p >= 9) { *s++ = '0' + v / 1000000000ULL % 10; } - if ( p == 9) { *s++ = '.'; } - if (v >= 100000000ULL || p >= 8) { *s++ = '0' + v / 100000000ULL % 10; } - if ( p == 8) { *s++ = '.'; } - if (v >= 10000000ULL || p >= 7) { *s++ = '0' + v / 10000000ULL % 10; } - if ( p == 7) { *s++ = '.'; } - if (v >= 1000000ULL || p >= 6) { *s++ = '0' + v / 1000000ULL % 10; } - if ( p == 6) { *s++ = '.'; } - if (v >= 100000ULL || p >= 5) { *s++ = '0' + v / 100000ULL % 10; } - if ( p == 5) { *s++ = '.'; } - if (v >= 10000ULL || p >= 4) { *s++ = '0' + v / 10000ULL % 10; } - if ( p == 4) { *s++ = '.'; } - if (v >= 1000ULL || p >= 3) { *s++ = '0' + v / 1000ULL % 10; } - if ( p == 3) { *s++ = '.'; } - if (v >= 100ULL || p >= 2) { *s++ = '0' + v / 100ULL % 10; } - if ( p == 2) { *s++ = '.'; } - if (v >= 10ULL || p >= 1) { *s++ = '0' + v / 10ULL % 10; } - if ( p == 1) { *s++ = '.'; } - *s++ = '0' + v % 10; - *s++ = ' '; - - // Symbol - for (int i = 0; i < 7; i++) { - char c = (char)((asset->symbol >> (i+1)*8) & 0xff); - if (!('A' <= c && c <= 'Z') && c != 0) { - memset(str, 0, EOS_ASSET_STR_SIZE); - return false; // Invalid symbol - } - *s++ = c; + memset(str, 0, EOS_ASSET_STR_SIZE); + char *s = str; + uint64_t v = (uint64_t)asset->amount; + + // Sign + if (asset->amount < 0) { + *s++ = '-'; + v = ~v + 1; + } + + // Value. Precision stored in low 8 bits + uint8_t p = asset->symbol & 0xff; + if (v >= 10000000000000000000ULL || p >= 19) { + *s++ = '0' + v / 10000000000000000000ULL % 10; + } + if (p == 19) { + *s++ = '.'; + } + if (v >= 1000000000000000000ULL || p >= 18) { + *s++ = '0' + v / 1000000000000000000ULL % 10; + } + if (p == 18) { + *s++ = '.'; + } + if (v >= 100000000000000000ULL || p >= 17) { + *s++ = '0' + v / 100000000000000000ULL % 10; + } + if (p == 17) { + *s++ = '.'; + } + if (v >= 10000000000000000ULL || p >= 16) { + *s++ = '0' + v / 10000000000000000ULL % 10; + } + if (p == 16) { + *s++ = '.'; + } + if (v >= 1000000000000000ULL || p >= 15) { + *s++ = '0' + v / 1000000000000000ULL % 10; + } + if (p == 15) { + *s++ = '.'; + } + if (v >= 100000000000000ULL || p >= 14) { + *s++ = '0' + v / 100000000000000ULL % 10; + } + if (p == 14) { + *s++ = '.'; + } + if (v >= 10000000000000ULL || p >= 13) { + *s++ = '0' + v / 10000000000000ULL % 10; + } + if (p == 13) { + *s++ = '.'; + } + if (v >= 1000000000000ULL || p >= 12) { + *s++ = '0' + v / 1000000000000ULL % 10; + } + if (p == 12) { + *s++ = '.'; + } + if (v >= 100000000000ULL || p >= 11) { + *s++ = '0' + v / 100000000000ULL % 10; + } + if (p == 11) { + *s++ = '.'; + } + if (v >= 10000000000ULL || p >= 10) { + *s++ = '0' + v / 10000000000ULL % 10; + } + if (p == 10) { + *s++ = '.'; + } + if (v >= 1000000000ULL || p >= 9) { + *s++ = '0' + v / 1000000000ULL % 10; + } + if (p == 9) { + *s++ = '.'; + } + if (v >= 100000000ULL || p >= 8) { + *s++ = '0' + v / 100000000ULL % 10; + } + if (p == 8) { + *s++ = '.'; + } + if (v >= 10000000ULL || p >= 7) { + *s++ = '0' + v / 10000000ULL % 10; + } + if (p == 7) { + *s++ = '.'; + } + if (v >= 1000000ULL || p >= 6) { + *s++ = '0' + v / 1000000ULL % 10; + } + if (p == 6) { + *s++ = '.'; + } + if (v >= 100000ULL || p >= 5) { + *s++ = '0' + v / 100000ULL % 10; + } + if (p == 5) { + *s++ = '.'; + } + if (v >= 10000ULL || p >= 4) { + *s++ = '0' + v / 10000ULL % 10; + } + if (p == 4) { + *s++ = '.'; + } + if (v >= 1000ULL || p >= 3) { + *s++ = '0' + v / 1000ULL % 10; + } + if (p == 3) { + *s++ = '.'; + } + if (v >= 100ULL || p >= 2) { + *s++ = '0' + v / 100ULL % 10; + } + if (p == 2) { + *s++ = '.'; + } + if (v >= 10ULL || p >= 1) { + *s++ = '0' + v / 10ULL % 10; + } + if (p == 1) { + *s++ = '.'; + } + *s++ = '0' + v % 10; + *s++ = ' '; + + // Symbol + for (int i = 0; i < 7; i++) { + char c = (char)((asset->symbol >> (i + 1) * 8) & 0xff); + if (!('A' <= c && c <= 'Z') && c != 0) { + memset(str, 0, EOS_ASSET_STR_SIZE); + return false; // Invalid symbol } + *s++ = c; + } - return true; + return true; } /// Ported from EOSIO libraries/chain/name.cpp bool eos_formatName(uint64_t name, char str[EOS_NAME_STR_SIZE]) { - memset(str, '.', EOS_NAME_STR_SIZE); - static const char *charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - - uint64_t tmp = name; - for (uint32_t i = 0; i <= 12; ++i) { - char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)]; - str[12-i] = c; - tmp >>= (i == 0 ? 4 : 5); - } - - for (int i = 1; i <= EOS_NAME_STR_SIZE; i++) { - if (str[EOS_NAME_STR_SIZE - i] != '.') - break; - str[EOS_NAME_STR_SIZE - i] = '\0'; - } - - return true; + memset(str, '.', EOS_NAME_STR_SIZE); + static const char *charmap = ".12345abcdefghijklmnopqrstuvwxyz"; + + uint64_t tmp = name; + for (uint32_t i = 0; i <= 12; ++i) { + char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)]; + str[12 - i] = c; + tmp >>= (i == 0 ? 4 : 5); + } + + for (int i = 1; i <= EOS_NAME_STR_SIZE; i++) { + if (str[EOS_NAME_STR_SIZE - i] != '.') break; + str[EOS_NAME_STR_SIZE - i] = '\0'; + } + + return true; } bool eos_derivePublicKey(const uint32_t *addr_n, size_t addr_n_count, uint8_t *public_key, size_t len) { - if (len < sizeof(node.public_key)) - return false; + if (len < sizeof(node.public_key)) return false; - if (!eos_signingIsInited()) - return false; + if (!eos_signingIsInited()) return false; - memcpy(&node, &root, sizeof(node)); - if (hdnode_private_ckd_cached(&node, addr_n, addr_n_count, NULL) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Child key derivation failed"); - eos_signingAbort(); - return false; - } + memcpy(&node, &root, sizeof(node)); + if (hdnode_private_ckd_cached(&node, addr_n, addr_n_count, NULL) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Child key derivation failed"); + eos_signingAbort(); + return false; + } - hdnode_fill_public_key(&node); - memcpy(public_key, node.public_key, sizeof(node.public_key)); - memzero(&node, sizeof(node)); - return true; + hdnode_fill_public_key(&node); + memcpy(public_key, node.public_key, sizeof(node.public_key)); + memzero(&node, sizeof(node)); + return true; } -bool eos_getPublicKey(const HDNode *n, const curve_info *curve, EosPublicKeyKind kind, - char *pubkey, size_t len) { - (void)curve; - return eos_publicKeyToWif(n->public_key, kind, pubkey, len); +bool eos_getPublicKey(const HDNode *n, const curve_info *curve, + EosPublicKeyKind kind, char *pubkey, size_t len) { + (void)curve; + return eos_publicKeyToWif(n->public_key, kind, pubkey, len); } -bool eos_publicKeyToWif(const uint8_t *public_key, EosPublicKeyKind kind, char *pubkey, size_t len) { - const char *prefix = ""; - switch (kind) { - case EosPublicKeyKind_EOS: prefix = "EOS"; break; - case EosPublicKeyKind_EOS_K1: prefix = "EOS_K1_"; break; - case EosPublicKeyKind_EOS_R1: return false; - default: return false; - } - - const size_t prefix_len = strlen(prefix); - strlcpy(pubkey, prefix, len); - - if (!base58_encode_check(public_key, 33, HASHER_RIPEMD, - pubkey + prefix_len, - len - prefix_len)) { - return false; - } +bool eos_publicKeyToWif(const uint8_t *public_key, EosPublicKeyKind kind, + char *pubkey, size_t len) { + const char *prefix = ""; + switch (kind) { + case EosPublicKeyKind_EOS: + prefix = "EOS"; + break; + case EosPublicKeyKind_EOS_K1: + prefix = "EOS_K1_"; + break; + case EosPublicKeyKind_EOS_R1: + return false; + default: + return false; + } + + const size_t prefix_len = strlen(prefix); + strlcpy(pubkey, prefix, len); + + if (!base58_encode_check(public_key, 33, HASHER_RIPEMD, pubkey + prefix_len, + len - prefix_len)) { + return false; + } - return true; + return true; } // https://github.com/EOSIO/fc/blob/30eb81c1d995f9cd9834701e03b83ec7e6468a0f/include/fc/io/raw.hpp#L214 size_t eos_hashUInt(Hasher *hasher, uint64_t val) { - size_t count = 0; - do { - uint8_t b = ((uint8_t)val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - count++; - if (hasher) hasher_Update(hasher, &b, 1); - } while (val); - return count; + size_t count = 0; + do { + uint8_t b = ((uint8_t)val) & 0x7f; + val >>= 7; + b |= ((val > 0) << 7); + count++; + if (hasher) hasher_Update(hasher, &b, 1); + } while (val); + return count; } void eos_signingInit(const uint8_t *chain_id, uint32_t num_actions, const EosTxHeader *_header, const HDNode *_root, const uint32_t _address_n[8], size_t _address_n_count) { - hasher_Init(&hasher_preimage, HASHER_SHA2); - - memcpy(&header, _header, sizeof(header)); - memzero(&node, sizeof(node)); - memcpy(&root, _root, sizeof(root)); - memcpy(address_n, _address_n, sizeof(address_n)); - address_n_count = _address_n_count; - - hasher_Update(&hasher_preimage, chain_id, 32); - hasher_Update(&hasher_preimage, (const uint8_t*)&header.expiration, 4); - hasher_Update(&hasher_preimage, (const uint8_t*)&header.ref_block_num, 2); - hasher_Update(&hasher_preimage, (const uint8_t*)&header.ref_block_prefix, 4); - eos_hashUInt(&hasher_preimage, header.max_net_usage_words); - hasher_Update(&hasher_preimage, (const uint8_t*)&header.max_cpu_usage_ms, 1); - eos_hashUInt(&hasher_preimage, header.delay_sec); - - // context_free_actions. count, followed by each action - eos_hashUInt(&hasher_preimage, 0); - - // actions. count, followed by each action - eos_hashUInt(&hasher_preimage, num_actions); - - unknown_remaining = 0; - unknown_total = 0; - hasher_Init(&hasher_unknown, HASHER_SHA2); - - actions_remaining = num_actions; - inited = true; + hasher_Init(&hasher_preimage, HASHER_SHA2); + + memcpy(&header, _header, sizeof(header)); + memzero(&node, sizeof(node)); + memcpy(&root, _root, sizeof(root)); + memcpy(address_n, _address_n, sizeof(address_n)); + address_n_count = _address_n_count; + + hasher_Update(&hasher_preimage, chain_id, 32); + hasher_Update(&hasher_preimage, (const uint8_t *)&header.expiration, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&header.ref_block_num, 2); + hasher_Update(&hasher_preimage, (const uint8_t *)&header.ref_block_prefix, 4); + eos_hashUInt(&hasher_preimage, header.max_net_usage_words); + hasher_Update(&hasher_preimage, (const uint8_t *)&header.max_cpu_usage_ms, 1); + eos_hashUInt(&hasher_preimage, header.delay_sec); + + // context_free_actions. count, followed by each action + eos_hashUInt(&hasher_preimage, 0); + + // actions. count, followed by each action + eos_hashUInt(&hasher_preimage, num_actions); + + unknown_remaining = 0; + unknown_total = 0; + hasher_Init(&hasher_unknown, HASHER_SHA2); + + actions_remaining = num_actions; + inited = true; } -bool eos_signingIsInited(void) { - return inited; -} +bool eos_signingIsInited(void) { return inited; } bool eos_signingIsFinished(void) { - return inited && actions_remaining == 0 && unknown_remaining == 0; + return inited && actions_remaining == 0 && unknown_remaining == 0; } -uint32_t eos_actionsRemaining(void) { - return actions_remaining; -} +uint32_t eos_actionsRemaining(void) { return actions_remaining; } void eos_signingAbort(void) { - inited = false; - memzero(&hasher_preimage, sizeof(hasher_preimage)); - memzero(&hasher_unknown, sizeof(hasher_unknown)); - memzero(&header, sizeof(header)); - memzero(&node, sizeof(node)); - memzero(&root, sizeof(root)); - memzero(address_n, sizeof(address_n)); - address_n_count = 0; - actions_remaining = 0; - unknown_remaining = 0; - unknown_total = 0; + inited = false; + memzero(&hasher_preimage, sizeof(hasher_preimage)); + memzero(&hasher_unknown, sizeof(hasher_unknown)); + memzero(&header, sizeof(header)); + memzero(&node, sizeof(node)); + memzero(&root, sizeof(root)); + memzero(address_n, sizeof(address_n)); + address_n_count = 0; + actions_remaining = 0; + unknown_remaining = 0; + unknown_total = 0; } bool eos_compileAsset(const EosAsset *asset) { - if (!asset->has_amount) - return false; + if (!asset->has_amount) return false; - if (!asset->has_symbol) - return false; + if (!asset->has_symbol) return false; - hasher_Update(&hasher_preimage, (const uint8_t*)&asset->amount, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&asset->symbol, 8); - return true; + hasher_Update(&hasher_preimage, (const uint8_t *)&asset->amount, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&asset->symbol, 8); + return true; } bool eos_compileString(const char *str) { - if (!str) - return false; - uint32_t len = strlen(str); - eos_hashUInt(&hasher_preimage, len); - if (len) - hasher_Update(&hasher_preimage, (const uint8_t*)str, len); - return true; + if (!str) return false; + uint32_t len = strlen(str); + eos_hashUInt(&hasher_preimage, len); + if (len) hasher_Update(&hasher_preimage, (const uint8_t *)str, len); + return true; } bool eos_compileActionCommon(const EosActionCommon *common) { - if (!(actions_remaining--)) - return false; + if (!(actions_remaining--)) return false; - if (!common->has_account) - return false; + if (!common->has_account) return false; - if (!common->has_name) - return false; + if (!common->has_name) return false; - if (!common->authorization_count) - return false; + if (!common->authorization_count) return false; - hasher_Update(&hasher_preimage, (const uint8_t*)&common->account, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&common->name, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&common->account, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&common->name, 8); - eos_hashUInt(&hasher_preimage, common->authorization_count); - for (size_t i = 0; i < common->authorization_count; i++) { - if (!eos_compilePermissionLevel(&common->authorization[i])) - return false; - } + eos_hashUInt(&hasher_preimage, common->authorization_count); + for (size_t i = 0; i < common->authorization_count; i++) { + if (!eos_compilePermissionLevel(&common->authorization[i])) return false; + } - return true; + return true; } bool eos_compilePermissionLevel(const EosPermissionLevel *auth) { - if (!auth->has_actor) - return false; + if (!auth->has_actor) return false; - if (!auth->has_permission) - return false; + if (!auth->has_permission) return false; - hasher_Update(&hasher_preimage, (const uint8_t*)&auth->actor, 8); - hasher_Update(&hasher_preimage, (const uint8_t*)&auth->permission, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&auth->actor, 8); + hasher_Update(&hasher_preimage, (const uint8_t *)&auth->permission, 8); - return true; + return true; } -bool eos_hasActionUnknownDataRemaining(void) { - return 0 < unknown_remaining; -} +bool eos_hasActionUnknownDataRemaining(void) { return 0 < unknown_remaining; } static bool isSupportedAction(const EosActionCommon *common) { - if (common->account == EOS_eosio || - common->account == EOS_eosio_token) { - switch (common->name) { - case EOS_Transfer: - case EOS_Owner: - case EOS_Active: - case EOS_DelegateBW: - case EOS_UndelegateBW: - case EOS_Refund: - case EOS_BuyRam: - case EOS_BuyRamBytes: - case EOS_SellRam: - case EOS_VoteProducer: - case EOS_UpdateAuth: - case EOS_DeleteAuth: - case EOS_LinkAuth: - case EOS_UnlinkAuth: - return true; - } + if (common->account == EOS_eosio || common->account == EOS_eosio_token) { + switch (common->name) { + case EOS_Transfer: + case EOS_Owner: + case EOS_Active: + case EOS_DelegateBW: + case EOS_UndelegateBW: + case EOS_Refund: + case EOS_BuyRam: + case EOS_BuyRamBytes: + case EOS_SellRam: + case EOS_VoteProducer: + case EOS_UpdateAuth: + case EOS_DeleteAuth: + case EOS_LinkAuth: + case EOS_UnlinkAuth: + return true; } - return false; + } + return false; } bool eos_compileActionUnknown(const EosActionCommon *common, const EosActionUnknown *action) { - if (isSupportedAction(common)) { - fsm_sendFailure(FailureType_Failure_SyntaxError, - "EosActionUnknown cannot be used with supported contract actions"); - eos_signingAbort(); - return false; - } - - if (!storage_isPolicyEnabled("AdvancedMode")) { - (void)review(ButtonRequestType_ButtonRequest_Other, "Warning", - "Signing of arbitrary EOS actions is recommended only for " - "experienced users. Enable 'AdvancedMode' policy to dismiss."); - } + if (isSupportedAction(common)) { + fsm_sendFailure( + FailureType_Failure_SyntaxError, + "EosActionUnknown cannot be used with supported contract actions"); + eos_signingAbort(); + return false; + } - if (unknown_remaining == 0) { - CHECK_PARAM_RET(eos_compileActionCommon(common), - "Cannot compile ActionCommon", false); + if (!storage_isPolicyEnabled("AdvancedMode")) { + (void)review(ButtonRequestType_ButtonRequest_Other, "Warning", + "Signing of arbitrary EOS actions is recommended only for " + "experienced users. Enable 'AdvancedMode' policy to dismiss."); + } - hasher_Init(&hasher_unknown, HASHER_SHA2); + if (unknown_remaining == 0) { + CHECK_PARAM_RET(eos_compileActionCommon(common), + "Cannot compile ActionCommon", false); - unknown_total = unknown_remaining = action->data_size; - eos_hashUInt(&hasher_preimage, action->data_size); - } else if (action->data_size != unknown_total) { - fsm_sendFailure(FailureType_Failure_SyntaxError, - "EosActionUnknown unexpected change in total length"); - eos_signingAbort(); - layoutHome(); - return false; - } + hasher_Init(&hasher_unknown, HASHER_SHA2); - if (unknown_remaining < action->data_chunk.size) { - fsm_sendFailure(FailureType_Failure_SyntaxError, - "EosActionUnknown unexpected data chunk size"); - eos_signingAbort(); - layoutHome(); - return false; - } + unknown_total = unknown_remaining = action->data_size; + eos_hashUInt(&hasher_preimage, action->data_size); + } else if (action->data_size != unknown_total) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "EosActionUnknown unexpected change in total length"); + eos_signingAbort(); + layoutHome(); + return false; + } - hasher_Update(&hasher_unknown, (const uint8_t*)action->data_chunk.bytes, - action->data_chunk.size); - hasher_Update(&hasher_preimage, (const uint8_t*)action->data_chunk.bytes, - action->data_chunk.size); - unknown_remaining -= action->data_chunk.size; - - if (unknown_remaining == 0) { - char name[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(common->name, name), - "Invalid name", false); - - char account[EOS_NAME_STR_SIZE]; - CHECK_PARAM_RET(eos_formatName(common->account, account), - "Invalid name", false); - - char title[MEDIUM_STR_BUF]; - snprintf(title, sizeof(title), "%s:%s", account, name); - - static uint8_t hash[32]; - hasher_Final(&hasher_unknown, hash); - - char hex[2][16 * 2 + 1]; - data2hex(hash, 16, hex[0]); - data2hex(hash + 16, 16, hex[1]); - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, - title, "%" PRIu32 " bytes with fingerprint:\n%s\n%s", unknown_total, hex[0], hex[1])) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Action Cancelled"); - eos_signingAbort(); - layoutHome(); - return false; - } + if (unknown_remaining < action->data_chunk.size) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "EosActionUnknown unexpected data chunk size"); + eos_signingAbort(); + layoutHome(); + return false; + } + + hasher_Update(&hasher_unknown, (const uint8_t *)action->data_chunk.bytes, + action->data_chunk.size); + hasher_Update(&hasher_preimage, (const uint8_t *)action->data_chunk.bytes, + action->data_chunk.size); + unknown_remaining -= action->data_chunk.size; + + if (unknown_remaining == 0) { + char name[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(common->name, name), "Invalid name", false); + + char account[EOS_NAME_STR_SIZE]; + CHECK_PARAM_RET(eos_formatName(common->account, account), "Invalid name", + false); + + char title[MEDIUM_STR_BUF]; + snprintf(title, sizeof(title), "%s:%s", account, name); + + static uint8_t hash[32]; + hasher_Final(&hasher_unknown, hash); + + char hex[2][16 * 2 + 1]; + data2hex(hash, 16, hex[0]); + data2hex(hash + 16, 16, hex[1]); + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosAction, title, + "%" PRIu32 " bytes with fingerprint:\n%s\n%s", unknown_total, + hex[0], hex[1])) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + layoutHome(); + return false; } + } - return true; + return true; } static int eos_is_canonic(uint8_t v, uint8_t signature[64]) { - (void) v; - return !(signature[0] & 0x80) - && !(signature[0] == 0 && !(signature[1] & 0x80)) - && !(signature[32] & 0x80) - && !(signature[32] == 0 && !(signature[33] & 0x80)); + (void)v; + return !(signature[0] & 0x80) && + !(signature[0] == 0 && !(signature[1] & 0x80)) && + !(signature[32] & 0x80) && + !(signature[32] == 0 && !(signature[33] & 0x80)); } bool eos_signTx(EosSignedTx *tx) { - memzero(tx, sizeof(*tx)); + memzero(tx, sizeof(*tx)); - if (!eos_signingIsInited()) { - fsm_sendFailure(FailureType_Failure_Other, "Must call EosSignTx first"); - eos_signingAbort(); - return false; - } + if (!eos_signingIsInited()) { + fsm_sendFailure(FailureType_Failure_Other, "Must call EosSignTx first"); + eos_signingAbort(); + return false; + } - // transaction_extensions. count, followed by data - eos_hashUInt(&hasher_preimage, 0); + // transaction_extensions. count, followed by data + eos_hashUInt(&hasher_preimage, 0); - // context_free_data. if nonempty, the sha256 digest of it. otherwise: - hasher_Update(&hasher_preimage, (const uint8_t*) + // context_free_data. if nonempty, the sha256 digest of it. otherwise: + hasher_Update(&hasher_preimage, (const uint8_t*) "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00", 32); - char ram_limit[8 + 5 + 14 + 1] = "Unlimited RAM"; - if (header.max_net_usage_words) { - snprintf(ram_limit, sizeof(ram_limit), "At most %" PRIu16 " bytes RAM", - (uint16_t)header.max_net_usage_words); - } - - char cpu_limit[8 + 5 + 11 + 1] = "Unlimited CPU"; - if (header.max_cpu_usage_ms) { - snprintf(cpu_limit, sizeof(cpu_limit), "At most %" PRIu8 " ms CPU", - (uint8_t)header.max_cpu_usage_ms); - } - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosBudget, - "Confirm Budget", - "You may be billed for up to:\n%s\n%s", - ram_limit, cpu_limit)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - return false; - } - - time_t expiry = header.expiration; - char expiry_str[26]; - asctime_r(gmtime(&expiry), expiry_str); - expiry_str[24] = 0; // cut off the '\n' - uint32_t delay = header.delay_sec; - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, - "Sign Transaction", - "Do you want to sign this EOS transaction?\n" - "Expiry: %s UTC\n" - "Delay: %" PRIu32 "h%02" PRIu32 "m%02" PRIu32 "s", - expiry_str, - delay / 3600, (delay / 60) % 60, (delay % 60))) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); - eos_signingAbort(); - return false; - } - - tx->has_hash = true; - tx->hash.size = 32; - hasher_Final(&hasher_preimage, tx->hash.bytes); + char ram_limit[8 + 5 + 14 + 1] = "Unlimited RAM"; + if (header.max_net_usage_words) { + snprintf(ram_limit, sizeof(ram_limit), "At most %" PRIu16 " bytes RAM", + (uint16_t)header.max_net_usage_words); + } + + char cpu_limit[8 + 5 + 11 + 1] = "Unlimited CPU"; + if (header.max_cpu_usage_ms) { + snprintf(cpu_limit, sizeof(cpu_limit), "At most %" PRIu8 " ms CPU", + (uint8_t)header.max_cpu_usage_ms); + } + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmEosBudget, + "Confirm Budget", "You may be billed for up to:\n%s\n%s", + ram_limit, cpu_limit)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + return false; + } + + time_t expiry = header.expiration; + char expiry_str[26]; + asctime_r(gmtime(&expiry), expiry_str); + expiry_str[24] = 0; // cut off the '\n' + uint32_t delay = header.delay_sec; + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Sign Transaction", + "Do you want to sign this EOS transaction?\n" + "Expiry: %s UTC\n" + "Delay: %" PRIu32 "h%02" PRIu32 "m%02" PRIu32 "s", + expiry_str, delay / 3600, (delay / 60) % 60, (delay % 60))) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action Cancelled"); + eos_signingAbort(); + return false; + } - memcpy(&node, &root, sizeof(node)); - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Child key derivation failed"); - eos_signingAbort(); - return false; - } + tx->has_hash = true; + tx->hash.size = 32; + hasher_Final(&hasher_preimage, tx->hash.bytes); - uint8_t sig[64]; - uint8_t pby; - if (ecdsa_sign_digest(&secp256k1, node.private_key, tx->hash.bytes, sig, &pby, - eos_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); - eos_signingAbort(); - return false; - } - memzero(&node, sizeof(node)); - memzero(&root, sizeof(root)); + memcpy(&node, &root, sizeof(node)); + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Child key derivation failed"); + eos_signingAbort(); + return false; + } + + uint8_t sig[64]; + uint8_t pby; + if (ecdsa_sign_digest(&secp256k1, node.private_key, tx->hash.bytes, sig, &pby, + eos_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + eos_signingAbort(); + return false; + } + memzero(&node, sizeof(node)); + memzero(&root, sizeof(root)); - tx->has_signature_v = true; - tx->signature_v = 27 + pby + /*compressed=*/4; + tx->has_signature_v = true; + tx->signature_v = 27 + pby + /*compressed=*/4; - tx->has_signature_r = true; - tx->signature_r.size = 32; - memcpy(tx->signature_r.bytes, sig, 32); + tx->has_signature_r = true; + tx->signature_r.size = 32; + memcpy(tx->signature_r.bytes, sig, 32); - tx->has_signature_s = true; - tx->signature_s.size = 32; - memcpy(tx->signature_s.bytes, sig + 32, 32); + tx->has_signature_s = true; + tx->signature_s.size = 32; + memcpy(tx->signature_s.bytes, sig + 32, 32); - return true; + return true; } diff --git a/lib/firmware/eos.h b/lib/firmware/eos.h index ca5eca997..811ed242a 100644 --- a/lib/firmware/eos.h +++ b/lib/firmware/eos.h @@ -22,15 +22,13 @@ #include "trezor/crypto/hasher.h" -#define CHECK_PARAM_RET(cond, errormsg, retval) \ - if (!(cond)) { \ - fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ - layoutHome(); \ - return retval; \ - } - +#define CHECK_PARAM_RET(cond, errormsg, retval) \ + if (!(cond)) { \ + fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ + layoutHome(); \ + return retval; \ + } extern CONFIDENTIAL Hasher hasher_preimage; #endif - diff --git a/lib/firmware/ethereum.c b/lib/firmware/ethereum.c index d26a81fda..498626025 100644 --- a/lib/firmware/ethereum.c +++ b/lib/firmware/ethereum.c @@ -55,157 +55,163 @@ static uint32_t tx_type; struct SHA3_CTX keccak_ctx; bool ethereum_isStandardERC20Transfer(const EthereumSignTx *msg) { - if (msg->has_to && msg->to.size == 20 && msg->value.size == 0 && msg->data_initial_chunk.size == 68 - && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - return true; - } - return false; + if (msg->has_to && msg->to.size == 20 && msg->value.size == 0 && + msg->data_initial_chunk.size == 68 && + memcmp(msg->data_initial_chunk.bytes, + "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16) == 0) { + return true; + } + return false; } bool ethereum_isStandardERC20Approve(const EthereumSignTx *msg) { - if (msg->has_to && msg->to.size == 20 && msg->value.size == 0 && msg->data_initial_chunk.size == 68 - && memcmp(msg->data_initial_chunk.bytes, "\x09\x5e\xa7\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - return true; - } - return false; + if (msg->has_to && msg->to.size == 20 && msg->value.size == 0 && + msg->data_initial_chunk.size == 68 && + memcmp(msg->data_initial_chunk.bytes, + "\x09\x5e\xa7\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16) == 0) { + return true; + } + return false; } -bool ethereum_getStandardERC20Recipient(const EthereumSignTx *msg, char *address, size_t len) { - if (len < 2 * 20 + 1) - return false; +bool ethereum_getStandardERC20Recipient(const EthereumSignTx *msg, + char *address, size_t len) { + if (len < 2 * 20 + 1) return false; - data2hex(msg->data_initial_chunk.bytes + 16, 20, address); - return true; + data2hex(msg->data_initial_chunk.bytes + 16, 20, address); + return true; } bool ethereum_getStandardERC20Coin(const EthereumSignTx *msg, CoinType *coin) { - const CoinType *found = coinByChainAddress(msg->has_chain_id ? msg->chain_id : 1, msg->to.bytes); - if (found) { - memcpy(coin, found, sizeof(*coin)); - return true; - } - - const TokenType *token = tokenByChainAddress(msg->has_chain_id ? msg->chain_id : 1, msg->to.bytes); - if (token == UnknownToken) - return false; - - coinFromToken(coin, token); - return true; + const CoinType *found = + coinByChainAddress(msg->has_chain_id ? msg->chain_id : 1, msg->to.bytes); + if (found) { + memcpy(coin, found, sizeof(*coin)); + return true; + } + + const TokenType *token = + tokenByChainAddress(msg->has_chain_id ? msg->chain_id : 1, msg->to.bytes); + if (token == UnknownToken) return false; + + coinFromToken(coin, token); + return true; } -bool ethereum_getStandardERC20Amount(const EthereumSignTx *msg, void **tx_out_amount) { - const ExchangeType *exchange = &msg->exchange_type; - size_t size = exchange->signed_exchange_response.responseV2.deposit_amount.size; - if (32 < size) - return false; - - // Make sure the value in data_initial_chunk contains the correct number of - // leading zeroes (as compared to what the exchange contract wants). - char *value = (char*)msg->data_initial_chunk.bytes + 36; - if (memcmp(value, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32-size) != 0) - return false; - - *tx_out_amount = value + (32 - size); - return true; +bool ethereum_getStandardERC20Amount(const EthereumSignTx *msg, + void **tx_out_amount) { + const ExchangeType *exchange = &msg->exchange_type; + size_t size = + exchange->signed_exchange_response.responseV2.deposit_amount.size; + if (32 < size) return false; + + // Make sure the value in data_initial_chunk contains the correct number of + // leading zeroes (as compared to what the exchange contract wants). + char *value = (char *)msg->data_initial_chunk.bytes + 36; + if (memcmp(value, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 32 - size) != 0) + return false; + + *tx_out_amount = value + (32 - size); + return true; } void bn_from_bytes(const uint8_t *value, size_t value_len, bignum256 *val) { - uint8_t pad_val[32]; - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, val); - memzero(pad_val, sizeof(pad_val)); + uint8_t pad_val[32]; + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, val); + memzero(pad_val, sizeof(pad_val)); } -static inline void hash_data(const uint8_t *buf, size_t size) -{ - sha3_Update(&keccak_ctx, buf, size); +static inline void hash_data(const uint8_t *buf, size_t size) { + sha3_Update(&keccak_ctx, buf, size); } /* * Push an RLP encoded length to the hash buffer. */ -static void hash_rlp_length(uint32_t length, uint8_t firstbyte) -{ - uint8_t buf[4]; - if (length == 1 && firstbyte <= 0x7f) { - /* empty length header */ - } else if (length <= 55) { - buf[0] = 0x80 + length; - hash_data(buf, 1); - } else if (length <= 0xff) { - buf[0] = 0xb7 + 1; - buf[1] = length; - hash_data(buf, 2); - } else if (length <= 0xffff) { - buf[0] = 0xb7 + 2; - buf[1] = length >> 8; - buf[2] = length & 0xff; - hash_data(buf, 3); - } else { - buf[0] = 0xb7 + 3; - buf[1] = length >> 16; - buf[2] = length >> 8; - buf[3] = length & 0xff; - hash_data(buf, 4); - } +static void hash_rlp_length(uint32_t length, uint8_t firstbyte) { + uint8_t buf[4]; + if (length == 1 && firstbyte <= 0x7f) { + /* empty length header */ + } else if (length <= 55) { + buf[0] = 0x80 + length; + hash_data(buf, 1); + } else if (length <= 0xff) { + buf[0] = 0xb7 + 1; + buf[1] = length; + hash_data(buf, 2); + } else if (length <= 0xffff) { + buf[0] = 0xb7 + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + hash_data(buf, 3); + } else { + buf[0] = 0xb7 + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + hash_data(buf, 4); + } } /* * Push an RLP encoded list length to the hash buffer. */ -static void hash_rlp_list_length(uint32_t length) -{ - uint8_t buf[4]; - if (length <= 55) { - buf[0] = 0xc0 + length; - hash_data(buf, 1); - } else if (length <= 0xff) { - buf[0] = 0xf7 + 1; - buf[1] = length; - hash_data(buf, 2); - } else if (length <= 0xffff) { - buf[0] = 0xf7 + 2; - buf[1] = length >> 8; - buf[2] = length & 0xff; - hash_data(buf, 3); - } else { - buf[0] = 0xf7 + 3; - buf[1] = length >> 16; - buf[2] = length >> 8; - buf[3] = length & 0xff; - hash_data(buf, 4); - } +static void hash_rlp_list_length(uint32_t length) { + uint8_t buf[4]; + if (length <= 55) { + buf[0] = 0xc0 + length; + hash_data(buf, 1); + } else if (length <= 0xff) { + buf[0] = 0xf7 + 1; + buf[1] = length; + hash_data(buf, 2); + } else if (length <= 0xffff) { + buf[0] = 0xf7 + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + hash_data(buf, 3); + } else { + buf[0] = 0xf7 + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + hash_data(buf, 4); + } } /* * Push an RLP encoded length field and data to the hash buffer. */ -static void hash_rlp_field(const uint8_t *buf, size_t size) -{ - hash_rlp_length(size, buf[0]); - hash_data(buf, size); +static void hash_rlp_field(const uint8_t *buf, size_t size) { + hash_rlp_length(size, buf[0]); + hash_data(buf, size); } /* * Push an RLP encoded number to the hash buffer. * Ethereum yellow paper says to convert to big endian and strip leading zeros. */ -static void hash_rlp_number(uint32_t number) -{ - if (!number) { - return; - } - uint8_t data[4]; - data[0] = (number >> 24) & 0xff; - data[1] = (number >> 16) & 0xff; - data[2] = (number >> 8) & 0xff; - data[3] = (number) & 0xff; - int offset = 0; - while (!data[offset]) { - offset++; - } - hash_rlp_field(data + offset, 4 - offset); +static void hash_rlp_number(uint32_t number) { + if (!number) { + return; + } + uint8_t data[4]; + data[0] = (number >> 24) & 0xff; + data[1] = (number >> 16) & 0xff; + data[2] = (number >> 8) & 0xff; + data[3] = (number)&0xff; + int offset = 0; + while (!data[offset]) { + offset++; + } + hash_rlp_field(data + offset, 4 - offset); } /* @@ -213,283 +219,314 @@ static void hash_rlp_number(uint32_t number) * NOTE: supports up to 16MB of data (how unlikely...) * FIXME: improve */ -static int rlp_calculate_length(int length, uint8_t firstbyte) -{ - if (length == 1 && firstbyte <= 0x7f) { - return 1; - } else if (length <= 55) { - return 1 + length; - } else if (length <= 0xff) { - return 2 + length; - } else if (length <= 0xffff) { - return 3 + length; - } else { - return 4 + length; - } +static int rlp_calculate_length(int length, uint8_t firstbyte) { + if (length == 1 && firstbyte <= 0x7f) { + return 1; + } else if (length <= 55) { + return 1 + length; + } else if (length <= 0xff) { + return 2 + length; + } else if (length <= 0xffff) { + return 3 + length; + } else { + return 4 + length; + } } -static int rlp_calculate_number_length(uint32_t number) -{ - if (number <= 0x7f) { - return 1; - } - else if (number <= 0xff) { - return 2; - } - else if (number <= 0xffff) { - return 3; - } - else if (number <= 0xffffff) { - return 4; - } else { - return 5; - } +static int rlp_calculate_number_length(uint32_t number) { + if (number <= 0x7f) { + return 1; + } else if (number <= 0xff) { + return 2; + } else if (number <= 0xffff) { + return 3; + } else if (number <= 0xffffff) { + return 4; + } else { + return 5; + } } -static void send_request_chunk(void) -{ - layoutProgress(_("Signing"), (data_total - data_left) * 1000 / data_total); - msg_tx_request.has_data_length = true; - msg_tx_request.data_length = data_left <= 1024 ? data_left : 1024; - msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); +static void send_request_chunk(void) { + layoutProgress(_("Signing"), (data_total - data_left) * 1000 / data_total); + msg_tx_request.has_data_length = true; + msg_tx_request.data_length = data_left <= 1024 ? data_left : 1024; + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); } -static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) -{ - (void) signature; - return (v & 2) == 0; +static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) { + (void)signature; + return (v & 2) == 0; } -static void send_signature(void) -{ - uint8_t hash[32], sig[64]; - uint8_t v; - layoutProgress(_("Signing"), 1000); - - /* eip-155 replay protection */ - if (chain_id) { - /* hash v=chain_id, r=0, s=0 */ - hash_rlp_number(chain_id); - hash_rlp_length(0, 0); - hash_rlp_length(0, 0); - } - - keccak_Final(&keccak_ctx, hash); - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); - ethereum_signing_abort(); - return; - } - - memzero(privkey, sizeof(privkey)); - - /* Send back the result */ - msg_tx_request.has_data_length = false; - - msg_tx_request.has_signature_v = true; - if (chain_id > MAX_CHAIN_ID) { - msg_tx_request.signature_v = v; - } else if (chain_id) { - msg_tx_request.signature_v = v + 2 * chain_id + 35; - } else { - msg_tx_request.signature_v = v + 27; - } - - msg_tx_request.has_signature_r = true; - msg_tx_request.signature_r.size = 32; - memcpy(msg_tx_request.signature_r.bytes, sig, 32); - - msg_tx_request.has_signature_s = true; - msg_tx_request.signature_s.size = 32; - memcpy(msg_tx_request.signature_s.bytes, sig + 32, 32); - - // KeepKey custom (for the KeepKey Client) - msg_tx_request.has_hash = true; - msg_tx_request.hash.size = sizeof(msg_tx_request.hash.bytes); - memcpy(msg_tx_request.hash.bytes, hash, msg_tx_request.hash.size); - msg_tx_request.has_signature_der = true; - msg_tx_request.signature_der.size = ecdsa_sig_to_der(sig, msg_tx_request.signature_der.bytes); - - msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); - - ethereum_signing_abort(); +static void send_signature(void) { + uint8_t hash[32], sig[64]; + uint8_t v; + layoutProgress(_("Signing"), 1000); + + /* eip-155 replay protection */ + if (chain_id) { + /* hash v=chain_id, r=0, s=0 */ + hash_rlp_number(chain_id); + hash_rlp_length(0, 0); + hash_rlp_length(0, 0); + } + + keccak_Final(&keccak_ctx, hash); + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, + ethereum_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + ethereum_signing_abort(); + return; + } + + memzero(privkey, sizeof(privkey)); + + /* Send back the result */ + msg_tx_request.has_data_length = false; + + msg_tx_request.has_signature_v = true; + if (chain_id > MAX_CHAIN_ID) { + msg_tx_request.signature_v = v; + } else if (chain_id) { + msg_tx_request.signature_v = v + 2 * chain_id + 35; + } else { + msg_tx_request.signature_v = v + 27; + } + + msg_tx_request.has_signature_r = true; + msg_tx_request.signature_r.size = 32; + memcpy(msg_tx_request.signature_r.bytes, sig, 32); + + msg_tx_request.has_signature_s = true; + msg_tx_request.signature_s.size = 32; + memcpy(msg_tx_request.signature_s.bytes, sig + 32, 32); + + // KeepKey custom (for the KeepKey Client) + msg_tx_request.has_hash = true; + msg_tx_request.hash.size = sizeof(msg_tx_request.hash.bytes); + memcpy(msg_tx_request.hash.bytes, hash, msg_tx_request.hash.size); + msg_tx_request.has_signature_der = true; + msg_tx_request.signature_der.size = + ecdsa_sig_to_der(sig, msg_tx_request.signature_der.bytes); + + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); + + ethereum_signing_abort(); } /* Format a 256 bit number (amount in wei) into a human readable format * using standard ethereum units. * The buffer must be at least 25 bytes. */ -void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, uint32_t cid, char *buf, int buflen) -{ - bignum256 bn1e9; - bn_read_uint32(1000000000, &bn1e9); - const char *suffix = NULL; - int decimals = 18; - if (token == UnknownToken) { - strlcpy(buf, "Unknown token value", buflen); - return; - } else - if (token != NULL) { - suffix = token->ticker; - decimals = token->decimals; - } else - if (bn_is_less(amnt, &bn1e9)) { - suffix = " Wei"; - decimals = 0; - } else { - if (tx_type == 1 || tx_type == 6) { - suffix = " WAN"; - } else { - // constants from trezor-common/defs/ethereum/networks.json - switch (cid) { - case 1: suffix = " ETH"; break; // Ethereum - case 2: suffix = " EXP"; break; // Expanse - case 3: suffix = " tROP"; break; // Ethereum Testnet Ropsten - case 4: suffix = " tRIN"; break; // Ethereum Testnet Rinkeby - case 8: suffix = " UBQ"; break; // UBIQ - case 20: suffix = " EOSC"; break; // EOS Classic - case 28: suffix = " ETSC"; break; // Ethereum Social - case 30: suffix = " RBTC"; break; // RSK - case 31: suffix = " tRBTC";break; // RSK Testnet - case 42: suffix = " tKOV"; break; // Ethereum Testnet Kovan - case 61: suffix = " ETC"; break; // Ethereum Classic - case 62: suffix = " tETC"; break; // Ethereum Classic Testnet - case 64: suffix = " ELLA"; break; // Ellaism - case 820: suffix = " CLO"; break; // Callisto - case 1987: suffix = " EGEM"; break; // EtherGem - default : suffix = " UNKN"; break; // unknown chain - } - } - } - bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); +void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, + uint32_t cid, char *buf, int buflen) { + bignum256 bn1e9; + bn_read_uint32(1000000000, &bn1e9); + const char *suffix = NULL; + int decimals = 18; + if (token == UnknownToken) { + strlcpy(buf, "Unknown token value", buflen); + return; + } else if (token != NULL) { + suffix = token->ticker; + decimals = token->decimals; + } else if (bn_is_less(amnt, &bn1e9)) { + suffix = " Wei"; + decimals = 0; + } else { + if (tx_type == 1 || tx_type == 6) { + suffix = " WAN"; + } else { + // constants from trezor-common/defs/ethereum/networks.json + switch (cid) { + case 1: + suffix = " ETH"; + break; // Ethereum + case 2: + suffix = " EXP"; + break; // Expanse + case 3: + suffix = " tROP"; + break; // Ethereum Testnet Ropsten + case 4: + suffix = " tRIN"; + break; // Ethereum Testnet Rinkeby + case 8: + suffix = " UBQ"; + break; // UBIQ + case 20: + suffix = " EOSC"; + break; // EOS Classic + case 28: + suffix = " ETSC"; + break; // Ethereum Social + case 30: + suffix = " RBTC"; + break; // RSK + case 31: + suffix = " tRBTC"; + break; // RSK Testnet + case 42: + suffix = " tKOV"; + break; // Ethereum Testnet Kovan + case 61: + suffix = " ETC"; + break; // Ethereum Classic + case 62: + suffix = " tETC"; + break; // Ethereum Classic Testnet + case 64: + suffix = " ELLA"; + break; // Ellaism + case 820: + suffix = " CLO"; + break; // Callisto + case 1987: + suffix = " EGEM"; + break; // EtherGem + default: + suffix = " UNKN"; + break; // unknown chain + } + } + } + bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); } -static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token, - char *out_str, size_t out_str_len, bool approve) -{ - bignum256 val; - uint8_t pad_val[32]; - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, &val); - - char amount[32]; - if (token == NULL) { - if (bn_is_zero(&val)) { - strcpy(amount, _("message")); - } else { - ethereumFormatAmount(&val, NULL, chain_id, amount, sizeof(amount)); - } - } else { - ethereumFormatAmount(&val, token, chain_id, amount, sizeof(amount)); - } - - char addr[43] = "0x"; - if (to_len) { - ethereum_address_checksum(to, addr + 2, false, chain_id); - } - - bool approve_all = approve && value_len == 32 && - memcmp(value, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && - memcmp(value + 8, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && - memcmp(value + 16, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && - memcmp(value + 24, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0; - - const char *address = addr; - if (to_len && makerdao_isOasisDEXAddress(to, chain_id)) { - address = "OasisDEX"; - } - - int cx; - if (approve && bn_is_zero(&val) && token) { - cx = snprintf(out_str, out_str_len, "Remove ability for %s to withdraw %s?", address, token->ticker + 1); - } else if (approve_all) { - cx = snprintf(out_str, out_str_len, "Unlock full %s balance for withdrawal by %s?", token->ticker + 1, address); - } else if (approve) { - cx = snprintf(out_str, out_str_len, "Approve withdrawal of up to %s by %s?", amount, address); - } else { - cx = snprintf(out_str, out_str_len, "Send %s to %s", amount, to_len ? address : "new contract?"); - } - - if (out_str_len <= (size_t)cx) { - /*error detected. Clear the buffer */ - memset(out_str, 0, out_str_len); - } +static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, + const uint8_t *value, uint32_t value_len, + const TokenType *token, char *out_str, + size_t out_str_len, bool approve) { + bignum256 val; + uint8_t pad_val[32]; + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); + + char amount[32]; + if (token == NULL) { + if (bn_is_zero(&val)) { + strcpy(amount, _("message")); + } else { + ethereumFormatAmount(&val, NULL, chain_id, amount, sizeof(amount)); + } + } else { + ethereumFormatAmount(&val, token, chain_id, amount, sizeof(amount)); + } + + char addr[43] = "0x"; + if (to_len) { + ethereum_address_checksum(to, addr + 2, false, chain_id); + } + + bool approve_all = + approve && value_len == 32 && + memcmp(value, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && + memcmp(value + 8, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && + memcmp(value + 16, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 && + memcmp(value + 24, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0; + + const char *address = addr; + if (to_len && makerdao_isOasisDEXAddress(to, chain_id)) { + address = "OasisDEX"; + } + + int cx; + if (approve && bn_is_zero(&val) && token) { + cx = snprintf(out_str, out_str_len, "Remove ability for %s to withdraw %s?", + address, token->ticker + 1); + } else if (approve_all) { + cx = snprintf(out_str, out_str_len, + "Unlock full %s balance for withdrawal by %s?", + token->ticker + 1, address); + } else if (approve) { + cx = snprintf(out_str, out_str_len, "Approve withdrawal of up to %s by %s?", + amount, address); + } else { + cx = snprintf(out_str, out_str_len, "Send %s to %s", amount, + to_len ? address : "new contract?"); + } + + if (out_str_len <= (size_t)cx) { + /*error detected. Clear the buffer */ + memset(out_str, 0, out_str_len); + } } -static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total_len, - char *out_str, size_t out_str_len) -{ - char hexdata[3][17]; - char summary[20]; - uint32_t printed = 0; - for (int i = 0; i < 3; i++) { - uint32_t linelen = len - printed; - if (linelen > 8) { - linelen = 8; - } - data2hex(data, linelen, hexdata[i]); - data += linelen; - printed += linelen; - } - - strcpy(summary, "... bytes"); - char *p = summary + 11; - uint32_t number = total_len; - while (number > 0) { - *p-- = '0' + number % 10; - number = number / 10; - } - char *summarystart = summary; - if (total_len == printed) - summarystart = summary + 4; - - if((uint32_t)snprintf(out_str, out_str_len, "%s%s\n%s%s", hexdata[0], hexdata[1], - hexdata[2], summarystart) >= out_str_len) { - /*error detected. Clear the buffer */ - memset(out_str, 0, out_str_len); - } +static void layoutEthereumData(const uint8_t *data, uint32_t len, + uint32_t total_len, char *out_str, + size_t out_str_len) { + char hexdata[3][17]; + char summary[20]; + uint32_t printed = 0; + for (int i = 0; i < 3; i++) { + uint32_t linelen = len - printed; + if (linelen > 8) { + linelen = 8; + } + data2hex(data, linelen, hexdata[i]); + data += linelen; + printed += linelen; + } + + strcpy(summary, "... bytes"); + char *p = summary + 11; + uint32_t number = total_len; + while (number > 0) { + *p-- = '0' + number % 10; + number = number / 10; + } + char *summarystart = summary; + if (total_len == printed) summarystart = summary + 4; + + if ((uint32_t)snprintf(out_str, out_str_len, "%s%s\n%s%s", hexdata[0], + hexdata[1], hexdata[2], summarystart) >= out_str_len) { + /*error detected. Clear the buffer */ + memset(out_str, 0, out_str_len); + } } static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, - const uint8_t *gas_price, uint32_t gas_price_len, - const uint8_t *gas_limit, uint32_t gas_limit_len, - bool is_token, char *out_str, size_t out_str_len) -{ - bignum256 val, gas; - uint8_t pad_val[32]; - char tx_value[32]; - char gas_value[32]; - - memzero(tx_value, sizeof(tx_value)); - memzero(gas_value, sizeof(gas_value)); - - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); - bn_read_be(pad_val, &val); - - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); - bn_read_be(pad_val, &gas); - bn_multiply(&val, &gas, &secp256k1.prime); - - ethereumFormatAmount(&gas, NULL, chain_id, gas_value, sizeof(gas_value)); - - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, &val); - - if (bn_is_zero(&val)) { - strcpy(tx_value, is_token ? _("the tokens") : _("the message")); - } else { - ethereumFormatAmount(&val, NULL, chain_id, tx_value, sizeof(tx_value)); - } - - if((uint32_t)snprintf(out_str, out_str_len, - _("Send %s from your wallet, paying up to %s for gas?"), - tx_value, gas_value) >= out_str_len) { - /*error detected. Clear the buffer */ - memset(out_str, 0, out_str_len); - } + const uint8_t *gas_price, uint32_t gas_price_len, + const uint8_t *gas_limit, uint32_t gas_limit_len, + bool is_token, char *out_str, + size_t out_str_len) { + bignum256 val, gas; + uint8_t pad_val[32]; + char tx_value[32]; + char gas_value[32]; + + memzero(tx_value, sizeof(tx_value)); + memzero(gas_value, sizeof(gas_value)); + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); + bn_read_be(pad_val, &val); + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); + bn_read_be(pad_val, &gas); + bn_multiply(&val, &gas, &secp256k1.prime); + + ethereumFormatAmount(&gas, NULL, chain_id, gas_value, sizeof(gas_value)); + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); + + if (bn_is_zero(&val)) { + strcpy(tx_value, is_token ? _("the tokens") : _("the message")); + } else { + ethereumFormatAmount(&val, NULL, chain_id, tx_value, sizeof(tx_value)); + } + + if ((uint32_t)snprintf( + out_str, out_str_len, + _("Send %s from your wallet, paying up to %s for gas?"), tx_value, + gas_value) >= out_str_len) { + /*error detected. Clear the buffer */ + memset(out_str, 0, out_str_len); + } } /* @@ -502,353 +539,391 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, * - data (0 ..) */ -static bool ethereum_signing_check(EthereumSignTx *msg) -{ - if (!msg->has_gas_price || !msg->has_gas_limit) { - return false; - } - - if (msg->to.size != 20 && msg->to.size != 0) { - /* Address has wrong length */ - return false; - } - - // sending transaction to address 0 (contract creation) without a data field - if (msg->to.size == 0 && (!msg->has_data_length || msg->data_length == 0)) { - return false; - } - - if (msg->gas_price.size + msg->gas_limit.size > 30) { - // sanity check that fee doesn't overflow - return false; - } - - return true; +static bool ethereum_signing_check(EthereumSignTx *msg) { + if (!msg->has_gas_price || !msg->has_gas_limit) { + return false; + } + + if (msg->to.size != 20 && msg->to.size != 0) { + /* Address has wrong length */ + return false; + } + + // sending transaction to address 0 (contract creation) without a data field + if (msg->to.size == 0 && (!msg->has_data_length || msg->data_length == 0)) { + return false; + } + + if (msg->gas_price.size + msg->gas_limit.size > 30) { + // sanity check that fee doesn't overflow + return false; + } + + return true; } -void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node, bool needs_confirm) -{ - ethereum_signing = true; - sha3_256_Init(&keccak_ctx); - - memset(&msg_tx_request, 0, sizeof(EthereumTxRequest)); - /* set fields to 0, to avoid conditions later */ - if (!msg->has_value) - msg->value.size = 0; - if (!msg->has_data_initial_chunk) - msg->data_initial_chunk.size = 0; - if (!msg->has_to) - msg->to.size = 0; - if (!msg->has_nonce) - msg->nonce.size = 0; - - /* eip-155 chain id */ - if (msg->has_chain_id) { - if (msg->chain_id < 1) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Chain Id out of bounds")); - ethereum_signing_abort(); - return; - } - chain_id = msg->chain_id; - } else { - chain_id = 0; - } - - /* Wanchain txtype */ - if (msg->has_tx_type) { - if (msg->tx_type == 1 || msg->tx_type == 6) { - tx_type = msg->tx_type; - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Txtype out of bounds")); - ethereum_signing_abort(); - return; - } - } else { - tx_type = 0; - } - - if (msg->has_data_length && msg->data_length > 0) { - if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Data length provided, but no initial chunk")); - ethereum_signing_abort(); - return; - } - /* Our encoding only supports transactions up to 2^24 bytes. To - * prevent exceeding the limit we use a stricter limit on data length. - */ - if (msg->data_length > 16000000) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Data length exceeds limit")); - ethereum_signing_abort(); - return; - } - data_total = msg->data_length; - } else { - data_total = 0; - } - if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(FailureType_Failure_Other, _("Invalid size of initial chunk")); - ethereum_signing_abort(); - return; - } - - const TokenType *token = NULL; - - // safety checks - if (!ethereum_signing_check(msg)) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Safety check failed")); - ethereum_signing_abort(); - return; - } - - bool data_needs_confirm = true; - if (ethereum_contractHandled(data_total, msg, node)) { - if (!ethereum_contractConfirmed(data_total, msg, node)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - ethereum_signing_abort(); - return; - } - needs_confirm = false; - data_needs_confirm = false; - } - - // detect ERC-20 token - if (data_total == 68 && ethereum_isStandardERC20Transfer(msg)) { - token = tokenByChainAddress(chain_id, msg->to.bytes); - } - - bool is_approve = false; - if (data_total == 68 && ethereum_isStandardERC20Approve(msg)) { - token = tokenByChainAddress(chain_id, msg->to.bytes); - is_approve = true; - } - - char confirm_body_message[BODY_CHAR_MAX]; - if (needs_confirm) { - memset(confirm_body_message, 0, sizeof(confirm_body_message)); - if (token != NULL) { - layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token, - confirm_body_message, sizeof(confirm_body_message), /*approve=*/is_approve); - } else { - layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL, - confirm_body_message, sizeof(confirm_body_message), /*approve=*/false); - } - bool is_transfer = msg->address_type == OutputAddressType_TRANSFER; - const char *title; - ButtonRequestType BRT; - if (is_approve) { - title = "Approve"; - BRT = ButtonRequestType_ButtonRequest_ConfirmOutput; - } else if (is_transfer) { - title = "Transfer"; - BRT = ButtonRequestType_ButtonRequest_ConfirmTransferToAccount; - } else { - title = "Send"; - BRT = ButtonRequestType_ButtonRequest_ConfirmOutput; - } - if (!confirm(BRT, title, "%s", confirm_body_message)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - ethereum_signing_abort(); - return; - } - } - - memset(confirm_body_message, 0, sizeof(confirm_body_message)); - if (token == NULL && data_total > 0 && data_needs_confirm) { - // KeepKey custom: warn the user that they're trying to do something - // that is potentially dangerous. People (generally) aren't great at - // parsing raw transaction data, and we can't effectively show them - // what they're about to do in the general case. - if (!storage_isPolicyEnabled("AdvancedMode")) { - (void)review(ButtonRequestType_ButtonRequest_Other, "Warning", - "Signing of arbitrary ETH contract data is recommended only for " - "experienced users. Enable 'AdvancedMode' policy to dismiss."); - } - - layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total, - confirm_body_message, sizeof(confirm_body_message)); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Confirm Ethereum Data", "%s", - confirm_body_message)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - ethereum_signing_abort(); - return; - } - } - - if (is_approve) { - token = NULL; - } - - memset(confirm_body_message, 0, sizeof(confirm_body_message)); - layoutEthereumFee(msg->value.bytes, msg->value.size, - msg->gas_price.bytes, msg->gas_price.size, - msg->gas_limit.bytes, msg->gas_limit.size, token != NULL, - confirm_body_message, sizeof(confirm_body_message)); - if(!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", "%s", - confirm_body_message)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - ethereum_signing_abort(); - return; - } - - /* Stage 1: Calculate total RLP length */ - uint32_t rlp_length = 0; - layoutProgress(_("Signing"), 0); - - rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); - rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); - rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); - rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); - rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); - if (tx_type) { - rlp_length += rlp_calculate_number_length(tx_type); - } - if (chain_id) { - rlp_length += rlp_calculate_number_length(chain_id); - rlp_length += rlp_calculate_length(0, 0); - rlp_length += rlp_calculate_length(0, 0); - } - - /* Stage 2: Store header fields */ - hash_rlp_list_length(rlp_length); - layoutProgress(_("Signing"), 100); - - if (tx_type) { - hash_rlp_number(tx_type); - } - hash_rlp_field(msg->nonce.bytes, msg->nonce.size); - hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); - hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - hash_rlp_field(msg->to.bytes, msg->to.size); - hash_rlp_field(msg->value.bytes, msg->value.size); - hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); - hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - data_left = data_total - msg->data_initial_chunk.size; - - memcpy(privkey, node->private_key, 32); - - if (data_left > 0) { - send_request_chunk(); - } else { - send_signature(); - } +void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node, + bool needs_confirm) { + ethereum_signing = true; + sha3_256_Init(&keccak_ctx); + + memset(&msg_tx_request, 0, sizeof(EthereumTxRequest)); + /* set fields to 0, to avoid conditions later */ + if (!msg->has_value) msg->value.size = 0; + if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0; + if (!msg->has_to) msg->to.size = 0; + if (!msg->has_nonce) msg->nonce.size = 0; + + /* eip-155 chain id */ + if (msg->has_chain_id) { + if (msg->chain_id < 1) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Chain Id out of bounds")); + ethereum_signing_abort(); + return; + } + chain_id = msg->chain_id; + } else { + chain_id = 0; + } + + /* Wanchain txtype */ + if (msg->has_tx_type) { + if (msg->tx_type == 1 || msg->tx_type == 6) { + tx_type = msg->tx_type; + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Txtype out of bounds")); + ethereum_signing_abort(); + return; + } + } else { + tx_type = 0; + } + + if (msg->has_data_length && msg->data_length > 0) { + if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Data length provided, but no initial chunk")); + ethereum_signing_abort(); + return; + } + /* Our encoding only supports transactions up to 2^24 bytes. To + * prevent exceeding the limit we use a stricter limit on data length. + */ + if (msg->data_length > 16000000) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Data length exceeds limit")); + ethereum_signing_abort(); + return; + } + data_total = msg->data_length; + } else { + data_total = 0; + } + if (msg->data_initial_chunk.size > data_total) { + fsm_sendFailure(FailureType_Failure_Other, + _("Invalid size of initial chunk")); + ethereum_signing_abort(); + return; + } + + const TokenType *token = NULL; + + // safety checks + if (!ethereum_signing_check(msg)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Safety check failed")); + ethereum_signing_abort(); + return; + } + + bool data_needs_confirm = true; + if (ethereum_contractHandled(data_total, msg, node)) { + if (!ethereum_contractConfirmed(data_total, msg, node)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + needs_confirm = false; + data_needs_confirm = false; + } + + // detect ERC-20 token + if (data_total == 68 && ethereum_isStandardERC20Transfer(msg)) { + token = tokenByChainAddress(chain_id, msg->to.bytes); + } + + bool is_approve = false; + if (data_total == 68 && ethereum_isStandardERC20Approve(msg)) { + token = tokenByChainAddress(chain_id, msg->to.bytes); + is_approve = true; + } + + char confirm_body_message[BODY_CHAR_MAX]; + if (needs_confirm) { + memset(confirm_body_message, 0, sizeof(confirm_body_message)); + if (token != NULL) { + layoutEthereumConfirmTx( + msg->data_initial_chunk.bytes + 16, 20, + msg->data_initial_chunk.bytes + 36, 32, token, confirm_body_message, + sizeof(confirm_body_message), /*approve=*/is_approve); + } else { + layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, + msg->value.size, NULL, confirm_body_message, + sizeof(confirm_body_message), /*approve=*/false); + } + bool is_transfer = msg->address_type == OutputAddressType_TRANSFER; + const char *title; + ButtonRequestType BRT; + if (is_approve) { + title = "Approve"; + BRT = ButtonRequestType_ButtonRequest_ConfirmOutput; + } else if (is_transfer) { + title = "Transfer"; + BRT = ButtonRequestType_ButtonRequest_ConfirmTransferToAccount; + } else { + title = "Send"; + BRT = ButtonRequestType_ButtonRequest_ConfirmOutput; + } + if (!confirm(BRT, title, "%s", confirm_body_message)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + } + + memset(confirm_body_message, 0, sizeof(confirm_body_message)); + if (token == NULL && data_total > 0 && data_needs_confirm) { + // KeepKey custom: warn the user that they're trying to do something + // that is potentially dangerous. People (generally) aren't great at + // parsing raw transaction data, and we can't effectively show them + // what they're about to do in the general case. + if (!storage_isPolicyEnabled("AdvancedMode")) { + (void)review( + ButtonRequestType_ButtonRequest_Other, "Warning", + "Signing of arbitrary ETH contract data is recommended only for " + "experienced users. Enable 'AdvancedMode' policy to dismiss."); + } + + layoutEthereumData(msg->data_initial_chunk.bytes, + msg->data_initial_chunk.size, data_total, + confirm_body_message, sizeof(confirm_body_message)); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Confirm Ethereum Data", "%s", confirm_body_message)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + ethereum_signing_abort(); + return; + } + } + + if (is_approve) { + token = NULL; + } + + memset(confirm_body_message, 0, sizeof(confirm_body_message)); + layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes, + msg->gas_price.size, msg->gas_limit.bytes, + msg->gas_limit.size, token != NULL, confirm_body_message, + sizeof(confirm_body_message)); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", "%s", + confirm_body_message)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + + /* Stage 1: Calculate total RLP length */ + uint32_t rlp_length = 0; + layoutProgress(_("Signing"), 0); + + rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); + rlp_length += + rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); + rlp_length += + rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); + rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); + rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); + rlp_length += + rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); + if (tx_type) { + rlp_length += rlp_calculate_number_length(tx_type); + } + if (chain_id) { + rlp_length += rlp_calculate_number_length(chain_id); + rlp_length += rlp_calculate_length(0, 0); + rlp_length += rlp_calculate_length(0, 0); + } + + /* Stage 2: Store header fields */ + hash_rlp_list_length(rlp_length); + layoutProgress(_("Signing"), 100); + + if (tx_type) { + hash_rlp_number(tx_type); + } + hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); + hash_rlp_field(msg->to.bytes, msg->to.size); + hash_rlp_field(msg->value.bytes, msg->value.size); + hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); + hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); + data_left = data_total - msg->data_initial_chunk.size; + + memcpy(privkey, node->private_key, 32); + + if (data_left > 0) { + send_request_chunk(); + } else { + send_signature(); + } } -void ethereum_signing_txack(EthereumTxAck *tx) -{ - if (!ethereum_signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); - layoutHome(); - return; - } - - if (tx->data_chunk.size > data_left) { - fsm_sendFailure(FailureType_Failure_Other, _("Too much data")); - ethereum_signing_abort(); - return; - } - - if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(FailureType_Failure_Other, _("Empty data chunk received")); - ethereum_signing_abort(); - return; - } - - hash_data(tx->data_chunk.bytes, tx->data_chunk.size); - - data_left -= tx->data_chunk.size; - - if (data_left > 0) { - send_request_chunk(); - } else { - send_signature(); - } +void ethereum_signing_txack(EthereumTxAck *tx) { + if (!ethereum_signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Ethereum signing mode")); + layoutHome(); + return; + } + + if (tx->data_chunk.size > data_left) { + fsm_sendFailure(FailureType_Failure_Other, _("Too much data")); + ethereum_signing_abort(); + return; + } + + if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { + fsm_sendFailure(FailureType_Failure_Other, _("Empty data chunk received")); + ethereum_signing_abort(); + return; + } + + hash_data(tx->data_chunk.bytes, tx->data_chunk.size); + + data_left -= tx->data_chunk.size; + + if (data_left > 0) { + send_request_chunk(); + } else { + send_signature(); + } } -void ethereum_signing_abort(void) -{ - if (ethereum_signing) { - memzero(privkey, sizeof(privkey)); - layoutHome(); - ethereum_signing = false; - } +void ethereum_signing_abort(void) { + if (ethereum_signing) { + memzero(privkey, sizeof(privkey)); + layoutHome(); + ethereum_signing = false; + } } -static void ethereum_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) -{ - struct SHA3_CTX ctx; - sha3_256_Init(&ctx); - sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); - uint8_t c; - if (message_len >= 1000000000) { c = '0' + message_len / 1000000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 100000000) { c = '0' + message_len / 100000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 10000000) { c = '0' + message_len / 10000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 1000000) { c = '0' + message_len / 1000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 100000) { c = '0' + message_len / 100000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 10000) { c = '0' + message_len / 10000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 1000) { c = '0' + message_len / 1000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 100) { c = '0' + message_len / 100 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len >= 10) { c = '0' + message_len / 10 % 10; sha3_Update(&ctx, &c, 1); } - c = '0' + message_len % 10; sha3_Update(&ctx, &c, 1); - sha3_Update(&ctx, message, message_len); - keccak_Final(&ctx, hash); +static void ethereum_message_hash(const uint8_t *message, size_t message_len, + uint8_t hash[32]) { + struct SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); + uint8_t c; + if (message_len >= 1000000000) { + c = '0' + message_len / 1000000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 100000000) { + c = '0' + message_len / 100000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 10000000) { + c = '0' + message_len / 10000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 1000000) { + c = '0' + message_len / 1000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 100000) { + c = '0' + message_len / 100000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 10000) { + c = '0' + message_len / 10000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 1000) { + c = '0' + message_len / 1000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 100) { + c = '0' + message_len / 100 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len >= 10) { + c = '0' + message_len / 10 % 10; + sha3_Update(&ctx, &c, 1); + } + c = '0' + message_len % 10; + sha3_Update(&ctx, &c, 1); + sha3_Update(&ctx, message, message_len); + keccak_Final(&ctx, hash); } -void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) -{ - uint8_t hash[32]; - - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { - return; - } - resp->has_address = true; - resp->address.size = 20; - ethereum_message_hash(msg->message.bytes, msg->message.size, hash); - - uint8_t v; - if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Signing failed")); - return; - } - - resp->has_signature = true; - resp->signature.bytes[64] = 27 + v; - resp->signature.size = 65; - msg_write(MessageType_MessageType_EthereumMessageSignature, resp); +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, + EthereumMessageSignature *resp) { + uint8_t hash[32]; + + if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { + return; + } + resp->has_address = true; + resp->address.size = 20; + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + + uint8_t v; + if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, + resp->signature.bytes, &v, ethereum_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_Other, _("Signing failed")); + return; + } + + resp->has_signature = true; + resp->signature.bytes[64] = 27 + v; + resp->signature.size = 65; + msg_write(MessageType_MessageType_EthereumMessageSignature, resp); } -int ethereum_message_verify(const EthereumVerifyMessage *msg) -{ - if (msg->signature.size != 65 || msg->address.size != 20) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Malformed data")); - return 1; - } - - uint8_t pubkey[65]; - uint8_t hash[32]; - - ethereum_message_hash(msg->message.bytes, msg->message.size, hash); - - /* v should be 27, 28 but some implementations use 0,1. We are - * compatible with both. - */ - uint8_t v = msg->signature.bytes[64]; - if (v >= 27) { - v -= 27; - } - if (v >= 2 || - ecdsa_recover_pub_from_sig(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { - return 2; - } - - struct SHA3_CTX ctx; - sha3_256_Init(&ctx); - sha3_Update(&ctx, pubkey + 1, 64); - keccak_Final(&ctx, hash); - - /* result are the least significant 160 bits */ - if (memcmp(msg->address.bytes, hash + 12, 20) != 0) { - return 2; - } - return 0; +int ethereum_message_verify(const EthereumVerifyMessage *msg) { + if (msg->signature.size != 65 || msg->address.size != 20) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Malformed data")); + return 1; + } + + uint8_t pubkey[65]; + uint8_t hash[32]; + + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + + /* v should be 27, 28 but some implementations use 0,1. We are + * compatible with both. + */ + uint8_t v = msg->signature.bytes[64]; + if (v >= 27) { + v -= 27; + } + if (v >= 2 || ecdsa_recover_pub_from_sig( + &secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { + return 2; + } + + struct SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, pubkey + 1, 64); + keccak_Final(&ctx, hash); + + /* result are the least significant 160 bits */ + if (memcmp(msg->address.bytes, hash + 12, 20) != 0) { + return 2; + } + return 0; } diff --git a/lib/firmware/ethereum.h b/lib/firmware/ethereum.h index 5327b845f..db1678de8 100644 --- a/lib/firmware/ethereum.h +++ b/lib/firmware/ethereum.h @@ -29,7 +29,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); void ethereum_signing_abort(void); void ethereum_signing_txack(EthereumTxAck *msg); -void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); +void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, + EthereumMessageSignature *resp); int ethereum_message_verify(EthereumVerifyMessage *msg); #endif diff --git a/lib/firmware/ethereum_contracts.c b/lib/firmware/ethereum_contracts.c index df393d031..d482864dd 100644 --- a/lib/firmware/ethereum_contracts.c +++ b/lib/firmware/ethereum_contracts.c @@ -22,23 +22,20 @@ #include "keepkey/firmware/ethereum_contracts/makerdao.h" bool ethereum_contractHandled(uint32_t data_total, const EthereumSignTx *msg, - const HDNode *node) -{ - (void)node; + const HDNode *node) { + (void)node; - if (makerdao_isMakerDAO(data_total, msg)) - return true; + if (makerdao_isMakerDAO(data_total, msg)) return true; - return false; + return false; } bool ethereum_contractConfirmed(uint32_t data_total, const EthereumSignTx *msg, - const HDNode *node) -{ - (void)node; + const HDNode *node) { + (void)node; - if (makerdao_isMakerDAO(data_total, msg)) - return makerdao_confirmMakerDAO(data_total, msg); + if (makerdao_isMakerDAO(data_total, msg)) + return makerdao_confirmMakerDAO(data_total, msg); - return false; + return false; } diff --git a/lib/firmware/ethereum_contracts/makerdao.c b/lib/firmware/ethereum_contracts/makerdao.c index e019ec78d..fa9890be6 100644 --- a/lib/firmware/ethereum_contracts/makerdao.c +++ b/lib/firmware/ethereum_contracts/makerdao.c @@ -26,731 +26,667 @@ #include "keepkey/firmware/fsm.h" #include "trezor/crypto/address.h" -static bool getCupId(const uint8_t *param, uint32_t *val) -{ - bignum256 value; - bn_from_bytes(param, 32, &value); +static bool getCupId(const uint8_t *param, uint32_t *val) { + bignum256 value; + bn_from_bytes(param, 32, &value); - if (32 < bn_bitcount(&value)) - return false; + if (32 < bn_bitcount(&value)) return false; - *val = bn_write_uint32(&value); - return true; + *val = bn_write_uint32(&value); + return true; } -static bool confirmParamIsTub(const uint8_t *param, uint32_t chain_id) -{ - if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) - return false; - - const uint8_t *address = param + 12; +static bool confirmParamIsTub(const uint8_t *param, uint32_t chain_id) { + if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != + 0) + return false; - // Mainnet - // saiValuesAggregator: https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L16 - // saiValuesAggregator.tub: https://etherscan.io/readContract?m=normal&a=0x83f6ed3d377674186d8898a89d9032216e07e659#collapse4 - if (chain_id == 1 && memcmp(address, "\x44\x8a\x50\x65\xae\xbb\x8e\x42\x3f\x08\x96\xe6\xc5\xd5\x25\xc0\x40\xf5\x9a\xf3", 20) == 0) - return true; + const uint8_t *address = param + 12; + + // Mainnet + // saiValuesAggregator: + // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L16 + // saiValuesAggregator.tub: + // https://etherscan.io/readContract?m=normal&a=0x83f6ed3d377674186d8898a89d9032216e07e659#collapse4 + if (chain_id == 1 && memcmp(address, + "\x44\x8a\x50\x65\xae\xbb\x8e\x42\x3f\x08\x96\xe6" + "\xc5\xd5\x25\xc0\x40\xf5\x9a\xf3", + 20) == 0) + return true; - // Kovan - if (chain_id == 42 && memcmp(address, "\xa7\x19\x37\x14\x7b\x55\xde\xb8\xa5\x30\xc7\x22\x9c\x44\x2f\xd3\xf3\x1b\x7d\xb2", 20) == 0) - return true; + // Kovan + if (chain_id == 42 && memcmp(address, + "\xa7\x19\x37\x14\x7b\x55\xde\xb8\xa5\x30\xc7" + "\x22\x9c\x44\x2f\xd3\xf3\x1b\x7d\xb2", + 20) == 0) + return true; - char contract[43] = "0x"; - ethereum_address_checksum(address, contract + 2, false, chain_id); + char contract[43] = "0x"; + ethereum_address_checksum(address, contract + 2, false, chain_id); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Confirm TUB:\n%s", contract); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Confirm TUB:\n%s", contract); } -bool makerdao_isOasisDEXAddress(const uint8_t *address, uint32_t chain_id) -{ - // Mainnet - // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L17 - if (chain_id == 1 && memcmp(address, "\x39\x75\x53\x57\x75\x9c\xe0\xd7\xf3\x2d\xc8\xdc\x45\x41\x4c\xca\x40\x9a\xe2\x4e", 20) == 0) - return true; +bool makerdao_isOasisDEXAddress(const uint8_t *address, uint32_t chain_id) { + // Mainnet + // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L17 + if (chain_id == 1 && memcmp(address, + "\x39\x75\x53\x57\x75\x9c\xe0\xd7\xf3\x2d\xc8\xdc" + "\x45\x41\x4c\xca\x40\x9a\xe2\x4e", + 20) == 0) + return true; - // Kovan - if (chain_id == 42 && memcmp(address, "\x4a\x6b\xc4\xe8\x03\xc6\x20\x81\xff\xeb\xcc\x8d\x22\x7b\x5a\x87\xa5\x8f\x1f\x8f", 20) == 0) - return true; + // Kovan + if (chain_id == 42 && memcmp(address, + "\x4a\x6b\xc4\xe8\x03\xc6\x20\x81\xff\xeb\xcc" + "\x8d\x22\x7b\x5a\x87\xa5\x8f\x1f\x8f", + 20) == 0) + return true; - return false; + return false; } -static bool confirmParamIsOTCProvider(const uint8_t *param, uint32_t chain_id, const char **otcProvider) -{ - if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) - return false; +static bool confirmParamIsOTCProvider(const uint8_t *param, uint32_t chain_id, + const char **otcProvider) { + if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != + 0) + return false; - const uint8_t *address = param + 12; + const uint8_t *address = param + 12; - if (makerdao_isOasisDEXAddress(address, chain_id)) { - if (otcProvider) - *otcProvider = " via OasisDEX"; - return true; - } + if (makerdao_isOasisDEXAddress(address, chain_id)) { + if (otcProvider) *otcProvider = " via OasisDEX"; + return true; + } - char contract[43] = "0x"; - ethereum_address_checksum(address, contract + 2, false, chain_id); + char contract[43] = "0x"; + ethereum_address_checksum(address, contract + 2, false, chain_id); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Confirm OTC:\n%s", contract); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Confirm OTC:\n%s", contract); } -static bool confirmParamIsRegistryAddress(const uint8_t *param, uint32_t chain_id) -{ - if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) - return false; +static bool confirmParamIsRegistryAddress(const uint8_t *param, + uint32_t chain_id) { + if (memcmp(param, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != + 0) + return false; - const uint8_t *address = param + 12; + const uint8_t *address = param + 12; - // Mainnet - // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L21 - if (chain_id == 1 && memcmp(address, "\x46\x78\xf0\xa6\x95\x8e\x4d\x2b\xc4\xf1\xba\xf7\xbc\x52\xe8\xf3\x56\x4f\x3f\xe4", 20) == 0) - return true; + // Mainnet + // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L21 + if (chain_id == 1 && memcmp(address, + "\x46\x78\xf0\xa6\x95\x8e\x4d\x2b\xc4\xf1\xba\xf7" + "\xbc\x52\xe8\xf3\x56\x4f\x3f\xe4", + 20) == 0) + return true; - // Kovan - if (chain_id == 42 && memcmp(address, "\x64\xa4\x36\xae\x83\x1c\x16\x72\xae\x81\xf6\x74\xca\xb8\xb6\x77\x5d\xf3\x47\x5c", 20) == 0) - return true; + // Kovan + if (chain_id == 42 && memcmp(address, + "\x64\xa4\x36\xae\x83\x1c\x16\x72\xae\x81\xf6" + "\x74\xca\xb8\xb6\x77\x5d\xf3\x47\x5c", + 20) == 0) + return true; - char contract[43] = "0x"; - ethereum_address_checksum(address, contract + 2, false, chain_id); + char contract[43] = "0x"; + ethereum_address_checksum(address, contract + 2, false, chain_id); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Confirm Proxy Registry:\n%s", contract); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Confirm Proxy Registry:\n%s", contract); } -static bool confirmSaiProxyCreateAndExecuteAddress(const uint8_t *address, uint32_t chain_id) -{ - // Mainnet - // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L22 - if (chain_id == 1 && memcmp(address, "\x52\x6a\xf3\x36\xd6\x14\xad\xe5\xcc\x25\x2a\x40\x70\x62\xb8\x86\x1a\xf9\x98\xf5", 20) == 0) - return true; +static bool confirmSaiProxyCreateAndExecuteAddress(const uint8_t *address, + uint32_t chain_id) { + // Mainnet + // https://github.com/makerdao/scd-cdp-portal/blob/fac7b0571dc4128e89dcd5f7f8d44ded4b66073b/src/settings.json#L22 + if (chain_id == 1 && memcmp(address, + "\x52\x6a\xf3\x36\xd6\x14\xad\xe5\xcc\x25\x2a\x40" + "\x70\x62\xb8\x86\x1a\xf9\x98\xf5", + 20) == 0) + return true; - if (chain_id == 1 && memcmp(address, "\x19\x0c\x2C\xFC\x69\xE6\x8A\x8e\x8D\x5e\x2b\x9e\x2B\x9C\xc3\x33\x2C\xaf\xF7\x7B", 20) == 0) - return true; + if (chain_id == 1 && memcmp(address, + "\x19\x0c\x2C\xFC\x69\xE6\x8A\x8e\x8D\x5e\x2b\x9e" + "\x2B\x9C\xc3\x33\x2C\xaf\xF7\x7B", + 20) == 0) + return true; - // Kovan - // https://github.com/makerdao/scd-cdp-portal/blob/bde18348919784c14bb36c747d368b72b1c8f064/src/settings.json#L12 - if (chain_id == 42 && memcmp(address, "\x96\xfc\x00\x5a\x8b\xa8\x2b\x84\xb1\x1e\x0f\xf2\x11\xa2\xa1\x36\x2f\x10\x7e\xf0", 20) == 0) - return true; + // Kovan + // https://github.com/makerdao/scd-cdp-portal/blob/bde18348919784c14bb36c747d368b72b1c8f064/src/settings.json#L12 + if (chain_id == 42 && memcmp(address, + "\x96\xfc\x00\x5a\x8b\xa8\x2b\x84\xb1\x1e\x0f" + "\xf2\x11\xa2\xa1\x36\x2f\x10\x7e\xf0", + 20) == 0) + return true; - char contract[43] = "0x"; - ethereum_address_checksum(address, contract + 2, false, chain_id); + char contract[43] = "0x"; + ethereum_address_checksum(address, contract + 2, false, chain_id); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Confirm SaiProxyCreateAndExecute:\n%s", contract); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Confirm SaiProxyCreateAndExecute:\n%s", contract); } static bool isProxyCall(const EthereumSignTx *msg) { - if (memcmp(msg->data_initial_chunk.bytes, "\x1c\xff\x79\xcd", 4) != 0) - return false; + if (memcmp(msg->data_initial_chunk.bytes, "\x1c\xff\x79\xcd", 4) != 0) + return false; - if (msg->data_initial_chunk.size < 4 + 32 + 32 + 32) - return false; + if (msg->data_initial_chunk.size < 4 + 32 + 32 + 32) return false; - bignum256 offset; - bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 32, 32, &offset); + bignum256 offset; + bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 32, 32, &offset); - if (32 < bn_bitcount(&offset)) - return false; + if (32 < bn_bitcount(&offset)) return false; - if (64 != bn_write_uint32(&offset)) - return false; + if (64 != bn_write_uint32(&offset)) return false; - bignum256 length; - bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 32 + 32, 32, &length); + bignum256 length; + bn_from_bytes(msg->data_initial_chunk.bytes + 4 + 32 + 32, 32, &length); - if (32 < bn_bitcount(&length)) - return false; + if (32 < bn_bitcount(&length)) return false; - if (msg->data_initial_chunk.size == 4 + 3 * 32 + (bn_write_uint32(&length) - 4)) - return false; + if (msg->data_initial_chunk.size == + 4 + 3 * 32 + (bn_write_uint32(&length) - 4)) + return false; - return true; + return true; } -static bool confirmProxyCall(const EthereumSignTx *msg) -{ - if (memcmp(msg->data_initial_chunk.bytes + 4, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) - return false; +static bool confirmProxyCall(const EthereumSignTx *msg) { + if (memcmp(msg->data_initial_chunk.bytes + 4, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) + return false; - if (!confirmSaiProxyCreateAndExecuteAddress(msg->data_initial_chunk.bytes + 4 + 12, msg->chain_id)) - return false; + if (!confirmSaiProxyCreateAndExecuteAddress( + msg->data_initial_chunk.bytes + 4 + 12, msg->chain_id)) + return false; - return true; + return true; } -static inline bool hasParams(const EthereumSignTx *msg, size_t count) -{ - return msg->data_initial_chunk.size == 4 + count * 32; +static inline bool hasParams(const EthereumSignTx *msg, size_t count) { + return msg->data_initial_chunk.size == 4 + count * 32; } -static inline bool hasProxiedParams(const EthereumSignTx *msg, size_t count) -{ - return msg->data_initial_chunk.size == 4 + 3 * 32 + 4 + count * 32 + (32 - 4); +static inline bool hasProxiedParams(const EthereumSignTx *msg, size_t count) { + return msg->data_initial_chunk.size == 4 + 3 * 32 + 4 + count * 32 + (32 - 4); } -static inline const uint8_t *getMethod(const EthereumSignTx *msg) -{ - return msg->data_initial_chunk.bytes; +static inline const uint8_t *getMethod(const EthereumSignTx *msg) { + return msg->data_initial_chunk.bytes; } -static inline const uint8_t *getParam(const EthereumSignTx *msg, size_t idx) -{ - if (isProxyCall(msg)) { - return msg->data_initial_chunk.bytes + 4 + 3 * 32 + 4 + idx * 32; - } +static inline const uint8_t *getParam(const EthereumSignTx *msg, size_t idx) { + if (isProxyCall(msg)) { + return msg->data_initial_chunk.bytes + 4 + 3 * 32 + 4 + idx * 32; + } - return msg->data_initial_chunk.bytes + 4 + idx * 32; + return msg->data_initial_chunk.bytes + 4 + idx * 32; } -static inline const uint8_t *getProxiedMethod(const EthereumSignTx *msg) -{ - return msg->data_initial_chunk.bytes + 4 + 3 * 32; +static inline const uint8_t *getProxiedMethod(const EthereumSignTx *msg) { + return msg->data_initial_chunk.bytes + 4 + 3 * 32; } static bool isMethod(const EthereumSignTx *msg, const char *hash, - size_t arg_count) -{ - if (isProxyCall(msg)) { - if (!hasProxiedParams(msg, arg_count)) - return false; + size_t arg_count) { + if (isProxyCall(msg)) { + if (!hasProxiedParams(msg, arg_count)) return false; - if (memcmp(getProxiedMethod(msg), hash, 4) != 0) - return false; + if (memcmp(getProxiedMethod(msg), hash, 4) != 0) return false; - return true; - } + return true; + } - if (!hasParams(msg, arg_count)) - return false; + if (!hasParams(msg, arg_count)) return false; - if (memcmp(getMethod(msg), hash, 4) != 0) - return false; + if (memcmp(getMethod(msg), hash, 4) != 0) return false; - return true; + return true; } -static void getETHValue(const EthereumSignTx *msg, bignum256 *val) -{ - uint8_t pad_val[32]; - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - msg->value.size), msg->value.bytes, msg->value.size); - bn_read_be(pad_val, val); +static void getETHValue(const EthereumSignTx *msg, bignum256 *val) { + uint8_t pad_val[32]; + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - msg->value.size), msg->value.bytes, msg->value.size); + bn_read_be(pad_val, val); } static bool isETHValueZero(const EthereumSignTx *msg) { - bignum256 val; - getETHValue(msg, &val); - return bn_is_zero(&val); + bignum256 val; + getETHValue(msg, &val); + return bn_is_zero(&val); } -bool makerdao_isOpen(const EthereumSignTx *msg) -{ - // `open(address)` - if (!isMethod(msg, "\xc7\x40\x73\xa1", 1)) - return false; +bool makerdao_isOpen(const EthereumSignTx *msg) { + // `open(address)` + if (!isMethod(msg, "\xc7\x40\x73\xa1", 1)) return false; - return true; + return true; } -bool makerdao_confirmOpen(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmOpen(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Open CDP?"); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Open CDP?"); } -bool makerdao_isClose(const EthereumSignTx *msg) -{ - // `shut(address,bytes32)` - // `shut(address,bytes32,address)` - if (!isMethod(msg, "\xbc\x24\x4c\x11", 2) && - !isMethod(msg, "\x79\x20\x37\xe3", 3)) - return false; +bool makerdao_isClose(const EthereumSignTx *msg) { + // `shut(address,bytes32)` + // `shut(address,bytes32,address)` + if (!isMethod(msg, "\xbc\x24\x4c\x11", 2) && + !isMethod(msg, "\x79\x20\x37\xe3", 3)) + return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmClose(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmClose(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - const char *otcProvider = ""; - if (isMethod(msg, "\x79\x20\x37\xe3", 3)) { - if (confirmParamIsOTCProvider(getParam(msg, 2), msg->chain_id, &otcProvider)) - return false; - } + const char *otcProvider = ""; + if (isMethod(msg, "\x79\x20\x37\xe3", 3)) { + if (confirmParamIsOTCProvider(getParam(msg, 2), msg->chain_id, + &otcProvider)) + return false; + } - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Close CDP %" PRIu32 "%s?", cupId, otcProvider); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Close CDP %" PRIu32 "%s?", cupId, otcProvider); } -bool makerdao_isGive(const EthereumSignTx *msg) -{ - // `give(address,bytes32,address)` - if (!isMethod(msg, "\xda\x93\xdf\xcf", 3)) - return false; +bool makerdao_isGive(const EthereumSignTx *msg) { + // `give(address,bytes32,address)` + if (!isMethod(msg, "\xda\x93\xdf\xcf", 3)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (memcmp(getParam(msg, 2), "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) - return false; + if (memcmp(getParam(msg, 2), + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12) != 0) + return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmGive(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmGive(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - char new_owner[43] = "0x"; - ethereum_address_checksum(getParam(msg, 2) + 12, new_owner + 2, false, msg->chain_id); + char new_owner[43] = "0x"; + ethereum_address_checksum(getParam(msg, 2) + 12, new_owner + 2, false, + msg->chain_id); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Move CDP %" PRIu32 " to %s?", cupId, new_owner); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Move CDP %" PRIu32 " to %s?", cupId, new_owner); } -bool makerdao_isLockAndDraw2(const EthereumSignTx *msg) -{ - // `lockAndDraw(address,uint256)` - if (!isMethod(msg, "\x51\x6e\x9a\xec", 2)) - return false; +bool makerdao_isLockAndDraw2(const EthereumSignTx *msg) { + // `lockAndDraw(address,uint256)` + if (!isMethod(msg, "\x51\x6e\x9a\xec", 2)) return false; - return true; + return true; } -bool makerdao_confirmLockAndDraw2(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmLockAndDraw2(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - bignum256 deposit_val; - getETHValue(msg, &deposit_val); + bignum256 deposit_val; + getETHValue(msg, &deposit_val); - char deposit[32]; - ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, + sizeof(deposit)); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 1), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 1), 32, &withdraw_val); - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, + sizeof(withdraw)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Create CDP, deposit %s, and generate %s from it?", - deposit, withdraw); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Create CDP, deposit %s, and generate %s from it?", deposit, + withdraw); } -bool makerdao_isCreateOpenLockAndDraw(const EthereumSignTx *msg) -{ - // `createOpenLockAndDraw(address,address,uint256)` - if (!isMethod(msg, "\xd3\x14\x0a\x65", 3)) - return false; +bool makerdao_isCreateOpenLockAndDraw(const EthereumSignTx *msg) { + // `createOpenLockAndDraw(address,address,uint256)` + if (!isMethod(msg, "\xd3\x14\x0a\x65", 3)) return false; - return true; + return true; } -bool makerdao_confirmCreateOpenLockAndDraw(const EthereumSignTx *msg) -{ - if (!confirmParamIsRegistryAddress(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmCreateOpenLockAndDraw(const EthereumSignTx *msg) { + if (!confirmParamIsRegistryAddress(getParam(msg, 0), msg->chain_id)) + return false; - if (!confirmParamIsTub(getParam(msg, 1), msg->chain_id)) - return false; + if (!confirmParamIsTub(getParam(msg, 1), msg->chain_id)) return false; - bignum256 deposit_val; - getETHValue(msg, &deposit_val); + bignum256 deposit_val; + getETHValue(msg, &deposit_val); - char deposit[32]; - ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, + sizeof(deposit)); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, + sizeof(withdraw)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Create proxy, create CDP, deposit %s, and generate %s from it?", - deposit, withdraw); + return confirm( + ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Create proxy, create CDP, deposit %s, and generate %s from it?", deposit, + withdraw); } -bool makerdao_isLock(const EthereumSignTx *msg) -{ - // `lock(address,bytes32)` - if (!isMethod(msg, "\xbc\x25\xa8\x10", 2)) - return false; +bool makerdao_isLock(const EthereumSignTx *msg) { + // `lock(address,bytes32)` + if (!isMethod(msg, "\xbc\x25\xa8\x10", 2)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - return true; + return true; } -bool makerdao_confirmLock(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmLock(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - bignum256 deposit_val; - getETHValue(msg, &deposit_val); + bignum256 deposit_val; + getETHValue(msg, &deposit_val); - char deposit[32]; - ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, + sizeof(deposit)); - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Deposit %s into CDP %" PRIu32 "?", deposit, cupId); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Deposit %s into CDP %" PRIu32 "?", deposit, cupId); } -bool makerdao_isDraw(const EthereumSignTx *msg) -{ - // `draw(address,bytes32,uint256)` - if (!isMethod(msg, "\x03\x44\xa3\x6f", 3)) - return false; +bool makerdao_isDraw(const EthereumSignTx *msg) { + // `draw(address,bytes32,uint256)` + if (!isMethod(msg, "\x03\x44\xa3\x6f", 3)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmDraw(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmDraw(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, + sizeof(withdraw)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Generate %s from CDP %" PRIu32 "?", withdraw, cupId); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Generate %s from CDP %" PRIu32 "?", withdraw, cupId); } -bool makerdao_isLockAndDraw3(const EthereumSignTx *msg) -{ - // `lockAndDraw(address,bytes32,uint256)` - if (!isMethod(msg, "\x1e\xdf\x0c\x1e", 3)) - return false; +bool makerdao_isLockAndDraw3(const EthereumSignTx *msg) { + // `lockAndDraw(address,bytes32,uint256)` + if (!isMethod(msg, "\x1e\xdf\x0c\x1e", 3)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - return true; + return true; } -bool makerdao_confirmLockAndDraw3(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmLockAndDraw3(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - bignum256 deposit_val; - getETHValue(msg, &deposit_val); + bignum256 deposit_val; + getETHValue(msg, &deposit_val); - char deposit[32]; - ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, NULL, msg->chain_id, deposit, + sizeof(deposit)); - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, DAI, msg->chain_id, withdraw, + sizeof(withdraw)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Deposit %s into CDP %" PRIu32 " and generate %s?", - deposit, cupId, withdraw); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Deposit %s into CDP %" PRIu32 " and generate %s?", deposit, + cupId, withdraw); } -bool makerdao_isFree(const EthereumSignTx *msg) -{ - // `free(address,bytes32,uint256)` - if (!isMethod(msg, "\xf9\xef\x04\xbe", 3)) - return false; +bool makerdao_isFree(const EthereumSignTx *msg) { + // `free(address,bytes32,uint256)` + if (!isMethod(msg, "\xf9\xef\x04\xbe", 3)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmFree(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmFree(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, NULL, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, NULL, msg->chain_id, withdraw, + sizeof(withdraw)); - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Withdraw %s from CDP %" PRIu32 "?", - withdraw, cupId); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Withdraw %s from CDP %" PRIu32 "?", withdraw, cupId); } -bool makerdao_isWipe(const EthereumSignTx *msg) -{ - // `wipe(address,bytes,uint256)` - // `wipe(address,bytes,uint256,address)` - if (!isMethod(msg, "\xa3\xdc\x65\xa7", 3) && - !isMethod(msg, "\x8a\x9f\xc4\x75", 4)) - return false; +bool makerdao_isWipe(const EthereumSignTx *msg) { + // `wipe(address,bytes,uint256)` + // `wipe(address,bytes,uint256,address)` + if (!isMethod(msg, "\xa3\xdc\x65\xa7", 3) && + !isMethod(msg, "\x8a\x9f\xc4\x75", 4)) + return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmWipe(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmWipe(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - bignum256 deposit_val; - bn_from_bytes(getParam(msg, 2), 32, &deposit_val); + bignum256 deposit_val; + bn_from_bytes(getParam(msg, 2), 32, &deposit_val); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - char deposit[32]; - ethereumFormatAmount(&deposit_val, DAI, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, DAI, msg->chain_id, deposit, + sizeof(deposit)); - const char *otcProvider = ""; - if (isMethod(msg, "\x8a\x9f\xc4\x75", 4)) { - if (confirmParamIsOTCProvider(getParam(msg, 2), msg->chain_id, &otcProvider)) - return false; - } + const char *otcProvider = ""; + if (isMethod(msg, "\x8a\x9f\xc4\x75", 4)) { + if (confirmParamIsOTCProvider(getParam(msg, 2), msg->chain_id, + &otcProvider)) + return false; + } - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Payback %s into CDP %" PRIu32 "%s?", - deposit, cupId, otcProvider); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Payback %s into CDP %" PRIu32 "%s?", deposit, cupId, + otcProvider); } -bool makerdao_isWipeAndFree(const EthereumSignTx *msg) -{ - // `wipeAndFree(address,bytes32,uint256,uint256)` - // `wipeAndFree(address,bytes32,uint256,uint256,address)` - if (!isMethod(msg, "\xfa\xed\x77\xab", 4) && - !isMethod(msg, "\x1b\x96\x81\x60", 5)) - return false; +bool makerdao_isWipeAndFree(const EthereumSignTx *msg) { + // `wipeAndFree(address,bytes32,uint256,uint256)` + // `wipeAndFree(address,bytes32,uint256,uint256,address)` + if (!isMethod(msg, "\xfa\xed\x77\xab", 4) && + !isMethod(msg, "\x1b\x96\x81\x60", 5)) + return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - if (!isETHValueZero(msg)) - return false; + if (!isETHValueZero(msg)) return false; - return true; + return true; } -bool makerdao_confirmWipeAndFree(const EthereumSignTx *msg) -{ - if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) - return false; +bool makerdao_confirmWipeAndFree(const EthereumSignTx *msg) { + if (!confirmParamIsTub(getParam(msg, 0), msg->chain_id)) return false; - uint32_t cupId; - if (!getCupId(getParam(msg, 1), &cupId)) - return false; + uint32_t cupId; + if (!getCupId(getParam(msg, 1), &cupId)) return false; - bignum256 deposit_val; - bn_from_bytes(getParam(msg, 2), 32, &deposit_val); + bignum256 deposit_val; + bn_from_bytes(getParam(msg, 2), 32, &deposit_val); - const TokenType *DAI; - if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) - return false; + const TokenType *DAI; + if (!tokenByTicker(msg->chain_id, "DAI", &DAI)) return false; - char deposit[32]; - ethereumFormatAmount(&deposit_val, DAI, msg->chain_id, deposit, sizeof(deposit)); + char deposit[32]; + ethereumFormatAmount(&deposit_val, DAI, msg->chain_id, deposit, + sizeof(deposit)); - bignum256 withdraw_val; - bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); + bignum256 withdraw_val; + bn_from_bytes(getParam(msg, 2), 32, &withdraw_val); - char withdraw[32]; - ethereumFormatAmount(&withdraw_val, NULL, msg->chain_id, withdraw, sizeof(withdraw)); + char withdraw[32]; + ethereumFormatAmount(&withdraw_val, NULL, msg->chain_id, withdraw, + sizeof(withdraw)); - const char *otcProvider = ""; - if (isMethod(msg, "\x1b\x96\x81\x60", 5)) { - if (!confirmParamIsOTCProvider(getParam(msg, 4), msg->chain_id, &otcProvider)) - return false; - } + const char *otcProvider = ""; + if (isMethod(msg, "\x1b\x96\x81\x60", 5)) { + if (!confirmParamIsOTCProvider(getParam(msg, 4), msg->chain_id, + &otcProvider)) + return false; + } - return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", - "Payback %s and withdraw %s from CDP %" PRIu32 "%s?", - deposit, withdraw, cupId, otcProvider); + return confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "MakerDAO", + "Payback %s and withdraw %s from CDP %" PRIu32 "%s?", deposit, + withdraw, cupId, otcProvider); } -bool makerdao_isMakerDAO(uint32_t data_total, const EthereumSignTx *msg) -{ - if (!msg->has_chain_id) - return false; +bool makerdao_isMakerDAO(uint32_t data_total, const EthereumSignTx *msg) { + if (!msg->has_chain_id) return false; - if (data_total != msg->data_initial_chunk.size) - return false; + if (data_total != msg->data_initial_chunk.size) return false; - if (makerdao_isOpen(msg)) - return true; + if (makerdao_isOpen(msg)) return true; - if (makerdao_isClose(msg)) - return true; + if (makerdao_isClose(msg)) return true; - if (makerdao_isGive(msg)) - return true; + if (makerdao_isGive(msg)) return true; - if (makerdao_isLockAndDraw2(msg)) - return true; + if (makerdao_isLockAndDraw2(msg)) return true; - if (makerdao_isCreateOpenLockAndDraw(msg)) - return true; + if (makerdao_isCreateOpenLockAndDraw(msg)) return true; - if (makerdao_isLock(msg)) - return true; + if (makerdao_isLock(msg)) return true; - if (makerdao_isDraw(msg)) - return true; + if (makerdao_isDraw(msg)) return true; - if (makerdao_isLockAndDraw3(msg)) - return true; + if (makerdao_isLockAndDraw3(msg)) return true; - if (makerdao_isFree(msg)) - return true; + if (makerdao_isFree(msg)) return true; - if (makerdao_isWipe(msg)) - return true; + if (makerdao_isWipe(msg)) return true; - if (makerdao_isWipeAndFree(msg)) - return true; + if (makerdao_isWipeAndFree(msg)) return true; - return false; + return false; } -bool makerdao_confirmMakerDAO(uint32_t data_total, const EthereumSignTx *msg) -{ - (void)data_total; +bool makerdao_confirmMakerDAO(uint32_t data_total, const EthereumSignTx *msg) { + (void)data_total; - if (isProxyCall(msg)) { - if (!confirmProxyCall(msg)) { - return false; - } - } else { - if (!confirmSaiProxyCreateAndExecuteAddress(msg->to.bytes, msg->chain_id)) { - return false; - } + if (isProxyCall(msg)) { + if (!confirmProxyCall(msg)) { + return false; } + } else { + if (!confirmSaiProxyCreateAndExecuteAddress(msg->to.bytes, msg->chain_id)) { + return false; + } + } - if (makerdao_isOpen(msg)) - return makerdao_confirmOpen(msg); + if (makerdao_isOpen(msg)) return makerdao_confirmOpen(msg); - if (makerdao_isClose(msg)) - return makerdao_confirmClose(msg); + if (makerdao_isClose(msg)) return makerdao_confirmClose(msg); - if (makerdao_isGive(msg)) - return makerdao_confirmGive(msg); + if (makerdao_isGive(msg)) return makerdao_confirmGive(msg); - if (makerdao_isLockAndDraw2(msg)) - return makerdao_confirmLockAndDraw2(msg); + if (makerdao_isLockAndDraw2(msg)) return makerdao_confirmLockAndDraw2(msg); - if (makerdao_isCreateOpenLockAndDraw(msg)) - return makerdao_confirmCreateOpenLockAndDraw(msg); + if (makerdao_isCreateOpenLockAndDraw(msg)) + return makerdao_confirmCreateOpenLockAndDraw(msg); - if (makerdao_isLock(msg)) - return makerdao_confirmLock(msg); + if (makerdao_isLock(msg)) return makerdao_confirmLock(msg); - if (makerdao_isDraw(msg)) - return makerdao_confirmDraw(msg); + if (makerdao_isDraw(msg)) return makerdao_confirmDraw(msg); - if (makerdao_isLockAndDraw3(msg)) - return makerdao_confirmLockAndDraw3(msg); + if (makerdao_isLockAndDraw3(msg)) return makerdao_confirmLockAndDraw3(msg); - if (makerdao_isFree(msg)) - return makerdao_confirmFree(msg); + if (makerdao_isFree(msg)) return makerdao_confirmFree(msg); - if (makerdao_isWipe(msg)) - return makerdao_confirmWipe(msg); + if (makerdao_isWipe(msg)) return makerdao_confirmWipe(msg); - if (makerdao_isWipeAndFree(msg)) - return makerdao_confirmWipeAndFree(msg); + if (makerdao_isWipeAndFree(msg)) return makerdao_confirmWipeAndFree(msg); - return false; + return false; } - diff --git a/lib/firmware/ethereum_tokens.c b/lib/firmware/ethereum_tokens.c index f97d8a7f3..e0d4003f2 100644 --- a/lib/firmware/ethereum_tokens.c +++ b/lib/firmware/ethereum_tokens.c @@ -6,83 +6,88 @@ const TokenType tokens[] = { #define X(CHAIN_ID, CONTRACT_ADDR, TICKER, DECIMALS) \ - { (CONTRACT_ADDR), (TICKER), (CHAIN_ID), (DECIMALS) }, + {(CONTRACT_ADDR), (TICKER), (CHAIN_ID), (DECIMALS)}, #include "keepkey/firmware/ethereum_tokens.def" }; _Static_assert(sizeof(tokens) / sizeof(tokens[0]) == TOKENS_COUNT, "TOKENS_COUNT mismatch"); -static const TokenType Unknown = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", " UNKN", 1, 0 }; +static const TokenType Unknown = { + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00", + " UNKN", 1, 0}; const TokenType *UnknownToken = (const TokenType *)&Unknown; -const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) -{ - if (!address) return 0; - for (int i = 0; i < TOKENS_COUNT; i++) { - if (chain_id == tokens[i].chain_id && memcmp(address, tokens[i].address, 20) == 0) { - return &(tokens[i]); - } - } - return UnknownToken; +const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) { + if (!address) return 0; + for (int i = 0; i < TOKENS_COUNT; i++) { + if (chain_id == tokens[i].chain_id && + memcmp(address, tokens[i].address, 20) == 0) { + return &(tokens[i]); + } + } + return UnknownToken; } -bool tokenByTicker(uint8_t chain_id, const char *ticker, const TokenType **token) { - *token = NULL; - - // First look in the legacy table, confirming that the entry also exists in - // the new table: - for (int i = 0; i < COINS_COUNT; i++) { - if (!coins[i].has_contract_address) { - continue; - } - if (strcmp(ticker, coins[i].coin_shortcut) == 0) { - *token = tokenByChainAddress(1, coins[i].contract_address.bytes); - if (*token == UnknownToken) - return false; - return true; - } - } - - // Then look in the new table: - for (int i = 0; i < TOKENS_COUNT; i++) { - if (chain_id == tokens[i].chain_id && strcmp(ticker, tokens[i].ticker + 1) == 0) { - if (!*token) - *token = &tokens[i]; - else - return false; - } - } - return *token; +bool tokenByTicker(uint8_t chain_id, const char *ticker, + const TokenType **token) { + *token = NULL; + + // First look in the legacy table, confirming that the entry also exists in + // the new table: + for (int i = 0; i < COINS_COUNT; i++) { + if (!coins[i].has_contract_address) { + continue; + } + if (strcmp(ticker, coins[i].coin_shortcut) == 0) { + *token = tokenByChainAddress(1, coins[i].contract_address.bytes); + if (*token == UnknownToken) return false; + return true; + } + } + + // Then look in the new table: + for (int i = 0; i < TOKENS_COUNT; i++) { + if (chain_id == tokens[i].chain_id && + strcmp(ticker, tokens[i].ticker + 1) == 0) { + if (!*token) + *token = &tokens[i]; + else + return false; + } + } + return *token; } void coinFromToken(CoinType *coin, const TokenType *token) { - memset(coin, 0, sizeof(*coin)); + memset(coin, 0, sizeof(*coin)); - coin->has_coin_name = true; - strncpy(&coin->coin_name[0], token->ticker + 1, sizeof(coin->coin_name)); + coin->has_coin_name = true; + strncpy(&coin->coin_name[0], token->ticker + 1, sizeof(coin->coin_name)); - coin->has_coin_shortcut = true; - strncpy(&coin->coin_shortcut[0], token->ticker + 1, sizeof(coin->coin_shortcut)); + coin->has_coin_shortcut = true; + strncpy(&coin->coin_shortcut[0], token->ticker + 1, + sizeof(coin->coin_shortcut)); - coin->has_forkid = true; - coin->forkid = token->chain_id; + coin->has_forkid = true; + coin->forkid = token->chain_id; - coin->has_maxfee_kb = true; - coin->maxfee_kb = 100000; + coin->has_maxfee_kb = true; + coin->maxfee_kb = 100000; - coin->has_bip44_account_path = true; - coin->bip44_account_path = 0x8000003C; + coin->has_bip44_account_path = true; + coin->bip44_account_path = 0x8000003C; - coin->has_decimals = true; - coin->decimals = token->decimals; + coin->has_decimals = true; + coin->decimals = token->decimals; - coin->has_contract_address = true; - coin->contract_address.size = 20; - memcpy((char*)&coin->contract_address.bytes[0], token->address, 20); - _Static_assert(20 <= sizeof(coin->contract_address.bytes), - "contract_address is not large enough to hold an ETH address"); + coin->has_contract_address = true; + coin->contract_address.size = 20; + memcpy((char *)&coin->contract_address.bytes[0], token->address, 20); + _Static_assert(20 <= sizeof(coin->contract_address.bytes), + "contract_address is not large enough to hold an ETH address"); - coin->has_curve_name = true; - strncpy(&coin->curve_name[0], "secp256k1", sizeof(coin->curve_name)); + coin->has_curve_name = true; + strncpy(&coin->curve_name[0], "secp256k1", sizeof(coin->curve_name)); } diff --git a/lib/firmware/exchange.c b/lib/firmware/exchange.c index c15753b21..e13ae96fc 100644 --- a/lib/firmware/exchange.c +++ b/lib/firmware/exchange.c @@ -47,7 +47,8 @@ static const char *exchange_msg = NULL; static const char *ShapeShift_pubkey = "1HxFWu1wM88q1aLkfUmpZBjhTWcdXGB6gT"; /* - * exchange_tx_layout_str() - assemble display message for exchange transaction output + * exchange_tx_layout_str() - assemble display message for exchange transaction + * output * * INPUT * coint - coin type being process @@ -60,60 +61,60 @@ static const char *ShapeShift_pubkey = "1HxFWu1wM88q1aLkfUmpZBjhTWcdXGB6gT"; * true/false - status * */ -static bool exchange_tx_layout_str(const CoinType *coin, const uint8_t *amt, size_t amt_len, char *out, size_t out_len) -{ - const TokenType *token = NULL; - if (!isEthereumLike(coin->coin_name) && coin->has_contract_address) { - if (!coin->has_forkid) - return false; - - token = tokenByChainAddress(coin->forkid, coin->contract_address.bytes); - } +static bool exchange_tx_layout_str(const CoinType *coin, const uint8_t *amt, + size_t amt_len, char *out, size_t out_len) { + const TokenType *token = NULL; + if (!isEthereumLike(coin->coin_name) && coin->has_contract_address) { + if (!coin->has_forkid) return false; - if (isEthereumLike(coin->coin_name) || token) { - if (!coin->has_forkid) - return false; + token = tokenByChainAddress(coin->forkid, coin->contract_address.bytes); + } - bignum256 value; - bn_from_bytes(amt, amt_len, &value); - ethereumFormatAmount(&value, token, coin->forkid, out, out_len); - return true; - } + if (isEthereumLike(coin->coin_name) || token) { + if (!coin->has_forkid) return false; - if (amt_len <= sizeof(uint64_t)) { - uint8_t amt_rev[sizeof(uint64_t)]; - memset(amt_rev, 0, sizeof(amt_rev)); - memcpy(amt_rev, amt, amt_len); - rev_byte_order(amt_rev, amt_len); - uint64_t amount64; - memcpy(&amount64, amt_rev, sizeof(amount64)); - coin_amnt_to_str(coin, amount64, out, out_len); - return true; - } + bignum256 value; + bn_from_bytes(amt, amt_len, &value); + ethereumFormatAmount(&value, token, coin->forkid, out, out_len); + return true; + } + + if (amt_len <= sizeof(uint64_t)) { + uint8_t amt_rev[sizeof(uint64_t)]; + memset(amt_rev, 0, sizeof(amt_rev)); + memcpy(amt_rev, amt, amt_len); + rev_byte_order(amt_rev, amt_len); + uint64_t amount64; + memcpy(&amount64, amt_rev, sizeof(amount64)); + coin_amnt_to_str(coin, amount64, out, out_len); + return true; + } - return false; + return false; } -/// \returns true iff two addresses match. Ignores differencess in leading '0x' for ETH-like addresses. -bool addresses_same(const char *LHS, size_t LHS_len, const char *RHS, size_t RHS_len, bool isETH) -{ - if (isETH) { - if (LHS[0] == '0' && (LHS[1] == 'x' || LHS[1] == 'X')) { - LHS += 2; - LHS_len -= 2; - } - - if (RHS[0] == '0' && (RHS[1] == 'x' || RHS[1] == 'X')) { - RHS += 2; - RHS_len -= 2; - } +/// \returns true iff two addresses match. Ignores differencess in leading '0x' +/// for ETH-like addresses. +bool addresses_same(const char *LHS, size_t LHS_len, const char *RHS, + size_t RHS_len, bool isETH) { + if (isETH) { + if (LHS[0] == '0' && (LHS[1] == 'x' || LHS[1] == 'X')) { + LHS += 2; + LHS_len -= 2; } - return strncasecmp(LHS, RHS, MIN(LHS_len, RHS_len)) == 0; + if (RHS[0] == '0' && (RHS[1] == 'x' || RHS[1] == 'X')) { + RHS += 2; + RHS_len -= 2; + } + } + + return strncasecmp(LHS, RHS, MIN(LHS_len, RHS_len)) == 0; } /* - * verify_exchange_address - verify address specified in exchange contract belongs to device. + * verify_exchange_address - verify address specified in exchange contract + * belongs to device. * * INPUT * coin - the CoinType @@ -126,77 +127,74 @@ bool addresses_same(const char *LHS, size_t LHS_len, const char *RHS, size_t RHS * OUTPUT * true/false - success/failure */ -static bool verify_exchange_address(const CoinType *coin, size_t address_n_count, - const uint32_t *address_n, bool has_script_type, - InputScriptType script_type, - const char *address_str, size_t address_str_len, - const HDNode *root, bool is_token) -{ - static CONFIDENTIAL HDNode node; - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - memzero(&node, sizeof(node)); - return false; - } - - if (isEthereumLike(coin->coin_name) || is_token) { - char tx_out_address[sizeof(((ExchangeAddress *)NULL)->address)]; - EthereumAddress_address_t ethereum_addr; +static bool verify_exchange_address( + const CoinType *coin, size_t address_n_count, const uint32_t *address_n, + bool has_script_type, InputScriptType script_type, const char *address_str, + size_t address_str_len, const HDNode *root, bool is_token) { + static CONFIDENTIAL HDNode node; + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { + memzero(&node, sizeof(node)); + return false; + } - ethereum_addr.size = 20; - if (hdnode_get_ethereum_pubkeyhash(&node, ethereum_addr.bytes) == 0) { - memzero(&node, sizeof(node)); - return false; - } + if (isEthereumLike(coin->coin_name) || is_token) { + char tx_out_address[sizeof(((ExchangeAddress *)NULL)->address)]; + EthereumAddress_address_t ethereum_addr; - data2hex((char *)ethereum_addr.bytes, 20, tx_out_address); - return addresses_same(tx_out_address, sizeof(tx_out_address), - address_str, address_str_len, true); + ethereum_addr.size = 20; + if (hdnode_get_ethereum_pubkeyhash(&node, ethereum_addr.bytes) == 0) { + memzero(&node, sizeof(node)); + return false; } - if (strcmp("Cosmos", coin->coin_name) == 0) { - char cosmos_addr[sizeof(((CosmosAddress *)0)->address)]; - if (!tendermint_getAddress(&node, "cosmos", cosmos_addr)) { - memzero(&node, sizeof(node)); - return false; - } + data2hex((char *)ethereum_addr.bytes, 20, tx_out_address); + return addresses_same(tx_out_address, sizeof(tx_out_address), address_str, + address_str_len, true); + } - return strncmp(cosmos_addr, address_str, address_str_len); + if (strcmp("Cosmos", coin->coin_name) == 0) { + char cosmos_addr[sizeof(((CosmosAddress *)0)->address)]; + if (!tendermint_getAddress(&node, "cosmos", cosmos_addr)) { + memzero(&node, sizeof(node)); + return false; } - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) { - memzero(&node, sizeof(node)); - return false; - } + return strncmp(cosmos_addr, address_str, address_str_len); + } - if (!has_script_type) - script_type = InputScriptType_SPENDADDRESS; + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) { + memzero(&node, sizeof(node)); + return false; + } - char tx_out_address[MAX_ADDR_SIZE]; - hdnode_fill_public_key(&node); + if (!has_script_type) script_type = InputScriptType_SPENDADDRESS; - // Unfortunately we can't do multisig here, since it makes the ExchangeType - // message too large from having two MultisigRedeemScriptType members for - // return/withdrawal respectively. - if (compute_address(coin, script_type, &node, false, NULL, tx_out_address) && - strncmp(tx_out_address, address_str, sizeof(tx_out_address)) == 0) { - memzero(&node, sizeof(node)); - return true; - } + char tx_out_address[MAX_ADDR_SIZE]; + hdnode_fill_public_key(&node); - if (!coin->has_cashaddr_prefix) { - memzero(&node, sizeof(node)); - return false; - } + // Unfortunately we can't do multisig here, since it makes the ExchangeType + // message too large from having two MultisigRedeemScriptType members for + // return/withdrawal respectively. + if (compute_address(coin, script_type, &node, false, NULL, tx_out_address) && + strncmp(tx_out_address, address_str, sizeof(tx_out_address)) == 0) { + memzero(&node, sizeof(node)); + return true; + } - // On coins supporting cashaddr (BCH, BSV), also support address comparison - // on the legacy format. - ecdsa_get_address(node.public_key, coin->address_type, curve->hasher_pubkey, - curve->hasher_base58, tx_out_address, - sizeof(tx_out_address)); + if (!coin->has_cashaddr_prefix) { memzero(&node, sizeof(node)); - return strncmp(tx_out_address, address_str, sizeof(tx_out_address)) == 0; + return false; + } + + // On coins supporting cashaddr (BCH, BSV), also support address comparison + // on the legacy format. + ecdsa_get_address(node.public_key, coin->address_type, curve->hasher_pubkey, + curve->hasher_base58, tx_out_address, + sizeof(tx_out_address)); + memzero(&node, sizeof(node)); + return strncmp(tx_out_address, address_str, sizeof(tx_out_address)) == 0; } /* @@ -209,43 +207,40 @@ static bool verify_exchange_address(const CoinType *coin, size_t address_n_count * OUTPUT * true/false - success/failure */ -bool verify_exchange_coin(const char *coin1, const char *coin2, uint32_t len) -{ - if (strncasecmp(coin1, coin2, len) == 0) - return true; +bool verify_exchange_coin(const char *coin1, const char *coin2, uint32_t len) { + if (strncasecmp(coin1, coin2, len) == 0) return true; - const CoinType *response_coin = coinByNameOrTicker(coin2); - if (!response_coin) - return false; + const CoinType *response_coin = coinByNameOrTicker(coin2); + if (!response_coin) return false; - if (strncasecmp(coin1, response_coin->coin_shortcut, len) == 0) - return true; + if (strncasecmp(coin1, response_coin->coin_shortcut, len) == 0) return true; - return strncmp(coin1, response_coin->coin_name, len) == 0; + return strncmp(coin1, response_coin->coin_name, len) == 0; } -static const CoinType *getWithdrawCoin(const ExchangeType *exchange) -{ - const CoinType *coin = coinByNameOrTicker(exchange->signed_exchange_response.responseV2.withdrawal_address.coin_type); +static const CoinType *getWithdrawCoin(const ExchangeType *exchange) { + const CoinType *coin = + coinByNameOrTicker(exchange->signed_exchange_response.responseV2 + .withdrawal_address.coin_type); - if (!coin) - coin = coinByNameOrTicker(exchange->withdrawal_coin_name); + if (!coin) coin = coinByNameOrTicker(exchange->withdrawal_coin_name); - return coin; + return coin; } -static const CoinType *getDepositCoin(const ExchangeType *exchange) -{ - return coinByNameOrTicker(exchange->signed_exchange_response.responseV2.deposit_address.coin_type); +static const CoinType *getDepositCoin(const ExchangeType *exchange) { + return coinByNameOrTicker( + exchange->signed_exchange_response.responseV2.deposit_address.coin_type); } -static const CoinType *getReturnCoin(const ExchangeType *exchange) -{ - return coinByNameOrTicker(exchange->signed_exchange_response.responseV2.return_address.coin_type); +static const CoinType *getReturnCoin(const ExchangeType *exchange) { + return coinByNameOrTicker( + exchange->signed_exchange_response.responseV2.return_address.coin_type); } /* - * verify_exchange_dep_amount() Verify deposit amount specified in exchange contract + * verify_exchange_dep_amount() Verify deposit amount specified in exchange + * contract * * INPUT * coin - name of coin being compare for the amount value @@ -258,39 +253,33 @@ static const CoinType *getReturnCoin(const ExchangeType *exchange) */ static bool verify_exchange_dep_amount( const char *coin, void *dep_amt_ptr, - const ExchangeResponseV2_deposit_amount_t *exch_dep_amt) -{ - char amt_str[sizeof(exch_dep_amt->bytes)]; - memset(amt_str, 0, sizeof(amt_str)); - if (isEthereumLike(coin)) { - memcpy(amt_str, exch_dep_amt->bytes, exch_dep_amt->size); - } else { - if (exch_dep_amt->size > sizeof(uint64_t)) - return false; - - memcpy(amt_str, exch_dep_amt->bytes, exch_dep_amt->size); - rev_byte_order((uint8_t *)amt_str, exch_dep_amt->size); - } - - return memcmp(amt_str, dep_amt_ptr, exch_dep_amt->size) == 0; + const ExchangeResponseV2_deposit_amount_t *exch_dep_amt) { + char amt_str[sizeof(exch_dep_amt->bytes)]; + memset(amt_str, 0, sizeof(amt_str)); + if (isEthereumLike(coin)) { + memcpy(amt_str, exch_dep_amt->bytes, exch_dep_amt->size); + } else { + if (exch_dep_amt->size > sizeof(uint64_t)) return false; + + memcpy(amt_str, exch_dep_amt->bytes, exch_dep_amt->size); + rev_byte_order((uint8_t *)amt_str, exch_dep_amt->size); + } + + return memcmp(amt_str, dep_amt_ptr, exch_dep_amt->size) == 0; } /// \brief Loose matching of two coins. /// /// Note: we can't just do pointer comparison here, since one of the coins /// might be constructed from the Token table. -static bool verify_coins_match(const CoinType *lhs, const CoinType *rhs) -{ - if (!lhs || !rhs) - return false; +static bool verify_coins_match(const CoinType *lhs, const CoinType *rhs) { + if (!lhs || !rhs) return false; - if (strcasecmp(lhs->coin_shortcut, rhs->coin_shortcut) == 0) - return true; + if (strcasecmp(lhs->coin_shortcut, rhs->coin_shortcut) == 0) return true; - if (strcasecmp(lhs->coin_name, rhs->coin_name) == 0) - return true; + if (strcasecmp(lhs->coin_name, rhs->coin_name) == 0) return true; - return false; + return false; } /* @@ -302,192 +291,194 @@ static bool verify_coins_match(const CoinType *lhs, const CoinType *rhs) * OUTPUT * true/false - success/failure */ -static bool verify_exchange_contract(const CoinType *coin, void *vtx_out, const HDNode *root) -{ - const ExchangeType *exchange; - if (isEthereumLike(coin->coin_name)) { - exchange = &((EthereumSignTx *)vtx_out)->exchange_type; - } else if (strcmp("Cosmos", coin->coin_name) == 0) { - exchange = &((CosmosMsgSend *)vtx_out)->exchange_type; - } else if (strcmp("Binance", coin->coin_name) == 0) { - exchange = &((BinanceTransferMsg *)vtx_out)->outputs[0].exchange_type; - } else if (strcmp("Ripple", coin->coin_name) == 0) { - // TODO: Support Ripple exchanges. - return false; - } else { - exchange = &((TxOutputType *)vtx_out)->exchange_type; - } +static bool verify_exchange_contract(const CoinType *coin, void *vtx_out, + const HDNode *root) { + const ExchangeType *exchange; + if (isEthereumLike(coin->coin_name)) { + exchange = &((EthereumSignTx *)vtx_out)->exchange_type; + } else if (strcmp("Cosmos", coin->coin_name) == 0) { + exchange = &((CosmosMsgSend *)vtx_out)->exchange_type; + } else if (strcmp("Binance", coin->coin_name) == 0) { + exchange = &((BinanceTransferMsg *)vtx_out)->outputs[0].exchange_type; + } else if (strcmp("Ripple", coin->coin_name) == 0) { + // TODO: Support Ripple exchanges. + return false; + } else { + exchange = &((TxOutputType *)vtx_out)->exchange_type; + } - if (!exchange->has_signed_exchange_response || - !exchange->signed_exchange_response.has_responseV2) { + if (!exchange->has_signed_exchange_response || + !exchange->signed_exchange_response.has_responseV2) { + set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); + return false; + } + + void *tx_out_amount; + char tx_out_address[sizeof(((ExchangeAddress *)NULL)->address)]; + memset(tx_out_address, 0, sizeof(tx_out_address)); + CoinType standard_deposit; + const CoinType *deposit_coin = NULL; + if (isEthereumLike(coin->coin_name)) { + EthereumSignTx *tx_out = (EthereumSignTx *)vtx_out; + tx_out->has_chain_id = coin->has_forkid; + tx_out->chain_id = coin->forkid; + + if (ethereum_isStandardERC20Transfer(tx_out)) { + if (!ethereum_getStandardERC20Recipient(tx_out, tx_out_address, + sizeof(tx_out_address)) || + !ethereum_getStandardERC20Amount(tx_out, &tx_out_amount) || + !ethereum_getStandardERC20Coin(tx_out, &standard_deposit)) { set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); return false; - } - - void *tx_out_amount; - char tx_out_address[sizeof(((ExchangeAddress *)NULL)->address)]; - memset(tx_out_address, 0, sizeof(tx_out_address)); - CoinType standard_deposit; - const CoinType *deposit_coin = NULL; - if (isEthereumLike(coin->coin_name)) { - EthereumSignTx *tx_out = (EthereumSignTx *)vtx_out; - tx_out->has_chain_id = coin->has_forkid; - tx_out->chain_id = coin->forkid; - - if (ethereum_isStandardERC20Transfer(tx_out)) { - if (!ethereum_getStandardERC20Recipient(tx_out, tx_out_address, sizeof(tx_out_address)) || - !ethereum_getStandardERC20Amount(tx_out, &tx_out_amount) || - !ethereum_getStandardERC20Coin(tx_out, &standard_deposit)) { - set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); - return false; - } - deposit_coin = &standard_deposit; - } else { - data2hex(tx_out->to.bytes, tx_out->to.size, tx_out_address); - tx_out_amount = (void *)tx_out->value.bytes; - deposit_coin = coin; - } - } else if (strcmp("Cosmos", coin->coin_name) == 0) { - CosmosMsgSend *tx_out = (CosmosMsgSend *)vtx_out; - exchange = &tx_out->exchange_type; - memcpy(tx_out_address, tx_out->to_address, sizeof(tx_out->to_address)); - tx_out_amount = (void *)&tx_out->amount; - deposit_coin = coin; - } else if (strcmp("Binance", coin->coin_name) == 0) { - BinanceTransferMsg *tx_out = (BinanceTransferMsg *)vtx_out; - exchange = &tx_out->outputs[0].exchange_type; - memcpy(tx_out_address, tx_out->outputs[0].address, sizeof(tx_out->outputs[0].address)); - tx_out_amount = (void *)&tx_out->outputs[0].coins[0].amount; - deposit_coin = coin; + } + deposit_coin = &standard_deposit; } else { - TxOutputType *tx_out = (TxOutputType *)vtx_out; - exchange = &tx_out->exchange_type; - memcpy(tx_out_address, tx_out->address, sizeof(tx_out->address)); - tx_out_amount = (void *)&tx_out->amount; - deposit_coin = coin; - } + data2hex(tx_out->to.bytes, tx_out->to.size, tx_out_address); + tx_out_amount = (void *)tx_out->value.bytes; + deposit_coin = coin; + } + } else if (strcmp("Cosmos", coin->coin_name) == 0) { + CosmosMsgSend *tx_out = (CosmosMsgSend *)vtx_out; + exchange = &tx_out->exchange_type; + memcpy(tx_out_address, tx_out->to_address, sizeof(tx_out->to_address)); + tx_out_amount = (void *)&tx_out->amount; + deposit_coin = coin; + } else if (strcmp("Binance", coin->coin_name) == 0) { + BinanceTransferMsg *tx_out = (BinanceTransferMsg *)vtx_out; + exchange = &tx_out->outputs[0].exchange_type; + memcpy(tx_out_address, tx_out->outputs[0].address, + sizeof(tx_out->outputs[0].address)); + tx_out_amount = (void *)&tx_out->outputs[0].coins[0].amount; + deposit_coin = coin; + } else { + TxOutputType *tx_out = (TxOutputType *)vtx_out; + exchange = &tx_out->exchange_type; + memcpy(tx_out_address, tx_out->address, sizeof(tx_out->address)); + tx_out_amount = (void *)&tx_out->amount; + deposit_coin = coin; + } + + if (!deposit_coin) { + set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); + return false; + } - if (!deposit_coin) { - set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); - return false; - } + /* verify Exchange signature */ + uint8_t response_raw[sizeof(ExchangeResponseV2)]; + memset(response_raw, 0, sizeof(response_raw)); + int response_raw_filled_len = + encode_pb((const void *)&exchange->signed_exchange_response.responseV2, + ExchangeResponseV2_fields, response_raw, sizeof(response_raw)); - /* verify Exchange signature */ - uint8_t response_raw[sizeof(ExchangeResponseV2)]; - memset(response_raw, 0, sizeof(response_raw)); - int response_raw_filled_len = encode_pb( - (const void *)&exchange->signed_exchange_response.responseV2, - ExchangeResponseV2_fields, - response_raw, - sizeof(response_raw)); - - if(response_raw_filled_len == 0) - { - set_exchange_error(ERROR_EXCHANGE_SIGNATURE); - return false; - } + if (response_raw_filled_len == 0) { + set_exchange_error(ERROR_EXCHANGE_SIGNATURE); + return false; + } - const CoinType *signed_coin = coinByShortcut((const char *)"BTC"); + const CoinType *signed_coin = coinByShortcut((const char *)"BTC"); #if DEBUG_LINK - if (memcmp(exchange->signed_exchange_response.signature.bytes, - "FAKE_SIG", sizeof("FAKE_SIG")) != 0 && - cryptoMessageVerify(signed_coin, response_raw, response_raw_filled_len, ShapeShift_pubkey, - (uint8_t *)exchange->signed_exchange_response.signature.bytes) != 0) + if (memcmp(exchange->signed_exchange_response.signature.bytes, "FAKE_SIG", + sizeof("FAKE_SIG")) != 0 && + cryptoMessageVerify( + signed_coin, response_raw, response_raw_filled_len, ShapeShift_pubkey, + (uint8_t *)exchange->signed_exchange_response.signature.bytes) != 0) #else - if (cryptoMessageVerify(signed_coin, response_raw, response_raw_filled_len, ShapeShift_pubkey, - (uint8_t *)exchange->signed_exchange_response.signature.bytes) != 0) + if (cryptoMessageVerify( + signed_coin, response_raw, response_raw_filled_len, ShapeShift_pubkey, + (uint8_t *)exchange->signed_exchange_response.signature.bytes) != 0) #endif - { - set_exchange_error(ERROR_EXCHANGE_SIGNATURE); - return false; - } - - /* verify Deposit coin type */ - if (!verify_coins_match(deposit_coin, getDepositCoin(exchange))) { - set_exchange_error(ERROR_EXCHANGE_DEPOSIT_COINTYPE); - return false; - } + { + set_exchange_error(ERROR_EXCHANGE_SIGNATURE); + return false; + } - /* verify Deposit address */ - if(!addresses_same(tx_out_address, sizeof(tx_out_address), - exchange->signed_exchange_response.responseV2.deposit_address.address, - sizeof(exchange->signed_exchange_response.responseV2.deposit_address.address), - isEthereumLike(coin->coin_name))) - { - set_exchange_error(ERROR_EXCHANGE_DEPOSIT_ADDRESS); - return false; - } + /* verify Deposit coin type */ + if (!verify_coins_match(deposit_coin, getDepositCoin(exchange))) { + set_exchange_error(ERROR_EXCHANGE_DEPOSIT_COINTYPE); + return false; + } + + /* verify Deposit address */ + if (!addresses_same( + tx_out_address, sizeof(tx_out_address), + exchange->signed_exchange_response.responseV2.deposit_address.address, + sizeof(exchange->signed_exchange_response.responseV2.deposit_address + .address), + isEthereumLike(coin->coin_name))) { + set_exchange_error(ERROR_EXCHANGE_DEPOSIT_ADDRESS); + return false; + } - /* verify Deposit amount*/ - if(!verify_exchange_dep_amount(coin->coin_name, - tx_out_amount, &exchange->signed_exchange_response.responseV2.deposit_amount)) - { - set_exchange_error(ERROR_EXCHANGE_DEPOSIT_AMOUNT); + /* verify Deposit amount*/ + if (!verify_exchange_dep_amount( + coin->coin_name, tx_out_amount, + &exchange->signed_exchange_response.responseV2.deposit_amount)) { + set_exchange_error(ERROR_EXCHANGE_DEPOSIT_AMOUNT); + return false; + } + + /* verify Withdrawal address */ + const CoinType *withdraw_coin = getWithdrawCoin(exchange); + if (withdraw_coin) { + if (!verify_coins_match( + withdraw_coin, + coinByNameOrTicker(exchange->withdrawal_coin_name))) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_COINTYPE); + return false; + } + + if (exchange->withdrawal_address_n_count) { + if (!verify_exchange_address( + withdraw_coin, exchange->withdrawal_address_n_count, + exchange->withdrawal_address_n, + exchange->has_withdrawal_script_type, + exchange->withdrawal_script_type, + exchange->signed_exchange_response.responseV2.withdrawal_address + .address, + sizeof(exchange->signed_exchange_response.responseV2 + .withdrawal_address.address), + root, withdraw_coin->has_contract_address)) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); return false; + } } - - /* verify Withdrawal address */ - const CoinType *withdraw_coin = getWithdrawCoin(exchange); - if (withdraw_coin) { - if (!verify_coins_match(withdraw_coin, coinByNameOrTicker(exchange->withdrawal_coin_name))) { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_COINTYPE); - return false; - } - - if (exchange->withdrawal_address_n_count) { - if (!verify_exchange_address( - withdraw_coin, - exchange->withdrawal_address_n_count, - exchange->withdrawal_address_n, - exchange->has_withdrawal_script_type, - exchange->withdrawal_script_type, - exchange->signed_exchange_response.responseV2.withdrawal_address.address, - sizeof(exchange->signed_exchange_response.responseV2.withdrawal_address.address), - root, withdraw_coin->has_contract_address)) - { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); - return false; - } - } - } else { - // If the firmware doesn't support the output coin, it can't check the - // deposit address belongs to it. - if (exchange->withdrawal_address_n_count) { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); - return false; - } + } else { + // If the firmware doesn't support the output coin, it can't check the + // deposit address belongs to it. + if (exchange->withdrawal_address_n_count) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); + return false; } + } - /* verify Return coin type */ - const CoinType *return_coin = getReturnCoin(exchange); - if (!return_coin) { - set_exchange_error(ERROR_EXCHANGE_RETURN_COINTYPE); - return false; - } - - if (!verify_coins_match(deposit_coin, return_coin)) { - set_exchange_error(ERROR_EXCHANGE_RETURN_COINTYPE); - return false; - } + /* verify Return coin type */ + const CoinType *return_coin = getReturnCoin(exchange); + if (!return_coin) { + set_exchange_error(ERROR_EXCHANGE_RETURN_COINTYPE); + return false; + } - /* verify Return address */ - if (!verify_exchange_address( - return_coin, - exchange->return_address_n_count, - exchange->return_address_n, - exchange->has_return_script_type, - exchange->return_script_type, - exchange->signed_exchange_response.responseV2.return_address.address, - sizeof(exchange->signed_exchange_response.responseV2.return_address.address), - root, return_coin->has_contract_address)) - { - set_exchange_error(ERROR_EXCHANGE_RETURN_ADDRESS); - return false; - } + if (!verify_coins_match(deposit_coin, return_coin)) { + set_exchange_error(ERROR_EXCHANGE_RETURN_COINTYPE); + return false; + } + + /* verify Return address */ + if (!verify_exchange_address( + return_coin, exchange->return_address_n_count, + exchange->return_address_n, exchange->has_return_script_type, + exchange->return_script_type, + exchange->signed_exchange_response.responseV2.return_address.address, + sizeof(exchange->signed_exchange_response.responseV2.return_address + .address), + root, return_coin->has_contract_address)) { + set_exchange_error(ERROR_EXCHANGE_RETURN_ADDRESS); + return false; + } - set_exchange_error(NO_EXCHANGE_ERROR); - return true; + set_exchange_error(NO_EXCHANGE_ERROR); + return true; } /* @@ -501,10 +492,10 @@ static bool verify_exchange_contract(const CoinType *coin, void *vtx_out, const void set_exchange_errorDebug(ExchangeError error_code, const char *_msg) { #else void set_exchange_error(ExchangeError error_code) { - const char *_msg = NULL; + const char *_msg = NULL; #endif - exchange_error = error_code; - exchange_msg = _msg; + exchange_error = error_code; + exchange_msg = _msg; } /* * get_exchange_error - get exchange error code @@ -513,21 +504,15 @@ void set_exchange_error(ExchangeError error_code) { * OUTPUT * exchange error code */ -ExchangeError get_exchange_error(void) -{ - return(exchange_error); -} +ExchangeError get_exchange_error(void) { return (exchange_error); } #if DEBUG_LINK -const char *get_exchange_msg(void) -{ - return exchange_msg ? exchange_msg : ""; -} +const char *get_exchange_msg(void) { return exchange_msg ? exchange_msg : ""; } #endif /* - * process_exchange_contract() - validate contract from exchange and populate the transaction - * output structure + * process_exchange_contract() - validate contract from exchange and populate + * the transaction output structure * * INPUT * coin - pointer signTx coin type @@ -537,142 +522,137 @@ const char *get_exchange_msg(void) * OUTPUT * true/false - success/failure */ -bool process_exchange_contract(const CoinType *coin, void *vtx_out, const HDNode *root, bool needs_confirm) -{ - /* validate contract before processing */ - if (!verify_exchange_contract(coin, vtx_out, root)) - return false; - - /* check if user confirmation is required */ - if (!needs_confirm) - return true; - - CoinType standard_deposit; - const CoinType *deposit_coin = NULL; - const ExchangeType *tx_exchange; - if (isEthereumLike(coin->coin_name)) { - const EthereumSignTx *msg = (const EthereumSignTx *)vtx_out; - tx_exchange = &msg->exchange_type; - if (ethereum_isStandardERC20Transfer(msg)) { - if (!ethereum_getStandardERC20Coin(msg, &standard_deposit)) { - set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); - return false; - } - deposit_coin = &standard_deposit; - } else { - deposit_coin = coin; - } - } else if (strcmp("Cosmos", coin->coin_name) == 0) { - tx_exchange = &((CosmosMsgSend *)vtx_out)->exchange_type; - deposit_coin = coin; - } else if (strcmp("Binance", coin->coin_name) == 0) { - tx_exchange = &((BinanceTransferMsg *)vtx_out)->outputs[0].exchange_type; - deposit_coin = coin; - } else if (strcmp("Ripple", coin->coin_name) == 0) { - // TODO: Support Ripple exchanges. +bool process_exchange_contract(const CoinType *coin, void *vtx_out, + const HDNode *root, bool needs_confirm) { + /* validate contract before processing */ + if (!verify_exchange_contract(coin, vtx_out, root)) return false; + + /* check if user confirmation is required */ + if (!needs_confirm) return true; + + CoinType standard_deposit; + const CoinType *deposit_coin = NULL; + const ExchangeType *tx_exchange; + if (isEthereumLike(coin->coin_name)) { + const EthereumSignTx *msg = (const EthereumSignTx *)vtx_out; + tx_exchange = &msg->exchange_type; + if (ethereum_isStandardERC20Transfer(msg)) { + if (!ethereum_getStandardERC20Coin(msg, &standard_deposit)) { + set_exchange_error(ERROR_EXCHANGE_RESPONSE_STRUCTURE); return false; + } + deposit_coin = &standard_deposit; } else { - tx_exchange = &((TxOutputType *)vtx_out)->exchange_type; - deposit_coin = coin; - } - - if (!deposit_coin) { - set_exchange_error(ERROR_EXCHANGE_DEPOSIT_COINTYPE); - return false; - } + deposit_coin = coin; + } + } else if (strcmp("Cosmos", coin->coin_name) == 0) { + tx_exchange = &((CosmosMsgSend *)vtx_out)->exchange_type; + deposit_coin = coin; + } else if (strcmp("Binance", coin->coin_name) == 0) { + tx_exchange = &((BinanceTransferMsg *)vtx_out)->outputs[0].exchange_type; + deposit_coin = coin; + } else if (strcmp("Ripple", coin->coin_name) == 0) { + // TODO: Support Ripple exchanges. + return false; + } else { + tx_exchange = &((TxOutputType *)vtx_out)->exchange_type; + deposit_coin = coin; + } - /* assemble deposit amount for display*/ - char amount_dep_str[128]; - if (!exchange_tx_layout_str(deposit_coin, - tx_exchange->signed_exchange_response.responseV2.deposit_amount.bytes, - tx_exchange->signed_exchange_response.responseV2.deposit_amount.size, - amount_dep_str, - sizeof(amount_dep_str))) { - set_exchange_error(ERROR_EXCHANGE_DEPOSIT_AMOUNT); - return false; - } + if (!deposit_coin) { + set_exchange_error(ERROR_EXCHANGE_DEPOSIT_COINTYPE); + return false; + } + + /* assemble deposit amount for display*/ + char amount_dep_str[128]; + if (!exchange_tx_layout_str( + deposit_coin, + tx_exchange->signed_exchange_response.responseV2.deposit_amount.bytes, + tx_exchange->signed_exchange_response.responseV2.deposit_amount.size, + amount_dep_str, sizeof(amount_dep_str))) { + set_exchange_error(ERROR_EXCHANGE_DEPOSIT_AMOUNT); + return false; + } - const CoinType *withdraw_coin = getWithdrawCoin(tx_exchange); + const CoinType *withdraw_coin = getWithdrawCoin(tx_exchange); - const ExchangeAddress *withdraw = - &tx_exchange->signed_exchange_response.responseV2.withdrawal_address; + const ExchangeAddress *withdraw = + &tx_exchange->signed_exchange_response.responseV2.withdrawal_address; - char withdraw_symbol[sizeof(withdraw->coin_type)]; - strlcpy(withdraw_symbol, withdraw->coin_type, sizeof(withdraw_symbol)); - kk_strupr(withdraw_symbol); + char withdraw_symbol[sizeof(withdraw->coin_type)]; + strlcpy(withdraw_symbol, withdraw->coin_type, sizeof(withdraw_symbol)); + kk_strupr(withdraw_symbol); - /* assemble withdrawal amount for display*/ - char amount_wit_str[128]; - switch (tx_exchange->signed_exchange_response.responseV2.type) { + /* assemble withdrawal amount for display*/ + char amount_wit_str[128]; + switch (tx_exchange->signed_exchange_response.responseV2.type) { case OrderType_Precise: { - if (!withdraw_coin) { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_COINTYPE); - return false; - } - - if (!tx_exchange->signed_exchange_response.responseV2.has_withdrawal_amount || - !exchange_tx_layout_str(withdraw_coin, - tx_exchange->signed_exchange_response.responseV2.withdrawal_amount.bytes, - tx_exchange->signed_exchange_response.responseV2.withdrawal_amount.size, - amount_wit_str, - sizeof(amount_wit_str))) { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_AMOUNT); - return false; - } - break; + if (!withdraw_coin) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_COINTYPE); + return false; + } + + if (!tx_exchange->signed_exchange_response.responseV2 + .has_withdrawal_amount || + !exchange_tx_layout_str(withdraw_coin, + tx_exchange->signed_exchange_response + .responseV2.withdrawal_amount.bytes, + tx_exchange->signed_exchange_response + .responseV2.withdrawal_amount.size, + amount_wit_str, sizeof(amount_wit_str))) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_AMOUNT); + return false; + } + break; } case OrderType_Quick: { - strlcpy(amount_wit_str, - withdraw_symbol, - sizeof(amount_wit_str)); - strlcat(amount_wit_str, " at market rate", sizeof(amount_wit_str)); - break; + strlcpy(amount_wit_str, withdraw_symbol, sizeof(amount_wit_str)); + strlcat(amount_wit_str, " at market rate", sizeof(amount_wit_str)); + break; } default: { - set_exchange_error(ERROR_EXCHANGE_TYPE); - return false; - } - } - - if (!confirm_exchange_output(amount_dep_str, amount_wit_str)) { - set_exchange_error(ERROR_EXCHANGE_CANCEL); - return false; + set_exchange_error(ERROR_EXCHANGE_TYPE); + return false; } + } - // Determine withdrawal account / address - if (withdraw_coin && tx_exchange->withdrawal_address_n_count) { - char node_str[100]; - memzero(node_str, sizeof(node_str)); - - if (!bip32_node_to_string( - node_str, sizeof(node_str), withdraw_coin, - tx_exchange->withdrawal_address_n, - tx_exchange->withdrawal_address_n_count, - /*whole_account=*/false, - /*show_addridx=*/true)) { - set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); - return false; - } - - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Confirm", "ShapeShift will send the %s to:\n%s", - withdraw_symbol, node_str)) { - set_exchange_error(ERROR_EXCHANGE_CANCEL); - return false; - } - } else { - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Confirm External Address", - withdraw->has_dest_tag - ? "ShapeShift will send the %s to:\n%s tag:%s" - : "ShapeShift will send the %s to:\n%s", - withdraw_symbol, withdraw->address, - withdraw->dest_tag)) { - set_exchange_error(ERROR_EXCHANGE_CANCEL); - return false; - } - } - - return true; + if (!confirm_exchange_output(amount_dep_str, amount_wit_str)) { + set_exchange_error(ERROR_EXCHANGE_CANCEL); + return false; + } + + // Determine withdrawal account / address + if (withdraw_coin && tx_exchange->withdrawal_address_n_count) { + char node_str[100]; + memzero(node_str, sizeof(node_str)); + + if (!bip32_node_to_string(node_str, sizeof(node_str), withdraw_coin, + tx_exchange->withdrawal_address_n, + tx_exchange->withdrawal_address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true)) { + set_exchange_error(ERROR_EXCHANGE_WITHDRAWAL_ADDRESS); + return false; + } + + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Confirm", + "ShapeShift will send the %s to:\n%s", withdraw_symbol, + node_str)) { + set_exchange_error(ERROR_EXCHANGE_CANCEL); + return false; + } + } else { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Confirm External Address", + withdraw->has_dest_tag + ? "ShapeShift will send the %s to:\n%s tag:%s" + : "ShapeShift will send the %s to:\n%s", + withdraw_symbol, withdraw->address, withdraw->dest_tag)) { + set_exchange_error(ERROR_EXCHANGE_CANCEL); + return false; + } + } + + return true; } - diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index 6d84fc13f..c3014c571 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -55,6 +55,7 @@ #include "keepkey/firmware/storage.h" #include "keepkey/firmware/tendermint.h" #include "keepkey/firmware/transaction.h" +#include "keepkey/firmware/txin_check.h" #include "keepkey/firmware/u2f.h" #include "keepkey/rand/rng.h" #include "trezor/crypto/address.h" @@ -82,44 +83,40 @@ static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4))); -#define CHECK_INITIALIZED \ - if (!storage_isInitialized()) \ - { \ - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ - return; \ - } +#define CHECK_INITIALIZED \ + if (!storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_NotInitialized, \ + "Device not initialized"); \ + return; \ + } -#define CHECK_NOT_INITIALIZED \ - if (storage_isInitialized()) \ - { \ - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ - return; \ - } +#define CHECK_NOT_INITIALIZED \ + if (storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, \ + "Device is already initialized. Use Wipe first."); \ + return; \ + } #define CHECK_PIN \ - if (!pin_protect_cached()) \ - { \ - layoutHome(); \ - return; \ - } + if (!pin_protect_cached()) { \ + layoutHome(); \ + return; \ + } #define CHECK_PIN_UNCACHED \ - if (!pin_protect_uncached()) \ - { \ - layoutHome(); \ - return; \ - } - -#define CHECK_PARAM_RET(cond, errormsg, retval) \ - if (!(cond)) \ - { \ - fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ - layoutHome(); \ - return retval; \ - } - -#define CHECK_PARAM(cond, errormsg) \ - CHECK_PARAM_RET(cond, errormsg, ) + if (!pin_protect_uncached()) { \ + layoutHome(); \ + return; \ + } + +#define CHECK_PARAM_RET(cond, errormsg, retval) \ + if (!(cond)) { \ + fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ + layoutHome(); \ + return retval; \ + } + +#define CHECK_PARAM(cond, errormsg) CHECK_PARAM_RET(cond, errormsg, ) static const MessagesMap_t MessagesMap[] = { #include "messagemap.def" @@ -127,18 +124,18 @@ static const MessagesMap_t MessagesMap[] = { #undef MSG_IN #define MSG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef MSG_OUT #define MSG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) #undef RAW_IN #define RAW_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_IN #define DEBUG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_OUT #define DEBUG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) @@ -147,150 +144,136 @@ static const MessagesMap_t MessagesMap[] = { extern bool reset_msg_stack; -static const CoinType *fsm_getCoin(bool has_name, const char *name) -{ - const CoinType *coin; - if (has_name) - { - coin = coinByName(name); - } - else - { - coin = coinByName("Bitcoin"); - } - if (!coin) - { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return 0; - } - - return coin; +static const CoinType *fsm_getCoin(bool has_name, const char *name) { + const CoinType *coin; + if (has_name) { + coin = coinByName(name); + } else { + coin = coinByName("Bitcoin"); + } + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return 0; + } + + return coin; } -static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) -{ - static HDNode CONFIDENTIAL node; - if (fingerprint) - { - *fingerprint = 0; - } - - if (!get_curve_by_name(curve)) - { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Unknown ecdsa curve"); - layoutHome(); - return 0; - } - - if (!storage_getRootNode(curve, true, &node)) - { - fsm_sendFailure(FailureType_Failure_NotInitialized, - "Device not initialized or passphrase request cancelled"); - layoutHome(); - return 0; - } - - if (!address_n || address_n_count == 0) - { - return &node; - } - - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) - { - fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); - layoutHome(); - return 0; - } - +static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, + size_t address_n_count, + uint32_t *fingerprint) { + static HDNode CONFIDENTIAL node; + if (fingerprint) { + *fingerprint = 0; + } + + if (!get_curve_by_name(curve)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Unknown ecdsa curve"); + layoutHome(); + return 0; + } + + if (!storage_getRootNode(curve, true, &node)) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + "Device not initialized or passphrase request cancelled"); + layoutHome(); + return 0; + } + + if (!address_n || address_n_count == 0) { return &node; + } + + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, + fingerprint) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + layoutHome(); + return 0; + } + + return &node; } #if DEBUG_LINK -static void sendFailureWrapper(FailureType code, const char *text) -{ - fsm_sendFailure(code, text); +static void sendFailureWrapper(FailureType code, const char *text) { + fsm_sendFailure(code, text); } #endif -void fsm_init(void) -{ - msg_map_init(MessagesMap, sizeof(MessagesMap) / sizeof(MessagesMap_t)); +void fsm_init(void) { + msg_map_init(MessagesMap, sizeof(MessagesMap) / sizeof(MessagesMap_t)); #if DEBUG_LINK - set_msg_failure_handler(&sendFailureWrapper); + set_msg_failure_handler(&sendFailureWrapper); #else - set_msg_failure_handler(&fsm_sendFailure); + set_msg_failure_handler(&fsm_sendFailure); #endif - /* set leaving handler for layout to help with determine home state */ - set_leaving_handler(&leave_home); + /* set leaving handler for layout to help with determine home state */ + set_leaving_handler(&leave_home); #if DEBUG_LINK - set_msg_debug_link_get_state_handler(&fsm_msgDebugLinkGetState); + set_msg_debug_link_get_state_handler(&fsm_msgDebugLinkGetState); #endif - msg_init(); + msg_init(); + + txin_dgst_initialize(); } -void fsm_sendSuccess(const char *text) -{ - if (reset_msg_stack) - { - fsm_msgInitialize((Initialize *)0); - reset_msg_stack = false; - return; - } - - RESP_INIT(Success); - - if (text) - { - resp->has_message = true; - strlcpy(resp->message, text, sizeof(resp->message)); - } - - msg_write(MessageType_MessageType_Success, resp); +void fsm_sendSuccess(const char *text) { + if (reset_msg_stack) { + fsm_msgInitialize((Initialize *)0); + reset_msg_stack = false; + return; + } + + RESP_INIT(Success); + + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } + + msg_write(MessageType_MessageType_Success, resp); } #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) +void fsm_sendFailureDebug(FailureType code, const char *text, + const char *source) #else void fsm_sendFailure(FailureType code, const char *text) #endif { - if (reset_msg_stack) - { - fsm_msgInitialize((Initialize *)0); - reset_msg_stack = false; - return; - } + if (reset_msg_stack) { + fsm_msgInitialize((Initialize *)0); + reset_msg_stack = false; + return; + } - RESP_INIT(Failure); - resp->has_code = true; - resp->code = code; + RESP_INIT(Failure); + resp->has_code = true; + resp->code = code; #if DEBUG_LINK - resp->has_message = true; - strlcpy(resp->message, source, sizeof(resp->message)); - if (text) - { - strlcat(resp->message, text, sizeof(resp->message)); - } + resp->has_message = true; + strlcpy(resp->message, source, sizeof(resp->message)); + if (text) { + strlcat(resp->message, text, sizeof(resp->message)); + } #else - if (text) - { - resp->has_message = true; - strlcpy(resp->message, text, sizeof(resp->message)); - } + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } #endif - msg_write(MessageType_MessageType_Failure, resp); + msg_write(MessageType_MessageType_Failure, resp); } -void fsm_msgClearSession(ClearSession *msg) -{ - (void)msg; - session_clear(/*clear_pin=*/true); - fsm_sendSuccess("Session cleared"); +void fsm_msgClearSession(ClearSession *msg) { + (void)msg; + session_clear(/*clear_pin=*/true); + fsm_sendSuccess("Session cleared"); } #include "fsm_msg_common.h" diff --git a/lib/firmware/fsm_msg_binance.h b/lib/firmware/fsm_msg_binance.h index cb53a06b0..4f6134f17 100644 --- a/lib/firmware/fsm_msg_binance.h +++ b/lib/firmware/fsm_msg_binance.h @@ -1,207 +1,222 @@ -void fsm_msgBinanceGetAddress(const BinanceGetAddress *msg) -{ - RESP_INIT(BinanceAddress); +void fsm_msgBinanceGetAddress(const BinanceGetAddress *msg) { + RESP_INIT(BinanceAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const char *coin_name = "Binance"; - const CoinType *coin = fsm_getCoin(true, coin_name); - if (!coin) { return; } - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } + const char *coin_name = "Binance"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) { + return; + } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) { + return; + } - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - if (!tendermint_getAddress(node, "bnb", resp->address)) { - fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't encode address")); + if (!tendermint_getAddress(node, "bnb", resp->address)) { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Can't create Bip32 Path String")); + layoutHome(); + } + + bool mismatch = + tendermint_pathMismatched(coin, msg->address_n, msg->address_n_count); + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", + "Wrong address path for selected coin. Continue at your own " + "risk!")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; + } } - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/false, - /*show_addridx=*/false) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't create Bip32 Path String")); - layoutHome(); - } - - bool mismatch = tendermint_pathMismatched(coin, msg->address_n, msg->address_n_count); - if (mismatch) { - if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", - "Wrong address path for selected coin. Continue at your own risk!")) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if(!confirm_ethereum_address(node_str, resp->address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); - layoutHome(); - return; - } + if (!confirm_ethereum_address(node_str, resp->address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show address cancelled"); + layoutHome(); + return; } + } - resp->has_address = true; + resp->has_address = true; - layoutHome(); - msg_write(MessageType_MessageType_BinanceAddress, resp); + layoutHome(); + msg_write(MessageType_MessageType_BinanceAddress, resp); } -void fsm_msgBinanceSignTx(const BinanceSignTx *msg) -{ - CHECK_INITIALIZED - CHECK_PIN - - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } +void fsm_msgBinanceSignTx(const BinanceSignTx *msg) { + CHECK_INITIALIZED + CHECK_PIN - hdnode_fill_public_key(node); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) { + return; + } - RESP_INIT(BinanceTxRequest); + hdnode_fill_public_key(node); - if (!binance_signTxInit(node, msg)) - { - binance_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, - _("Failed to initialize transaction signing")); - layoutHome(); - return; - } + RESP_INIT(BinanceTxRequest); + if (!binance_signTxInit(node, msg)) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to initialize transaction signing")); layoutHome(); - msg_write(MessageType_MessageType_BinanceTxRequest, resp); + return; + } + + layoutHome(); + msg_write(MessageType_MessageType_BinanceTxRequest, resp); } static void binance_response(void); void fsm_msgBinanceTransferMsg(const BinanceTransferMsg *msg) { - CHECK_PARAM(binance_signingIsInited(), "Signing not in progress?"); - CHECK_PARAM(msg->inputs_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->inputs[0].coins_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->outputs_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->outputs[0].coins_count == 1, "Malformed BinanceTransferMsg") - CHECK_PARAM(msg->inputs[0].coins[0].amount == - msg->outputs[0].coins[0].amount, "Malformed BinanceTransferMsg") - CHECK_PARAM(strcmp(msg->inputs[0].coins[0].denom, "BNB") == 0, - "Other BNB tokens not yet supported") - CHECK_PARAM(strcmp(msg->inputs[0].coins[0].denom, - msg->outputs[0].coins[0].denom) == 0, - "Malformed BinanceTransferMsg") - - const CoinType *coin = fsm_getCoin(true, "Binance"); - if (!coin) { return; } - - switch (msg->outputs[0].address_type) { + CHECK_PARAM(binance_signingIsInited(), "Signing not in progress?"); + CHECK_PARAM(msg->inputs_count == 1, "Malformed BinanceTransferMsg") + CHECK_PARAM(msg->inputs[0].coins_count == 1, "Malformed BinanceTransferMsg") + CHECK_PARAM(msg->outputs_count == 1, "Malformed BinanceTransferMsg") + CHECK_PARAM(msg->outputs[0].coins_count == 1, "Malformed BinanceTransferMsg") + CHECK_PARAM(msg->inputs[0].coins[0].amount == msg->outputs[0].coins[0].amount, + "Malformed BinanceTransferMsg") + CHECK_PARAM(strcmp(msg->inputs[0].coins[0].denom, "BNB") == 0, + "Other BNB tokens not yet supported") + CHECK_PARAM(strcmp(msg->inputs[0].coins[0].denom, + msg->outputs[0].coins[0].denom) == 0, + "Malformed BinanceTransferMsg") + + const CoinType *coin = fsm_getCoin(true, "Binance"); + if (!coin) { + return; + } + + switch (msg->outputs[0].address_type) { case OutputAddressType_EXCHANGE: { - HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); - if (!root_node) { - binance_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); - layoutHome(); - return; - } - - int ret = run_policy_compile_output(coin, root_node, (void *)&msg, (void *)NULL, true); - if (ret < TXOUT_OK) { - memzero((void *)root_node, sizeof(*root_node)); - binance_signAbort(); - send_fsm_co_error_message(ret); - layoutHome(); - return; - } - - break; - } - case OutputAddressType_TRANSFER: - default: { - char amount_str[32]; - bn_format_uint64(msg->outputs[0].coins[0].amount, NULL, " BNB", 8, 0, false, amount_str, sizeof(amount_str)); - if (!confirm_transaction_output( - ButtonRequestType_ButtonRequest_ConfirmOutput, - amount_str, msg->outputs[0].address)) { - binance_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - break; - } - } - - if (!binance_signTxUpdateTransfer(msg)) { + HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); + if (!root_node) { binance_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to include transfer message in transaction"); + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); layoutHome(); return; - } - - binance_response(); -} - -static void binance_response(void) -{ - if (!binance_signingIsFinished()) { - RESP_INIT(BinanceTxRequest); - msg_write(MessageType_MessageType_BinanceTxRequest, resp); - return; - } - - const CoinType *coin = fsm_getCoin(true, "Binance"); - if (!coin) { return; } + } - const BinanceSignTx *sign_tx = binance_getBinanceSignTx(); - - if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, - _("Memo"), "%s", sign_tx->memo)) - { + int ret = run_policy_compile_output(coin, root_node, (void *)&msg, + (void *)NULL, true); + if (ret < TXOUT_OK) { + memzero((void *)root_node, sizeof(*root_node)); binance_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + send_fsm_co_error_message(ret); layoutHome(); return; - } + } - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, sign_tx->address_n, - sign_tx->address_n_count, /*whole_account=*/false, - /*show_addridx=*/false) && - !bip32_path_to_string(node_str, sizeof(node_str), - sign_tx->address_n, sign_tx->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); + break; } - - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, - "Sign this Binance transaction on %s?", - sign_tx->chain_id)) - { + case OutputAddressType_TRANSFER: + default: { + char amount_str[32]; + bn_format_uint64(msg->outputs[0].coins[0].amount, NULL, " BNB", 8, 0, + false, amount_str, sizeof(amount_str)); + if (!confirm_transaction_output( + ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, + msg->outputs[0].address)) { binance_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; + } + break; } + } - RESP_INIT(BinanceSignedTx); + if (!binance_signTxUpdateTransfer(msg)) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include transfer message in transaction"); + layoutHome(); + return; + } - if (!binance_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { - binance_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to finalize signature"); - layoutHome(); - return; - } + binance_response(); +} + +static void binance_response(void) { + if (!binance_signingIsFinished()) { + RESP_INIT(BinanceTxRequest); + msg_write(MessageType_MessageType_BinanceTxRequest, resp); + return; + } + + const CoinType *coin = fsm_getCoin(true, "Binance"); + if (!coin) { + return; + } + + const BinanceSignTx *sign_tx = binance_getBinanceSignTx(); + + if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, + _("Memo"), "%s", sign_tx->memo)) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, + sign_tx->address_n, sign_tx->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), sign_tx->address_n, + sign_tx->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, + "Sign this Binance transaction on %s?", sign_tx->chain_id)) { + binance_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + RESP_INIT(BinanceSignedTx); - resp->public_key.size = 33; - resp->has_public_key = true; - resp->signature.size = 64; - resp->has_signature = true; + if (!binance_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { binance_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to finalize signature"); layoutHome(); - msg_write(MessageType_MessageType_BinanceSignedTx, resp); + return; + } + + resp->public_key.size = 33; + resp->has_public_key = true; + resp->signature.size = 64; + resp->has_signature = true; + binance_signAbort(); + layoutHome(); + msg_write(MessageType_MessageType_BinanceSignedTx, resp); } diff --git a/lib/firmware/fsm_msg_coin.h b/lib/firmware/fsm_msg_coin.h index aa9f3f78d..e9d4a21e4 100644 --- a/lib/firmware/fsm_msg_coin.h +++ b/lib/firmware/fsm_msg_coin.h @@ -1,325 +1,341 @@ -void fsm_msgGetPublicKey(GetPublicKey *msg) -{ - RESP_INIT(PublicKey); - - CHECK_INITIALIZED - - CHECK_PIN - - InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; - - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - - const char *curve = coin->curve_name; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - uint32_t fingerprint; - HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); - if (!node) return; - hdnode_fill_public_key(node); - - resp->node.depth = node->depth; - resp->node.fingerprint = fingerprint; - resp->node.child_num = node->child_num; - resp->node.chain_code.size = 32; - memcpy(resp->node.chain_code.bytes, node->chain_code, 32); - resp->node.has_private_key = false; - resp->node.has_public_key = true; - resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->node.public_key.bytes[0] = 0; - } - resp->has_xpub = true; - - if (coin->xpub_magic && script_type == InputScriptType_SPENDADDRESS) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); - } else - if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, resp->xpub, sizeof(resp->xpub)); - } else - if (coin->has_segwit && coin->xpub_magic_segwit_native && script_type == InputScriptType_SPENDWITNESS) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, resp->xpub, sizeof(resp->xpub)); - } else { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Invalid combination of coin and script_type")); - layoutHome(); - return; - } - - if (msg->has_show_display && msg->show_display) - { - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, - msg->address_n, - msg->address_n_count, - /*whole_account=*/true, - /*show_addridx=*/false) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - - if (!confirm_xpub(node_str, resp->xpub)) - { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show extended public key cancelled"); - layoutHome(); - return; - } - } - - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_PublicKey, resp); - layoutHome(); +void fsm_msgGetPublicKey(GetPublicKey *msg) { + RESP_INIT(PublicKey); + + CHECK_INITIALIZED + + CHECK_PIN + + InputScriptType script_type = + msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; + + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + + const char *curve = coin->curve_name; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + uint32_t fingerprint; + HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, + &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); + + resp->node.depth = node->depth; + resp->node.fingerprint = fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } + resp->has_xpub = true; + + if (coin->xpub_magic && script_type == InputScriptType_SPENDADDRESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, + sizeof(resp->xpub)); + } else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && + script_type == InputScriptType_SPENDP2SHWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, + resp->xpub, sizeof(resp->xpub)); + } else if (coin->has_segwit && coin->xpub_magic_segwit_native && + script_type == InputScriptType_SPENDWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, + resp->xpub, sizeof(resp->xpub)); + } else { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, + _("Invalid combination of coin and script_type")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, + /*whole_account=*/true, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + if (!confirm_xpub(node_str, resp->xpub)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show extended public key cancelled"); + layoutHome(); + return; + } + } + + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_PublicKey, resp); + layoutHome(); } -void fsm_msgSignTx(SignTx *msg) -{ - CHECK_INITIALIZED +void fsm_msgSignTx(SignTx *msg) { + CHECK_INITIALIZED - CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); - CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); - CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); + CHECK_PARAM(msg->inputs_count > 0, + _("Transaction must have at least one input")); + CHECK_PARAM(msg->outputs_count > 0, + _("Transaction must have at least one output")); + CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, + _("Value overflow")); - CHECK_PIN + CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if(!coin) { return; } - const HDNode *node = fsm_getDerivedNode(coin->curve_name, 0, 0, NULL); - if(!node) { return; } + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) { + return; + } + const HDNode *node = fsm_getDerivedNode(coin->curve_name, 0, 0, NULL); + if (!node) { + return; + } - layout_simple_message("Preparing Transaction..."); + layout_simple_message("Preparing Transaction..."); - signing_init(msg, coin, node); + signing_init(msg, coin, node); } -void fsm_msgTxAck(TxAck *msg) -{ - CHECK_PARAM(msg->has_tx, _("No transaction provided")); +void fsm_msgTxAck(TxAck *msg) { + CHECK_PARAM(msg->has_tx, _("No transaction provided")); - signing_txack(&(msg->tx)); + signing_txack(&(msg->tx)); } // NOTE: there is a very similar copy of this function in coins.c // PLEASE keep both copies in sync. -static bool path_mismatched(const CoinType *coin, const GetAddress *msg) -{ - bool mismatch = false; - - // m : no path - if (msg->address_n_count == 0) { - return false; - } - - // m/44' : BIP44 Legacy - // m / purpose' / bip44_account_path' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 44)) { - mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->bip44_account_path); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/45' - BIP45 Copay Abandoned Multisig P2SH - // m / purpose' / cosigner_index / change / address_index - if (msg->address_n[0] == (0x80000000 + 45)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count != 4); - mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/48' - BIP48 Copay Multisig P2SH - // m / purpose' / bip44_account_path' / account' / change / address_index - // Electrum: - // m / purpose' / coin_type' / account' / type' / change / address_index - if (msg->address_n[0] == (0x80000000 + 48)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG) && - (msg->script_type != InputScriptType_SPENDP2SHWITNESS) && - (msg->script_type != InputScriptType_SPENDWITNESS); - mismatch |= (msg->address_n_count != 5) && (msg->address_n_count != 6); - mismatch |= (msg->address_n[1] != coin->bip44_account_path); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/49' : BIP49 SegWit - // m / purpose' / bip44_account_path' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 49)) { - mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); - mismatch |= !coin->has_segwit || !coin->segwit; - mismatch |= !coin->has_address_type_p2sh; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->bip44_account_path); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/84' : BIP84 Native SegWit - // m / purpose' / bip44_account_path' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 84)) { - mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); - mismatch |= !coin->has_segwit || !coin->segwit; - mismatch |= !coin->has_bech32_prefix; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->bip44_account_path); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - return false; +static bool path_mismatched(const CoinType *coin, const GetAddress *msg) { + bool mismatch = false; + + // m : no path + if (msg->address_n_count == 0) { + return false; + } + + // m/44' : BIP44 Legacy + // m / purpose' / bip44_account_path' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 44)) { + mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->bip44_account_path); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/45' - BIP45 Copay Abandoned Multisig P2SH + // m / purpose' / cosigner_index / change / address_index + if (msg->address_n[0] == (0x80000000 + 45)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count != 4); + mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/48' - BIP48 Copay Multisig P2SH + // m / purpose' / bip44_account_path' / account' / change / address_index + // Electrum: + // m / purpose' / coin_type' / account' / type' / change / address_index + if (msg->address_n[0] == (0x80000000 + 48)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG) && + (msg->script_type != InputScriptType_SPENDP2SHWITNESS) && + (msg->script_type != InputScriptType_SPENDWITNESS); + mismatch |= (msg->address_n_count != 5) && (msg->address_n_count != 6); + mismatch |= (msg->address_n[1] != coin->bip44_account_path); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/49' : BIP49 SegWit + // m / purpose' / bip44_account_path' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 49)) { + mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); + mismatch |= !coin->has_segwit || !coin->segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->bip44_account_path); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/84' : BIP84 Native SegWit + // m / purpose' / bip44_account_path' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 84)) { + mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); + mismatch |= !coin->has_segwit || !coin->segwit; + mismatch |= !coin->has_bech32_prefix; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->bip44_account_path); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + return false; } -void fsm_msgGetAddress(GetAddress *msg) -{ - RESP_INIT(Address); - - CHECK_INITIALIZED - - CHECK_PIN - - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); - - char address[MAX_ADDR_SIZE]; - if (msg->has_multisig) { // use progress bar only for multisig - animating_progress_handler(_("Computing address"), 0); - } - if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); - layoutHome(); - return; - } - - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (msg->has_multisig) { - snprintf(node_str, sizeof(node_str), "Multisig (%" PRIu32 " of %" PRIu32 ")", - msg->multisig.m, (uint32_t)msg->multisig.pubkeys_count); - } else { - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/false, - /*show_addridx=*/true) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - } - - bool mismatch = path_mismatched(coin, msg); - - if (mismatch) { - if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", "Wrong address path for selected coin. Continue at your own risk!")) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - size_t prefix_len = coin->has_cashaddr_prefix - ? strlen(coin->cashaddr_prefix) + 1 - : 0; - - if(!confirm_address(node_str, address + prefix_len)) - { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); - layoutHome(); - return; - } - } - - memzero(node, sizeof(*node)); - strlcpy(resp->address, address, sizeof(resp->address)); - msg_write(MessageType_MessageType_Address, resp); - layoutHome(); +void fsm_msgGetAddress(GetAddress *msg) { + RESP_INIT(Address); + + CHECK_INITIALIZED + + CHECK_PIN + + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + char address[MAX_ADDR_SIZE]; + if (msg->has_multisig) { // use progress bar only for multisig + animating_progress_handler(_("Computing address"), 0); + } + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, + &msg->multisig, address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (msg->has_multisig) { + snprintf(node_str, sizeof(node_str), + "Multisig (%" PRIu32 " of %" PRIu32 ")", msg->multisig.m, + (uint32_t)msg->multisig.pubkeys_count); + } else { + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, + msg->address_n, msg->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + } + + bool mismatch = path_mismatched(coin, msg); + + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", + "Wrong address path for selected coin. Continue at your own " + "risk!")) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + size_t prefix_len = + coin->has_cashaddr_prefix ? strlen(coin->cashaddr_prefix) + 1 : 0; + + if (!confirm_address(node_str, address + prefix_len)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show address cancelled"); + layoutHome(); + return; + } + } + + memzero(node, sizeof(*node)); + strlcpy(resp->address, address, sizeof(resp->address)); + msg_write(MessageType_MessageType_Address, resp); + layoutHome(); } -void fsm_msgSignMessage(SignMessage *msg) -{ - RESP_INIT(MessageSignature); - - CHECK_INITIALIZED - - if (!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message", "%s", - (char *)msg->message.bytes)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); - layoutHome(); - return; - } - - CHECK_PIN - - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - animating_progress_handler(_("Signing"), 0); - if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { - resp->has_address = true; - hdnode_fill_public_key(node); - if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Error computing address")); - layoutHome(); - return; - } - resp->has_signature = true; - resp->signature.size = 65; - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_MessageSignature, resp); - } else { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Error signing message")); - } - layoutHome(); +void fsm_msgSignMessage(SignMessage *msg) { + RESP_INIT(MessageSignature); + + CHECK_INITIALIZED + + if (!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message", + "%s", (char *)msg->message.bytes)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Sign message cancelled"); + layoutHome(); + return; + } + + CHECK_PIN + + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + + animating_progress_handler(_("Signing"), 0); + if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, + msg->message.size, resp->signature.bytes) == 0) { + resp->has_address = true; + hdnode_fill_public_key(node); + if (!compute_address(coin, msg->script_type, node, false, NULL, + resp->address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Error computing address")); + layoutHome(); + return; + } + resp->has_signature = true; + resp->signature.size = 65; + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_MessageSignature, resp); + } else { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Error signing message")); + } + layoutHome(); } -void fsm_msgVerifyMessage(VerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - layout_simple_message("Verifying Message..."); - - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { - if (!confirm_address("Confirm Signer", msg->address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - if (!review(ButtonRequestType_ButtonRequest_Other, "Message Verified", "%s", - (char *)msg->message.bytes)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Action cancelled by user")); - layoutHome(); - return; - } - fsm_sendSuccess("Message verified"); - } else { - fsm_sendFailure(FailureType_Failure_InvalidSignature, _("Invalid signature")); - } - layoutHome(); +void fsm_msgVerifyMessage(VerifyMessage *msg) { + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + layout_simple_message("Verifying Message..."); + + if (msg->signature.size == 65 && + cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, + msg->address, msg->signature.bytes) == 0) { + if (!confirm_address("Confirm Signer", msg->address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + if (!review(ButtonRequestType_ButtonRequest_Other, "Message Verified", "%s", + (char *)msg->message.bytes)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Action cancelled by user")); + layoutHome(); + return; + } + fsm_sendSuccess("Message verified"); + } else { + fsm_sendFailure(FailureType_Failure_InvalidSignature, + _("Invalid signature")); + } + layoutHome(); } diff --git a/lib/firmware/fsm_msg_common.h b/lib/firmware/fsm_msg_common.h index 3e93cfc21..9e139f989 100644 --- a/lib/firmware/fsm_msg_common.h +++ b/lib/firmware/fsm_msg_common.h @@ -1,571 +1,615 @@ -void fsm_msgInitialize(Initialize *msg) -{ - (void)msg; - recovery_cipher_abort(); - signing_abort(); - ethereum_signing_abort(); - cosmos_signAbort(); - eos_signingAbort(); - session_clear(false); // do not clear PIN - layoutHome(); - fsm_msgGetFeatures(0); +void fsm_msgInitialize(Initialize *msg) { + (void)msg; + recovery_cipher_abort(); + signing_abort(); + ethereum_signing_abort(); + cosmos_signAbort(); + eos_signingAbort(); + session_clear(false); // do not clear PIN + layoutHome(); + fsm_msgGetFeatures(0); } static const char *model(void) { - const char *ret = flash_getModel(); - if (ret) - return ret; - return "Unknown"; + const char *ret = flash_getModel(); + if (ret) return ret; + return "Unknown"; } -void fsm_msgGetFeatures(GetFeatures *msg) -{ - (void)msg; - RESP_INIT(Features); - - /* Vendor */ - resp->has_vendor = true; - strlcpy(resp->vendor, "keepkey.com", sizeof(resp->vendor)); - - /* Version */ - resp->has_major_version = true; resp->major_version = MAJOR_VERSION; - resp->has_minor_version = true; resp->minor_version = MINOR_VERSION; - resp->has_patch_version = true; resp->patch_version = PATCH_VERSION; - - /* Device ID */ - resp->has_device_id = true; - strlcpy(resp->device_id, storage_getUuidStr(), sizeof(resp->device_id)); - - /* Model */ - resp->has_model = true; - strlcpy(resp->model, model(), sizeof(resp->model)); - - /* Variant Name */ - resp->has_firmware_variant = true; - strlcpy(resp->firmware_variant, variant_getName(), sizeof(resp->firmware_variant)); - - /* Security settings */ - resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); - resp->has_passphrase_protection = true; - resp->passphrase_protection = storage_getPassphraseProtected(); +void fsm_msgGetFeatures(GetFeatures *msg) { + (void)msg; + RESP_INIT(Features); + + /* Vendor */ + resp->has_vendor = true; + strlcpy(resp->vendor, "keepkey.com", sizeof(resp->vendor)); + + /* Version */ + resp->has_major_version = true; + resp->major_version = MAJOR_VERSION; + resp->has_minor_version = true; + resp->minor_version = MINOR_VERSION; + resp->has_patch_version = true; + resp->patch_version = PATCH_VERSION; + + /* Device ID */ + resp->has_device_id = true; + strlcpy(resp->device_id, storage_getUuidStr(), sizeof(resp->device_id)); + + /* Model */ + resp->has_model = true; + strlcpy(resp->model, model(), sizeof(resp->model)); + + /* Variant Name */ + resp->has_firmware_variant = true; + strlcpy(resp->firmware_variant, variant_getName(), + sizeof(resp->firmware_variant)); + + /* Security settings */ + resp->has_pin_protection = true; + resp->pin_protection = storage_hasPin(); + resp->has_passphrase_protection = true; + resp->passphrase_protection = storage_getPassphraseProtected(); + resp->has_wipe_code_protection = storage_hasWipeCode(); #ifdef SCM_REVISION - int len = sizeof(SCM_REVISION) - 1; - resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); - resp->revision.size = len; + int len = sizeof(SCM_REVISION) - 1; + resp->has_revision = true; + memcpy(resp->revision.bytes, SCM_REVISION, len); + resp->revision.size = len; #endif - /* Bootloader hash */ + /* Bootloader hash */ #ifndef EMULATOR - resp->has_bootloader_hash = true; - resp->bootloader_hash.size = memory_bootloader_hash( - resp->bootloader_hash.bytes, false); + resp->has_bootloader_hash = true; + resp->bootloader_hash.size = + memory_bootloader_hash(resp->bootloader_hash.bytes, false); #else - resp->has_bootloader_hash = false; + resp->has_bootloader_hash = false; #endif - /* Firmware hash */ + /* Firmware hash */ #ifndef EMULATOR - resp->has_firmware_hash = true; - resp->firmware_hash.size = memory_firmware_hash(resp->firmware_hash.bytes); + resp->has_firmware_hash = true; + resp->firmware_hash.size = memory_firmware_hash(resp->firmware_hash.bytes); #else - resp->has_firmware_hash = false; + resp->has_firmware_hash = false; #endif - /* Settings for device */ - if(storage_getLanguage()) - { - resp->has_language = true; - strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); - } - - if(storage_getLabel()) - { - resp->has_label = true; - strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); - } - - /* Is device initialized? */ - resp->has_initialized = true; - resp->initialized = storage_isInitialized(); - - /* Are private keys imported */ - resp->has_imported = true; resp->imported = storage_getImported(); - - /* Are private keys known to no-one? */ - resp->has_no_backup = true; resp->no_backup = storage_noBackup(); + /* Settings for device */ + if (storage_getLanguage()) { + resp->has_language = true; + strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); + } + + if (storage_getLabel()) { + resp->has_label = true; + strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); + } + + /* Is device initialized? */ + resp->has_initialized = true; + resp->initialized = storage_isInitialized(); + + /* Are private keys imported */ + resp->has_imported = true; + resp->imported = storage_getImported(); + + /* Are private keys known to no-one? */ + resp->has_no_backup = true; + resp->no_backup = storage_noBackup(); + + /* Cached pin and passphrase status */ + resp->has_pin_cached = true; + resp->pin_cached = session_isPinCached(); + resp->has_passphrase_cached = true; + resp->passphrase_cached = session_isPassphraseCached(); + + /* Policies */ + resp->policies_count = POLICY_COUNT; + storage_getPolicies(resp->policies); + _Static_assert( + sizeof(resp->policies) / sizeof(resp->policies[0]) == POLICY_COUNT, + "update messages.options to match POLICY_COUNT"); + + msg_write(MessageType_MessageType_Features, resp); +} - /* Cached pin and passphrase status */ - resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); - resp->has_passphrase_cached = true; - resp->passphrase_cached = session_isPassphraseCached(); +void fsm_msgGetCoinTable(GetCoinTable *msg) { + RESP_INIT(CoinTable); - /* Policies */ - resp->policies_count = POLICY_COUNT; - storage_getPolicies(resp->policies); - _Static_assert(sizeof(resp->policies) / sizeof(resp->policies[0]) == POLICY_COUNT, - "update messages.options to match POLICY_COUNT"); + CHECK_PARAM(msg->has_start == msg->has_end, + "Incorrect GetCoinTable parameters"); - msg_write(MessageType_MessageType_Features, resp); -} + resp->has_chunk_size = true; + resp->chunk_size = sizeof(resp->table) / sizeof(resp->table[0]); -void fsm_msgGetCoinTable(GetCoinTable *msg) -{ - RESP_INIT(CoinTable); - - CHECK_PARAM(msg->has_start == msg->has_end, "Incorrect GetCoinTable parameters"); - - resp->has_chunk_size = true; - resp->chunk_size = sizeof(resp->table) / sizeof(resp->table[0]); - - if (msg->has_start && msg->has_end) { - if (COINS_COUNT + TOKENS_COUNT <= msg->start || - COINS_COUNT + TOKENS_COUNT < msg->end || - msg->end < msg->start || - resp->chunk_size < msg->end - msg->start) { - fsm_sendFailure(FailureType_Failure_Other, - "Incorrect GetCoinTable parameters"); - layoutHome(); - return; - } + if (msg->has_start && msg->has_end) { + if (COINS_COUNT + TOKENS_COUNT <= msg->start || + COINS_COUNT + TOKENS_COUNT < msg->end || msg->end < msg->start || + resp->chunk_size < msg->end - msg->start) { + fsm_sendFailure(FailureType_Failure_Other, + "Incorrect GetCoinTable parameters"); + layoutHome(); + return; } + } - resp->has_num_coins = true; - resp->num_coins = COINS_COUNT + TOKENS_COUNT; + resp->has_num_coins = true; + resp->num_coins = COINS_COUNT + TOKENS_COUNT; - if (msg->has_start && msg->has_end) { - resp->table_count = msg->end - msg->start; + if (msg->has_start && msg->has_end) { + resp->table_count = msg->end - msg->start; - for (size_t i = 0; i < msg->end - msg->start; i++) { - if (msg->start + i < COINS_COUNT) { - resp->table[i] = coins[msg->start + i]; - } else if (msg->start + i - COINS_COUNT < TOKENS_COUNT) { - coinFromToken(&resp->table[i], &tokens[msg->start + i - COINS_COUNT]); - } - } + for (size_t i = 0; i < msg->end - msg->start; i++) { + if (msg->start + i < COINS_COUNT) { + resp->table[i] = coins[msg->start + i]; + } else if (msg->start + i - COINS_COUNT < TOKENS_COUNT) { + coinFromToken(&resp->table[i], &tokens[msg->start + i - COINS_COUNT]); + } } + } - msg_write(MessageType_MessageType_CoinTable, resp); + msg_write(MessageType_MessageType_CoinTable, resp); } static bool isValidModelNumber(const char *model) { #define MODEL_ENTRY(STRING, ENUM) \ - if (!strcmp(model, STRING)) \ - return true; + if (!strcmp(model, STRING)) return true; #include "keepkey/board/models.def" - return false; + return false; } -void fsm_msgPing(Ping *msg) -{ - RESP_INIT(Success); - - // If device is in manufacture mode, turn if off, lock it, and program the - // model number into OTP flash. - if (is_mfg_mode() && msg->has_message && isValidModelNumber(msg->message)) { - set_mfg_mode_off(); - char message[32]; - strncpy(message, msg->message, sizeof(message)); - message[31] = 0; - flash_setModel(&message); - } +void fsm_msgPing(Ping *msg) { + RESP_INIT(Success); + + // If device is in manufacture mode, turn if off, lock it, and program the + // model number into OTP flash. + if (is_mfg_mode() && msg->has_message && isValidModelNumber(msg->message)) { + set_mfg_mode_off(); + char message[32]; + strncpy(message, msg->message, sizeof(message)); + message[31] = 0; + flash_setModel(&message); + } + + if (msg->has_button_protection && msg->button_protection) + if (!confirm(ButtonRequestType_ButtonRequest_Ping, "Ping", "%s", + msg->message)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + layoutHome(); + return; + } + + if (msg->has_pin_protection && msg->pin_protection) { + CHECK_PIN + } + + if (msg->has_passphrase_protection && msg->passphrase_protection) { + if (!passphrase_protect()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + layoutHome(); + return; + } + } + + if (msg->has_message) { + resp->has_message = true; + memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); + } + + msg_write(MessageType_MessageType_Success, resp); + layoutHome(); +} - if(msg->has_button_protection && msg->button_protection) - if(!confirm(ButtonRequestType_ButtonRequest_Ping, "Ping", "%s", msg->message)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); - layoutHome(); - return; - } - - if(msg->has_pin_protection && msg->pin_protection) - { - CHECK_PIN - } +void fsm_msgChangePin(ChangePin *msg) { + bool removal = msg->has_remove && msg->remove; + bool confirmed = false; - if(msg->has_passphrase_protection && msg->passphrase_protection) - { - if(!passphrase_protect()) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); - layoutHome(); - return; - } + if (removal) { + if (storage_hasPin()) { + confirmed = + confirm(ButtonRequestType_ButtonRequest_RemovePin, "Remove PIN", + "Do you want to remove PIN protection?"); + } else { + fsm_sendSuccess("PIN removed"); + return; } + } else { + if (storage_hasPin()) + confirmed = confirm(ButtonRequestType_ButtonRequest_ChangePin, + "Change PIN", "Do you want to change your PIN?"); + else + confirmed = confirm(ButtonRequestType_ButtonRequest_CreatePin, + "Create PIN", "Do you want to add PIN protection?"); + } - if(msg->has_message) - { - resp->has_message = true; - memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); - } + if (!confirmed) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + removal ? "PIN removal cancelled" : "PIN change cancelled"); + layoutHome(); + return; + } + + CHECK_PIN_UNCACHED - msg_write(MessageType_MessageType_Success, resp); + if (removal) { + storage_setPin(""); + storage_commit(); + fsm_sendSuccess("PIN removed"); layoutHome(); + return; + } + + if (!change_pin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "PINs do not match"); + layoutHome(); + return; + } + + storage_commit(); + fsm_sendSuccess("PIN changed"); + layoutHome(); } -void fsm_msgChangePin(ChangePin *msg) -{ - bool removal = msg->has_remove && msg->remove; - bool confirmed = false; - - if(removal) - { - if(storage_hasPin()) - { - confirmed = confirm(ButtonRequestType_ButtonRequest_RemovePin, - "Remove PIN", "Do you want to remove PIN protection?"); - } - else - { - fsm_sendSuccess("PIN removed"); - return; - } - } - else - { - if(storage_hasPin()) - confirmed = confirm(ButtonRequestType_ButtonRequest_ChangePin, - "Change PIN", "Do you want to change your PIN?"); - else - confirmed = confirm(ButtonRequestType_ButtonRequest_CreatePin, - "Create PIN", "Do you want to add PIN protection?"); - } +void fsm_msgChangeWipeCode(ChangeWipeCode *msg) { + bool removal = msg->has_remove && msg->remove; + bool confirmed = false; - if(!confirmed) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - removal ? "PIN removal cancelled" : "PIN change cancelled"); - layoutHome(); - return; +#ifdef ENABLE_WIPECODE // disable until oled-vuln and automated test is in place + if (removal) { + if (storage_hasWipeCode()) { + confirmed = confirm(ButtonRequestType_ButtonRequest_RemoveWipeCode, + "Remove Wipe Code", + "Do you want to remove wipe code protection?"); + } else { + fsm_sendSuccess("Wipe code removed"); + return; + } + } else { + if (!storage_hasPin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "PIN must be set before setting wipe code"); + layoutHome(); + return; } - CHECK_PIN_UNCACHED + if (storage_hasWipeCode()) + confirmed = + confirm(ButtonRequestType_ButtonRequest_ChangeWipeCode, + "Change Wipe Code", "Do you want to change your wipe code?"); + else + confirmed = confirm(ButtonRequestType_ButtonRequest_CreateWipeCode, + "Create Wipe Code", + "Do you want to add wipe code protection?"); + } + + if (!confirmed) { + fsm_sendFailure( + FailureType_Failure_ActionCancelled, + removal ? "Wipe code removal cancelled" : "Wipe code change cancelled"); + layoutHome(); + return; + } - if (removal) { - storage_setPin(""); - storage_commit(); - fsm_sendSuccess("PIN removed"); - layoutHome(); - return; - } + CHECK_PIN_UNCACHED - if (!change_pin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "PINs do not match"); - layoutHome(); - return; - } + if (removal) { + storage_setWipeCode(""); storage_commit(); - fsm_sendSuccess("PIN changed"); + fsm_sendSuccess("Wipe code removed"); layoutHome(); -} + return; + } -void fsm_msgWipeDevice(WipeDevice *msg) -{ - (void)msg; + if (!change_wipe_code()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Wipe codes do not match"); + layoutHome(); + return; + } - if(!confirm(ButtonRequestType_ButtonRequest_WipeDevice, "Wipe Device", - "Do you want to erase your private keys and settings?")) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); - layoutHome(); - return; - } + storage_commit(); + fsm_sendSuccess("Wipe code changed"); + layoutHome(); - /* Wipe device */ - storage_wipe(); - storage_reset(); - storage_resetUuid(); - storage_commit(); +#else // ENABLE_WIPECODE + (void)removal; + (void)confirmed; - fsm_sendSuccess("Device wiped"); + fsm_sendSuccess("Wipe code function not available for this device"); + layoutHome(); +#endif + +} + +void fsm_msgWipeDevice(WipeDevice *msg) { + (void)msg; + + if (!confirm(ButtonRequestType_ButtonRequest_WipeDevice, "Wipe Device", + "Do you want to erase your private keys and settings?")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); layoutHome(); + return; + } + + /* Wipe device */ + storage_wipe(); + storage_reset(); + storage_resetUuid(); + storage_commit(); + + fsm_sendSuccess("Device wiped"); + layoutHome(); } -void fsm_msgFirmwareErase(FirmwareErase *msg) -{ - (void)msg; - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, - "Not in bootloader mode"); +void fsm_msgFirmwareErase(FirmwareErase *msg) { + (void)msg; + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in bootloader mode"); } -void fsm_msgFirmwareUpload(FirmwareUpload *msg) -{ - (void)msg; - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, - "Not in bootloader mode"); +void fsm_msgFirmwareUpload(FirmwareUpload *msg) { + (void)msg; + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in bootloader mode"); } -void fsm_msgGetEntropy(GetEntropy *msg) -{ - if(!confirm(ButtonRequestType_ButtonRequest_GetEntropy, - "Generate Entropy", - "Do you want to generate and return entropy using the hardware RNG?")) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); - layoutHome(); - return; - } +void fsm_msgGetEntropy(GetEntropy *msg) { + if (!confirm(ButtonRequestType_ButtonRequest_GetEntropy, "Generate Entropy", + "Do you want to generate and return entropy using the hardware " + "RNG?")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); + layoutHome(); + return; + } - RESP_INIT(Entropy); - uint32_t len = msg->size; + RESP_INIT(Entropy); + uint32_t len = msg->size; - if(len > ENTROPY_BUF) - { - len = ENTROPY_BUF; - } + if (len > ENTROPY_BUF) { + len = ENTROPY_BUF; + } - resp->entropy.size = len; - random_buffer(resp->entropy.bytes, len); - msg_write(MessageType_MessageType_Entropy, resp); - layoutHome(); + resp->entropy.size = len; + random_buffer(resp->entropy.bytes, len); + msg_write(MessageType_MessageType_Entropy, resp); + layoutHome(); } -void fsm_msgLoadDevice(LoadDevice *msg) -{ - CHECK_NOT_INITIALIZED +void fsm_msgLoadDevice(LoadDevice *msg) { + CHECK_NOT_INITIALIZED - if(!confirm_load_device(msg->has_node)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); - layoutHome(); - return; - } + if (!confirm_load_device(msg->has_node)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); + layoutHome(); + return; + } - if(msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) - { - if(!mnemonic_check(msg->mnemonic)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Mnemonic with wrong checksum provided"); - layoutHome(); - return; - } + if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) { + if (!mnemonic_check(msg->mnemonic)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Mnemonic with wrong checksum provided"); + layoutHome(); + return; } + } - storage_loadDevice(msg); + storage_loadDevice(msg); - storage_commit(); - fsm_sendSuccess("Device loaded"); - layoutHome(); -} + storage_commit(); -void fsm_msgResetDevice(ResetDevice *msg) -{ - CHECK_NOT_INITIALIZED + txin_dgst_initialize(); // reset tx tracking if seed words are loaded - reset_init( - msg->has_display_random && msg->display_random, - msg->has_strength ? msg->strength : 128, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_no_backup ? msg->no_backup : false, - msg->has_auto_lock_delay_ms ? msg->auto_lock_delay_ms : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT, - msg->has_u2f_counter ? msg->u2f_counter : 0 - ); + fsm_sendSuccess("Device loaded"); + layoutHome(); } -void fsm_msgEntropyAck(EntropyAck *msg) -{ - if(msg->has_entropy) - { - reset_entropy(msg->entropy.bytes, msg->entropy.size); - } - else - { - reset_entropy(0, 0); - } +void fsm_msgResetDevice(ResetDevice *msg) { + CHECK_NOT_INITIALIZED + + reset_init(msg->has_display_random && msg->display_random, + msg->has_strength ? msg->strength : 128, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_no_backup ? msg->no_backup : false, + msg->has_auto_lock_delay_ms ? msg->auto_lock_delay_ms + : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT, + msg->has_u2f_counter ? msg->u2f_counter : 0); } -void fsm_msgCancel(Cancel *msg) -{ - (void)msg; - recovery_cipher_abort(); - signing_abort(); - ethereum_signing_abort(); - cosmos_signAbort(); - eos_signingAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); +void fsm_msgEntropyAck(EntropyAck *msg) { + if (msg->has_entropy) { + reset_entropy(msg->entropy.bytes, msg->entropy.size); + } else { + reset_entropy(0, 0); + } } -void fsm_msgApplySettings(ApplySettings *msg) -{ - if (msg->has_label) { - if (!confirm(ButtonRequestType_ButtonRequest_ChangeLabel, - "Change Label", "Do you want to change the label to \"%s\"?", msg->label)) { - goto apply_settings_cancelled; - } - } - - if (msg->has_language) { - if (!confirm(ButtonRequestType_ButtonRequest_ChangeLanguage, - "Change Language", "Do you want to change the language to %s?", msg->language)) { - goto apply_settings_cancelled; - } - } - - if (msg->has_use_passphrase) { - if (msg->use_passphrase) { - if (!confirm(ButtonRequestType_ButtonRequest_EnablePassphrase, - "Enable Passphrase", "Do you want to enable BIP39 passphrases?")) { - goto apply_settings_cancelled; - } - } else { - if (!confirm(ButtonRequestType_ButtonRequest_DisablePassphrase, - "Disable Passphrase", "Do you want to disable BIP39 passphrases?")) { - goto apply_settings_cancelled; - } - } - } - - if (msg->has_auto_lock_delay_ms) { - if (!confirm(ButtonRequestType_ButtonRequest_AutoLockDelayMs, - "Change auto-lock delay", "Do you want to set the auto-lock delay to %" PRIu32 " seconds?", - msg->auto_lock_delay_ms / 1000)) { - goto apply_settings_cancelled; - } - } - - if (msg->has_u2f_counter) { - if (!confirm(ButtonRequestType_ButtonRequest_U2FCounter, - "Set U2F Counter", "Do you want to set the U2F Counter?")) { - goto apply_settings_cancelled; - } - } +void fsm_msgCancel(Cancel *msg) { + (void)msg; + recovery_cipher_abort(); + signing_abort(); + ethereum_signing_abort(); + cosmos_signAbort(); + eos_signingAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); +} - if (!msg->has_label && - !msg->has_language && - !msg->has_use_passphrase && - !msg->has_auto_lock_delay_ms && - !msg->has_u2f_counter) - { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); - return; - } +void fsm_msgApplySettings(ApplySettings *msg) { + if (msg->has_label) { + if (!confirm(ButtonRequestType_ButtonRequest_ChangeLabel, "Change Label", + "Do you want to change the label to \"%s\"?", msg->label)) { + goto apply_settings_cancelled; + } + } + + if (msg->has_language) { + if (!confirm(ButtonRequestType_ButtonRequest_ChangeLanguage, + "Change Language", "Do you want to change the language to %s?", + msg->language)) { + goto apply_settings_cancelled; + } + } + + if (msg->has_use_passphrase) { + if (msg->use_passphrase) { + if (!confirm(ButtonRequestType_ButtonRequest_EnablePassphrase, + "Enable Passphrase", + "Do you want to enable BIP39 passphrases?")) { + goto apply_settings_cancelled; + } + } else { + if (!confirm(ButtonRequestType_ButtonRequest_DisablePassphrase, + "Disable Passphrase", + "Do you want to disable BIP39 passphrases?")) { + goto apply_settings_cancelled; + } + } + } + + if (msg->has_auto_lock_delay_ms) { + if (!confirm(ButtonRequestType_ButtonRequest_AutoLockDelayMs, + "Change auto-lock delay", + "Do you want to set the auto-lock delay to %" PRIu32 + " seconds?", + msg->auto_lock_delay_ms / 1000)) { + goto apply_settings_cancelled; + } + } + + if (msg->has_u2f_counter) { + if (!confirm(ButtonRequestType_ButtonRequest_U2FCounter, "Set U2F Counter", + "Do you want to set the U2F Counter?")) { + goto apply_settings_cancelled; + } + } + + if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase && + !msg->has_auto_lock_delay_ms && !msg->has_u2f_counter) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); + return; + } - CHECK_PIN_UNCACHED + CHECK_PIN_UNCACHED - if (msg->has_label) { - storage_setLabel(msg->label); - } + if (msg->has_label) { + storage_setLabel(msg->label); + } - if (msg->has_language) { - storage_setLanguage(msg->language); - } + if (msg->has_language) { + storage_setLanguage(msg->language); + } - if (msg->has_use_passphrase) { - storage_setPassphraseProtected(msg->use_passphrase); - } + if (msg->has_use_passphrase) { + storage_setPassphraseProtected(msg->use_passphrase); + } - if (msg->has_auto_lock_delay_ms) { - storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); - } + if (msg->has_auto_lock_delay_ms) { + storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); + } - if (msg->has_u2f_counter) { - storage_setU2FCounter(msg->u2f_counter); - } + if (msg->has_u2f_counter) { + storage_setU2FCounter(msg->u2f_counter); + } - storage_commit(); + storage_commit(); - fsm_sendSuccess("Settings applied"); - layoutHome(); - return; + fsm_sendSuccess("Settings applied"); + layoutHome(); + return; apply_settings_cancelled: - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Apply settings cancelled"); - layoutHome(); - return; + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Apply settings cancelled"); + layoutHome(); + return; } -void fsm_msgRecoveryDevice(RecoveryDevice *msg) -{ - if (msg->has_dry_run && msg->dry_run) { - CHECK_INITIALIZED - } else { - CHECK_NOT_INITIALIZED - } - - recovery_cipher_init( - msg->has_word_count ? msg->word_count : 0, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist ? msg->enforce_wordlist : false, - msg->has_auto_lock_delay_ms ? msg->auto_lock_delay_ms : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT, - msg->has_u2f_counter ? msg->u2f_counter : 0, - msg->has_dry_run ? msg->dry_run : false - ); +void fsm_msgRecoveryDevice(RecoveryDevice *msg) { + if (msg->has_dry_run && msg->dry_run) { + CHECK_INITIALIZED + } else { + CHECK_NOT_INITIALIZED + } + + recovery_cipher_init( + msg->has_word_count ? msg->word_count : 0, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, + msg->has_enforce_wordlist ? msg->enforce_wordlist : false, + msg->has_auto_lock_delay_ms ? msg->auto_lock_delay_ms + : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT, + msg->has_u2f_counter ? msg->u2f_counter : 0, + msg->has_dry_run ? msg->dry_run : false); } -void fsm_msgCharacterAck(CharacterAck *msg) -{ - if (msg->has_delete && msg->del) { - recovery_delete_character(); - } else if(msg->has_done && msg->done) { - recovery_cipher_finalize(); - } else { - msg->character[1] = '\0'; - recovery_character(msg->character); - } +void fsm_msgCharacterAck(CharacterAck *msg) { + if (msg->has_delete && msg->del) { + recovery_delete_character(); + } else if (msg->has_done && msg->done) { + recovery_cipher_finalize(); + } else { + msg->character[1] = '\0'; + recovery_character(msg->character); + } } -void fsm_msgApplyPolicies(ApplyPolicies *msg) -{ - CHECK_PARAM(msg->policy_count > 0, "No policies provided"); +void fsm_msgApplyPolicies(ApplyPolicies *msg) { + CHECK_PARAM(msg->policy_count > 0, "No policies provided"); - for (size_t i = 0; i < msg->policy_count; ++i) { - CHECK_PARAM(msg->policy[i].has_policy_name, "Incorrect ApplyPolicies parameters"); - CHECK_PARAM(msg->policy[i].has_enabled, "Incorrect ApplyPolicies parameters"); - } + for (size_t i = 0; i < msg->policy_count; ++i) { + CHECK_PARAM(msg->policy[i].has_policy_name, + "Incorrect ApplyPolicies parameters"); + CHECK_PARAM(msg->policy[i].has_enabled, + "Incorrect ApplyPolicies parameters"); + } + + for (size_t i = 0; i < msg->policy_count; ++i) { + RESP_INIT(ButtonRequest); + resp->has_code = true; + resp->code = ButtonRequestType_ButtonRequest_ApplyPolicies; + resp->has_data = true; - for (size_t i = 0; i < msg->policy_count; ++i) { - RESP_INIT(ButtonRequest); - resp->has_code = true; - resp->code = ButtonRequestType_ButtonRequest_ApplyPolicies; - resp->has_data = true; - - strlcpy(resp->data, msg->policy[i].policy_name, sizeof(resp->data)); - - bool enabled = msg->policy[i].enabled; - strlcat(resp->data, enabled ? ":Enable" : ":Disable", sizeof(resp->data)); - - // ShapeShift policy is always enabled. - if (strcmp(msg->policy[i].policy_name, "ShapeShift") == 0) - continue; - - if (!confirm_with_custom_button_request( - resp, enabled ? "Enable Policy" : "Disable Policy", - "Do you want to %s %s policy?", - enabled ? "enable" : "disable", - msg->policy[i].policy_name)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Apply policies cancelled"); - layoutHome(); - return; - } + strlcpy(resp->data, msg->policy[i].policy_name, sizeof(resp->data)); + + bool enabled = msg->policy[i].enabled; + strlcat(resp->data, enabled ? ":Enable" : ":Disable", sizeof(resp->data)); + + // ShapeShift policy is always enabled. + if (strcmp(msg->policy[i].policy_name, "ShapeShift") == 0) continue; + + if (!confirm_with_custom_button_request( + resp, enabled ? "Enable Policy" : "Disable Policy", + "Do you want to %s %s policy?", enabled ? "enable" : "disable", + msg->policy[i].policy_name)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Apply policies cancelled"); + layoutHome(); + return; } + } - CHECK_PIN_UNCACHED + CHECK_PIN_UNCACHED - for (size_t i = 0; i < msg->policy_count; ++i) { - // ShapeShift policy is always enabled. - if (strcmp(msg->policy[i].policy_name, "ShapeShift") == 0) - continue; + for (size_t i = 0; i < msg->policy_count; ++i) { + // ShapeShift policy is always enabled. + if (strcmp(msg->policy[i].policy_name, "ShapeShift") == 0) continue; - if (!storage_setPolicy(msg->policy[i].policy_name, msg->policy[i].enabled)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Policies could not be applied"); - layoutHome(); - return; - } + if (!storage_setPolicy(msg->policy[i].policy_name, + msg->policy[i].enabled)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Policies could not be applied"); + layoutHome(); + return; } + } - storage_commit(); + storage_commit(); - fsm_sendSuccess("Policies applied"); - layoutHome(); + fsm_sendSuccess("Policies applied"); + layoutHome(); } - diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 5640e2758..ed3d9920b 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -1,213 +1,226 @@ -void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) -{ - RESP_INIT(CosmosAddress); +void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) { + RESP_INIT(CosmosAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const CoinType *coin = fsm_getCoin(true, "Cosmos"); - if (!coin) { return; } - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } + const CoinType *coin = fsm_getCoin(true, "Cosmos"); + if (!coin) { + return; + } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) { + return; + } - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - if (!tendermint_getAddress(node, "cosmos", resp->address)) { + if (!tendermint_getAddress(node, "cosmos", resp->address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Can't create Bip32 Path String")); + layoutHome(); + } + + bool mismatch = + tendermint_pathMismatched(coin, msg->address_n, msg->address_n_count); + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", + "Wrong address path for selected coin. Continue at your own " + "risk!")) { memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't encode address")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; + } } - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/false, - /*show_addridx=*/false) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't create Bip32 Path String")); - layoutHome(); - } - - bool mismatch = tendermint_pathMismatched(coin, msg->address_n, msg->address_n_count); - if (mismatch) { - if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", - "Wrong address path for selected coin. Continue at your own risk!")) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if(!confirm_ethereum_address(node_str, resp->address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); - layoutHome(); - return; - } + if (!confirm_ethereum_address(node_str, resp->address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show address cancelled"); + layoutHome(); + return; } + } - resp->has_address = true; + resp->has_address = true; - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_CosmosAddress, resp); - layoutHome(); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_CosmosAddress, resp); + layoutHome(); } -void fsm_msgCosmosSignTx(const CosmosSignTx *msg) -{ - CHECK_INITIALIZED - CHECK_PIN - - if (!msg->has_account_number || - !msg->has_chain_id || - !msg->has_fee_amount || - !msg->has_gas || - !msg->has_sequence) { - cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Missing Fields On Message"); - layoutHome(); - return; - } +void fsm_msgCosmosSignTx(const CosmosSignTx *msg) { + CHECK_INITIALIZED + CHECK_PIN - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } + if (!msg->has_account_number || !msg->has_chain_id || !msg->has_fee_amount || + !msg->has_gas || !msg->has_sequence) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Missing Fields On Message"); + layoutHome(); + return; + } - hdnode_fill_public_key(node); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) { + return; + } - RESP_INIT(CosmosMsgRequest); + hdnode_fill_public_key(node); - if (!cosmos_signTxInit(node, msg)) - { - cosmos_signAbort(); - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_FirmwareError, - _("Failed to initialize transaction signing")); - layoutHome(); - return; - } + RESP_INIT(CosmosMsgRequest); + if (!cosmos_signTxInit(node, msg)) { + cosmos_signAbort(); memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_CosmosMsgRequest, resp); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to initialize transaction signing")); layoutHome(); + return; + } + + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); + layoutHome(); } -void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { - // Confirm transaction basics - CHECK_PARAM(cosmos_signingIsInited(), "Signing not in progress"); - if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { - cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, - _("Invalid Cosmos Message Type")); - layoutHome(); - return; - } +void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg) { + // Confirm transaction basics + CHECK_PARAM(cosmos_signingIsInited(), "Signing not in progress"); + if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } - const CoinType *coin = fsm_getCoin(true, "Cosmos"); - if (!coin) { return; } + const CoinType *coin = fsm_getCoin(true, "Cosmos"); + if (!coin) { + return; + } - const CosmosSignTx *sign_tx = cosmos_getCosmosSignTx(); + const CosmosSignTx *sign_tx = cosmos_getCosmosSignTx(); - switch (msg->send.address_type) { + switch (msg->send.address_type) { case OutputAddressType_EXCHANGE: { - HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); - if (!root_node) { - cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); - layoutHome(); - return; - } - - int ret = run_policy_compile_output(coin, root_node, (void *)&msg->send, (void *)NULL, true); - if (ret < TXOUT_OK) { - memzero((void *)root_node, sizeof(*root_node)); - cosmos_signAbort(); - send_fsm_co_error_message(ret); - layoutHome(); - return; - } - - break; - } - case OutputAddressType_TRANSFER: - default: { - char amount_str[32]; - bn_format_uint64(msg->send.amount, NULL, " ATOM", 6, 0, false, amount_str, sizeof(amount_str)); - if (!confirm_transaction_output( - ButtonRequestType_ButtonRequest_ConfirmOutput, - amount_str, msg->send.to_address)) { - cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - break; - } - } - - if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { + HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); + if (!root_node) { cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to include send message in transaction"); + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); layoutHome(); return; - } - - if (!cosmos_signingIsFinished()) { - RESP_INIT(CosmosMsgRequest); - msg_write(MessageType_MessageType_CosmosMsgRequest, resp); - return; - } + } - if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, - _("Memo"), "%s", sign_tx->memo)) - { + int ret = run_policy_compile_output(coin, root_node, (void *)&msg->send, + (void *)NULL, true); + if (ret < TXOUT_OK) { + memzero((void *)root_node, sizeof(*root_node)); cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + send_fsm_co_error_message(ret); layoutHome(); return; - } + } - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, sign_tx->address_n, - sign_tx->address_n_count, /*whole_account=*/false, - /*show_addridx=*/false) && - !bip32_path_to_string(node_str, sizeof(node_str), - sign_tx->address_n, sign_tx->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); + break; } - - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, - "Sign this Cosmos transaction on %s? " - "It includes a fee of %" PRIu32 " uATOM and %" PRIu32 " gas.", - sign_tx->chain_id, sign_tx->fee_amount, sign_tx->gas)) - { + case OutputAddressType_TRANSFER: + default: { + char amount_str[32]; + bn_format_uint64(msg->send.amount, NULL, " ATOM", 6, 0, false, amount_str, + sizeof(amount_str)); + if (!confirm_transaction_output( + ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, + msg->send.to_address)) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; + } + + break; } + } - RESP_INIT(CosmosSignedTx); + if (!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to include send message in transaction"); + layoutHome(); + return; + } - if(!cosmos_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { - cosmos_signAbort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Failed to finalize signature"); - layoutHome(); - return; - } + if (!cosmos_signingIsFinished()) { + RESP_INIT(CosmosMsgRequest); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); + return; + } + + if (sign_tx->has_memo && !confirm(ButtonRequestType_ButtonRequest_ConfirmMemo, + _("Memo"), "%s", sign_tx->memo)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, + sign_tx->address_n, sign_tx->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/false) && + !bip32_path_to_string(node_str, sizeof(node_str), sign_tx->address_n, + sign_tx->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, node_str, + "Sign this Cosmos transaction on %s? " + "It includes a fee of %" PRIu32 " uATOM and %" PRIu32 " gas.", + sign_tx->chain_id, sign_tx->fee_amount, sign_tx->gas)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + RESP_INIT(CosmosSignedTx); - resp->public_key.size = 33; - resp->has_public_key = true; - resp->signature.size = 64; - resp->has_signature = true; + if (!cosmos_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Failed to finalize signature"); layoutHome(); - msg_write(MessageType_MessageType_CosmosSignedTx, resp); + return; + } + + resp->public_key.size = 33; + resp->has_public_key = true; + resp->signature.size = 64; + resp->has_signature = true; + cosmos_signAbort(); + layoutHome(); + msg_write(MessageType_MessageType_CosmosSignedTx, resp); } diff --git a/lib/firmware/fsm_msg_crypto.h b/lib/firmware/fsm_msg_crypto.h index b0c3737c9..22ce35163 100644 --- a/lib/firmware/fsm_msg_crypto.h +++ b/lib/firmware/fsm_msg_crypto.h @@ -1,145 +1,155 @@ -void fsm_msgCipherKeyValue(CipherKeyValue *msg) -{ - CHECK_INITIALIZED +void fsm_msgCipherKeyValue(CipherKeyValue *msg) { + CHECK_INITIALIZED - CHECK_PARAM(msg->has_key, "No key provided"); + CHECK_PARAM(msg->has_key, "No key provided"); - CHECK_PARAM(msg->has_value, "No value provided"); + CHECK_PARAM(msg->has_value, "No value provided"); - CHECK_PARAM(!(msg->value.size % 16), "Value length must be a multiple of 16"); + CHECK_PARAM(!(msg->value.size % 16), "Value length must be a multiple of 16"); - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); - if(!node) { return; } + if (!node) { + return; + } - bool encrypt = msg->has_encrypt && msg->encrypt; - bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; - bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; + bool encrypt = msg->has_encrypt && msg->encrypt; + bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; + bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; - if((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) - { - if(!confirm_cipher(encrypt, msg->key)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "CipherKeyValue cancelled"); - layoutHome(); - return; - } + if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { + if (!confirm_cipher(encrypt, msg->key)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "CipherKeyValue cancelled"); + layoutHome(); + return; } - - uint8_t data[256 + 4]; - strlcpy((char *)data, msg->key, sizeof(data)); - strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); - strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); - - hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); - - RESP_INIT(CipheredKeyValue); - - if(encrypt) - { - aes_encrypt_ctx ctx; - aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, - ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); - } - else - { - aes_decrypt_ctx ctx; - aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, - ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); - } - - resp->has_value = true; - resp->value.size = msg->value.size; - msg_write(MessageType_MessageType_CipheredKeyValue, resp); - layoutHome(); + } + + uint8_t data[256 + 4]; + strlcpy((char *)data, msg->key, sizeof(data)); + strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); + strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); + + hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); + + RESP_INIT(CipheredKeyValue); + + if (encrypt) { + aes_encrypt_ctx ctx; + aes_encrypt_key256(data, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, + ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), + &ctx); + } else { + aes_decrypt_ctx ctx; + aes_decrypt_key256(data, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, + ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), + &ctx); + } + + resp->has_value = true; + resp->value.size = msg->value.size; + msg_write(MessageType_MessageType_CipheredKeyValue, resp); + layoutHome(); } -void fsm_msgSignIdentity(SignIdentity *msg) -{ - RESP_INIT(SignedIdentity); - - CHECK_INITIALIZED - - if (!confirm_sign_identity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); - layoutHome(); - return; - } - - CHECK_PIN - - uint8_t hash[32]; - if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) - { - fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); - layoutHome(); - return; - } - - uint32_t address_n[5]; - address_n[0] = 0x80000000 | 13; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t)hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t)hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t)hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t)hash[15] << 24); +void fsm_msgSignIdentity(SignIdentity *msg) { + RESP_INIT(SignedIdentity); - const char *curve = SECP256K1_NAME; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); - if (!node) { return; } + CHECK_INITIALIZED - bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); - bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); + if (!confirm_sign_identity(&(msg->identity), msg->has_challenge_visual + ? msg->challenge_visual + : 0)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Sign identity cancelled"); + layoutHome(); + return; + } - int result = 0; - layout_simple_message("Signing Identity..."); + CHECK_PIN - if (sign_ssh) { // SSH does not sign visual challenge - result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); - } else if (sign_gpg) { // GPG should sign a message digest - result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); + uint8_t hash[32]; + if (!msg->has_identity || + cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); + layoutHome(); + return; + } + + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 13; + address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) | + ((uint32_t)hash[3] << 24); + address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) | + ((uint32_t)hash[7] << 24); + address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) | + ((uint32_t)hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | + ((uint32_t)hash[15] << 24); + + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); + if (!node) { + return; + } + + bool sign_ssh = + msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); + bool sign_gpg = + msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); + + int result = 0; + layout_simple_message("Signing Identity..."); + + if (sign_ssh) { // SSH does not sign visual challenge + result = sshMessageSign(node, msg->challenge_hidden.bytes, + msg->challenge_hidden.size, resp->signature.bytes); + } else if (sign_gpg) { // GPG should sign a message digest + result = gpgMessageSign(node, msg->challenge_hidden.bytes, + msg->challenge_hidden.size, resp->signature.bytes); + } else { + uint8_t digest[64]; + sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); + sha256_Raw((const uint8_t *)msg->challenge_visual, + strlen(msg->challenge_visual), digest + 32); + result = cryptoMessageSign(coinByName("Bitcoin"), node, + InputScriptType_SPENDADDRESS, digest, 64, + resp->signature.bytes); + } + + if (result == 0) { + hdnode_fill_public_key(node); + if (strcmp(curve, SECP256K1_NAME) != 0) { + resp->has_address = false; } else { - uint8_t digest[64]; - sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); - sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(coinByName("Bitcoin"), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); - } - - if (result == 0) { - hdnode_fill_public_key(node); - if (strcmp(curve, SECP256K1_NAME) != 0) - { - resp->has_address = false; - } - else - { - resp->has_address = true; - hdnode_fill_public_key(node); - hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type - } - resp->has_public_key = true; - resp->public_key.size = 33; - memcpy(resp->public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->public_key.bytes[0] = 0; - } - resp->has_signature = true; - resp->signature.size = 65; - msg_write(MessageType_MessageType_SignedIdentity, resp); + resp->has_address = true; + hdnode_fill_public_key(node); + hdnode_get_address( + node, 0x00, resp->address, + sizeof(resp->address)); // hardcoded Bitcoin address type } - else - { - fsm_sendFailure(FailureType_Failure_Other, "Error signing identity"); + resp->has_public_key = true; + resp->public_key.size = 33; + memcpy(resp->public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->public_key.bytes[0] = 0; } - - layoutHome(); + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_SignedIdentity, resp); + } else { + fsm_sendFailure(FailureType_Failure_Other, "Error signing identity"); + } + + layoutHome(); } diff --git a/lib/firmware/fsm_msg_debug.h b/lib/firmware/fsm_msg_debug.h index a487d1751..d44c26109 100644 --- a/lib/firmware/fsm_msg_debug.h +++ b/lib/firmware/fsm_msg_debug.h @@ -1,80 +1,74 @@ #if DEBUG_LINK -void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) -{ - (void)msg; - RESP_INIT(DebugLinkState); +void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) { + (void)msg; + RESP_INIT(DebugLinkState); - if(storage_hasPin()) - { - resp->has_pin = true; - strlcpy(resp->pin, storage_getPin(), sizeof(resp->pin)); - } + if (storage_hasPin()) { + resp->has_pin = true; + strlcpy(resp->pin, storage_getPin(), sizeof(resp->pin)); + } - resp->has_matrix = true; - strlcpy(resp->matrix, get_pin_matrix(), sizeof(resp->matrix)); + resp->has_matrix = true; + strlcpy(resp->matrix, get_pin_matrix(), sizeof(resp->matrix)); - resp->has_reset_entropy = true; - resp->reset_entropy.size = reset_get_int_entropy(resp->reset_entropy.bytes); + resp->has_reset_entropy = true; + resp->reset_entropy.size = reset_get_int_entropy(resp->reset_entropy.bytes); - resp->has_reset_word = true; - strlcpy(resp->reset_word, reset_get_word(), sizeof(resp->reset_word)); + resp->has_reset_word = true; + strlcpy(resp->reset_word, reset_get_word(), sizeof(resp->reset_word)); - if(storage_hasMnemonic()) - { - resp->has_mnemonic = true; - strlcpy(resp->mnemonic, storage_getMnemonic(), sizeof(resp->mnemonic)); - } + if (storage_hasMnemonic()) { + resp->has_mnemonic = true; + strlcpy(resp->mnemonic, storage_getMnemonic(), sizeof(resp->mnemonic)); + } - if(storage_hasNode()) - { - resp->has_node = true; - storage_dumpNode(&resp->node, storage_getNode()); - } + if (storage_hasNode()) { + resp->has_node = true; + storage_dumpNode(&resp->node, storage_getNode()); + } - resp->has_passphrase_protection = true; - resp->passphrase_protection = storage_getPassphraseProtected(); + resp->has_passphrase_protection = true; + resp->passphrase_protection = storage_getPassphraseProtected(); - resp->has_recovery_cipher = true; - strlcpy(resp->recovery_cipher, recovery_get_cipher(), - sizeof(resp->recovery_cipher)); + resp->has_recovery_cipher = true; + strlcpy(resp->recovery_cipher, recovery_get_cipher(), + sizeof(resp->recovery_cipher)); - resp->has_recovery_auto_completed_word = true; - strlcpy(resp->recovery_auto_completed_word, recovery_get_auto_completed_word(), - sizeof(resp->recovery_auto_completed_word)); + resp->has_recovery_auto_completed_word = true; + strlcpy(resp->recovery_auto_completed_word, + recovery_get_auto_completed_word(), + sizeof(resp->recovery_auto_completed_word)); - resp->has_firmware_hash = true; - resp->firmware_hash.size = memory_firmware_hash(resp->firmware_hash.bytes); + resp->has_firmware_hash = true; + resp->firmware_hash.size = memory_firmware_hash(resp->firmware_hash.bytes); - resp->has_storage_hash = true; - resp->storage_hash.size = memory_storage_hash(resp->storage_hash.bytes, - storage_getLocation()); + resp->has_storage_hash = true; + resp->storage_hash.size = + memory_storage_hash(resp->storage_hash.bytes, storage_getLocation()); - msg_debug_write(MessageType_MessageType_DebugLinkState, resp); + msg_debug_write(MessageType_MessageType_DebugLinkState, resp); } -void fsm_msgDebugLinkStop(DebugLinkStop *msg) -{ - (void)msg; -} +void fsm_msgDebugLinkStop(DebugLinkStop *msg) { (void)msg; } -void fsm_msgDebugLinkFlashDump(DebugLinkFlashDump *msg) -{ +void fsm_msgDebugLinkFlashDump(DebugLinkFlashDump *msg) { #ifndef EMULATOR - if (!msg->has_length || msg->length > sizeof(((DebugLinkFlashDumpResponse *)0)->data.bytes)) { + if (!msg->has_length || + msg->length > sizeof(((DebugLinkFlashDumpResponse *)0)->data.bytes)) { #endif - fsm_sendFailure(FailureType_Failure_Other, "Invalid FlashDump parameters"); - layoutHome(); - return; + fsm_sendFailure(FailureType_Failure_Other, "Invalid FlashDump parameters"); + layoutHome(); + return; #ifndef EMULATOR - } + } - RESP_INIT(DebugLinkFlashDumpResponse); + RESP_INIT(DebugLinkFlashDumpResponse); - memcpy(resp->data.bytes, (void*)msg->address, msg->length); + memcpy(resp->data.bytes, (void *)msg->address, msg->length); - resp->has_data = true; - resp->data.size = msg->length; - msg_write(MessageType_MessageType_DebugLinkFlashDumpResponse, resp); + resp->has_data = true; + resp->data.size = msg->length; + msg_write(MessageType_MessageType_DebugLinkFlashDumpResponse, resp); #endif } diff --git a/lib/firmware/fsm_msg_eos.h b/lib/firmware/fsm_msg_eos.h index cc6be83d6..24d7c8c51 100644 --- a/lib/firmware/fsm_msg_eos.h +++ b/lib/firmware/fsm_msg_eos.h @@ -18,193 +18,183 @@ */ void fsm_msgEosGetPublicKey(const EosGetPublicKey *msg) { - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const CoinType *coin = fsm_getCoin(true, "EOS"); - if (!coin) return; + const CoinType *coin = fsm_getCoin(true, "EOS"); + if (!coin) return; - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return; + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return; - uint32_t fingerprint; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, &fingerprint); - if (!node) return; - hdnode_fill_public_key(node); + uint32_t fingerprint; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); - RESP_INIT(EosPublicKey); + RESP_INIT(EosPublicKey); - if (!eos_getPublicKey(node, curve, msg->kind, - resp->wif_public_key, sizeof(resp->wif_public_key))) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, "Could not derive EOS pubkey"); - layoutHome(); - return; + if (!eos_getPublicKey(node, curve, msg->kind, resp->wif_public_key, + sizeof(resp->wif_public_key))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, "Could not derive EOS pubkey"); + layoutHome(); + return; + } + resp->has_wif_public_key = true; + + resp->has_raw_public_key = true; + resp->raw_public_key.size = 33; + memcpy(resp->raw_public_key.bytes, node->public_key, 33); + _Static_assert(sizeof(resp->raw_public_key.bytes) == 33, "size mismatch"); + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); } - resp->has_wif_public_key = true; - - resp->has_raw_public_key = true; - resp->raw_public_key.size = 33; - memcpy(resp->raw_public_key.bytes, node->public_key, 33); - _Static_assert(sizeof(resp->raw_public_key.bytes) == 33, "size mismatch"); - - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, - msg->address_n, - msg->address_n_count, - /*whole_account=*/false, - /*show_addridx=*/true) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - - if (!confirm(ButtonRequestType_ButtonRequest_Address, node_str, - "%s", resp->wif_public_key)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - "Show EOS public key cancelled."); - layoutHome(); - return; - } + + if (!confirm(ButtonRequestType_ButtonRequest_Address, node_str, "%s", + resp->wif_public_key)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show EOS public key cancelled."); + layoutHome(); + return; } + } - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_EosPublicKey, resp); - layoutHome(); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_EosPublicKey, resp); + layoutHome(); } void fsm_msgEosSignTx(const EosSignTx *msg) { - CHECK_PARAM(msg->chain_id.size == 32, "Wrong chain_id size"); - CHECK_PARAM(msg->has_header, "Must have transaction header"); - CHECK_PARAM(msg->has_num_actions && 0 < msg->num_actions, - "Eos transaction must have actions"); + CHECK_PARAM(msg->chain_id.size == 32, "Wrong chain_id size"); + CHECK_PARAM(msg->has_header, "Must have transaction header"); + CHECK_PARAM(msg->has_num_actions && 0 < msg->num_actions, + "Eos transaction must have actions"); - CHECK_PARAM(msg->header.max_cpu_usage_ms <= UINT8_MAX, - "Value overflow"); - CHECK_PARAM(msg->header.ref_block_num <= UINT16_MAX, - "Value overflow"); + CHECK_PARAM(msg->header.max_cpu_usage_ms <= UINT8_MAX, "Value overflow"); + CHECK_PARAM(msg->header.ref_block_num <= UINT16_MAX, "Value overflow"); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - HDNode *root = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); - if (!root) return; - hdnode_fill_public_key(root); + HDNode *root = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); + if (!root) return; + hdnode_fill_public_key(root); - eos_signingInit(msg->chain_id.bytes, msg->num_actions, &msg->header, - root, msg->address_n, msg->address_n_count); + eos_signingInit(msg->chain_id.bytes, msg->num_actions, &msg->header, root, + msg->address_n, msg->address_n_count); - memzero(root, sizeof(*root)); - RESP_INIT(EosTxActionRequest); - msg_write(MessageType_MessageType_EosTxActionRequest, resp); + memzero(root, sizeof(*root)); + RESP_INIT(EosTxActionRequest); + msg_write(MessageType_MessageType_EosTxActionRequest, resp); } void fsm_msgEosTxActionAck(const EosTxActionAck *msg) { - CHECK_PARAM(eos_signingIsInited(), "Must call EosSignTx to initiate signing"); - CHECK_PARAM(msg->has_common, "Must have common"); - - int action_count = - (int)msg->has_transfer + - (int)msg->has_delegate + - (int)msg->has_undelegate + - (int)msg->has_refund + - (int)msg->has_buy_ram + - (int)msg->has_buy_ram_bytes + - (int)msg->has_sell_ram + - (int)msg->has_vote_producer + - (int)msg->has_update_auth + - (int)msg->has_delete_auth + - (int)msg->has_link_auth + - (int)msg->has_unlink_auth + - (int)msg->has_new_account + - (int)msg->has_unknown + - 0; - CHECK_PARAM(action_count == 1, "Eos signing can only handle one action at a time"); - - if (eos_hasActionUnknownDataRemaining()) { - if (!msg->has_unknown) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Expected more EOSActionUnknown data chunks"); - eos_signingAbort(); - layoutHome(); - return; - } - } else if (eos_actionsRemaining() < 1) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Action count mismatch"); - eos_signingAbort(); - layoutHome(); - return; - } - - if (msg->has_transfer) { - if (!eos_compileActionTransfer(&msg->common, &msg->transfer)) - goto action_compile_failed; - } else if (msg->has_delegate) { - if (!eos_compileActionDelegate(&msg->common, &msg->delegate)) - goto action_compile_failed; - } else if (msg->has_undelegate) { - if (!eos_compileActionUndelegate(&msg->common, &msg->undelegate)) - goto action_compile_failed; - } else if (msg->has_refund) { - if (!eos_compileActionRefund(&msg->common, &msg->refund)) - goto action_compile_failed; - } else if (msg->has_buy_ram) { - if (!eos_compileActionBuyRam(&msg->common, &msg->buy_ram)) - goto action_compile_failed; - } else if (msg->has_buy_ram_bytes) { - if (!eos_compileActionBuyRamBytes(&msg->common, &msg->buy_ram_bytes)) - goto action_compile_failed; - } else if (msg->has_sell_ram) { - if (!eos_compileActionSellRam(&msg->common, &msg->sell_ram)) - goto action_compile_failed; - } else if (msg->has_vote_producer) { - if (!eos_compileActionVoteProducer(&msg->common, &msg->vote_producer)) - goto action_compile_failed; - } else if (msg->has_update_auth) { - if (!eos_compileActionUpdateAuth(&msg->common, &msg->update_auth)) - goto action_compile_failed; - } else if (msg->has_delete_auth) { - if (!eos_compileActionDeleteAuth(&msg->common, &msg->delete_auth)) - goto action_compile_failed; - } else if (msg->has_link_auth) { - if (!eos_compileActionLinkAuth(&msg->common, &msg->link_auth)) - goto action_compile_failed; - } else if (msg->has_unlink_auth) { - if (!eos_compileActionUnlinkAuth(&msg->common, &msg->unlink_auth)) - goto action_compile_failed; - } else if (msg->has_new_account) { - if (!eos_compileActionNewAccount(&msg->common, &msg->new_account)) - goto action_compile_failed; - } else if (msg->has_unknown) { - if (!eos_compileActionUnknown(&msg->common, &msg->unknown)) - goto action_compile_failed; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Unknown action"); - eos_signingAbort(); - layoutHome(); - return; + CHECK_PARAM(eos_signingIsInited(), "Must call EosSignTx to initiate signing"); + CHECK_PARAM(msg->has_common, "Must have common"); + + int action_count = (int)msg->has_transfer + (int)msg->has_delegate + + (int)msg->has_undelegate + (int)msg->has_refund + + (int)msg->has_buy_ram + (int)msg->has_buy_ram_bytes + + (int)msg->has_sell_ram + (int)msg->has_vote_producer + + (int)msg->has_update_auth + (int)msg->has_delete_auth + + (int)msg->has_link_auth + (int)msg->has_unlink_auth + + (int)msg->has_new_account + (int)msg->has_unknown + 0; + CHECK_PARAM(action_count == 1, + "Eos signing can only handle one action at a time"); + + if (eos_hasActionUnknownDataRemaining()) { + if (!msg->has_unknown) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Expected more EOSActionUnknown data chunks"); + eos_signingAbort(); + layoutHome(); + return; } + } else if (eos_actionsRemaining() < 1) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Action count mismatch"); + eos_signingAbort(); + layoutHome(); + return; + } + + if (msg->has_transfer) { + if (!eos_compileActionTransfer(&msg->common, &msg->transfer)) + goto action_compile_failed; + } else if (msg->has_delegate) { + if (!eos_compileActionDelegate(&msg->common, &msg->delegate)) + goto action_compile_failed; + } else if (msg->has_undelegate) { + if (!eos_compileActionUndelegate(&msg->common, &msg->undelegate)) + goto action_compile_failed; + } else if (msg->has_refund) { + if (!eos_compileActionRefund(&msg->common, &msg->refund)) + goto action_compile_failed; + } else if (msg->has_buy_ram) { + if (!eos_compileActionBuyRam(&msg->common, &msg->buy_ram)) + goto action_compile_failed; + } else if (msg->has_buy_ram_bytes) { + if (!eos_compileActionBuyRamBytes(&msg->common, &msg->buy_ram_bytes)) + goto action_compile_failed; + } else if (msg->has_sell_ram) { + if (!eos_compileActionSellRam(&msg->common, &msg->sell_ram)) + goto action_compile_failed; + } else if (msg->has_vote_producer) { + if (!eos_compileActionVoteProducer(&msg->common, &msg->vote_producer)) + goto action_compile_failed; + } else if (msg->has_update_auth) { + if (!eos_compileActionUpdateAuth(&msg->common, &msg->update_auth)) + goto action_compile_failed; + } else if (msg->has_delete_auth) { + if (!eos_compileActionDeleteAuth(&msg->common, &msg->delete_auth)) + goto action_compile_failed; + } else if (msg->has_link_auth) { + if (!eos_compileActionLinkAuth(&msg->common, &msg->link_auth)) + goto action_compile_failed; + } else if (msg->has_unlink_auth) { + if (!eos_compileActionUnlinkAuth(&msg->common, &msg->unlink_auth)) + goto action_compile_failed; + } else if (msg->has_new_account) { + if (!eos_compileActionNewAccount(&msg->common, &msg->new_account)) + goto action_compile_failed; + } else if (msg->has_unknown) { + if (!eos_compileActionUnknown(&msg->common, &msg->unknown)) + goto action_compile_failed; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Unknown action"); + eos_signingAbort(); + layoutHome(); + return; + } - if (!eos_signingIsFinished()) { - RESP_INIT(EosTxActionRequest); - msg_write(MessageType_MessageType_EosTxActionRequest, resp); - return; - } + if (!eos_signingIsFinished()) { + RESP_INIT(EosTxActionRequest); + msg_write(MessageType_MessageType_EosTxActionRequest, resp); + return; + } - RESP_INIT(EosSignedTx); + RESP_INIT(EosSignedTx); - if (!eos_signTx(resp)) - return; + if (!eos_signTx(resp)) return; - layoutHome(); - msg_write(MessageType_MessageType_EosSignedTx, resp); - return; + layoutHome(); + msg_write(MessageType_MessageType_EosSignedTx, resp); + return; action_compile_failed: - eos_signingAbort(); - layoutHome(); - return; + eos_signingAbort(); + layoutHome(); + return; } diff --git a/lib/firmware/fsm_msg_ethereum.h b/lib/firmware/fsm_msg_ethereum.h index f8a9b735c..1e243bcf7 100644 --- a/lib/firmware/fsm_msg_ethereum.h +++ b/lib/firmware/fsm_msg_ethereum.h @@ -1,235 +1,236 @@ -static int process_ethereum_xfer(const CoinType *coin, EthereumSignTx *msg) -{ - if (!ethereum_isStandardERC20Transfer(msg) && msg->data_length != 0) - return TXOUT_COMPILE_ERROR; +static int process_ethereum_xfer(const CoinType *coin, EthereumSignTx *msg) { + if (!ethereum_isStandardERC20Transfer(msg) && msg->data_length != 0) + return TXOUT_COMPILE_ERROR; + + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->to_address_n, + msg->to_address_n_count, /*whole_account=*/false, + /*show_addridx=*/false)) + return TXOUT_COMPILE_ERROR; + + if (!coin->has_forkid) return TXOUT_COMPILE_ERROR; + + const uint32_t chain_id = coin->forkid; + + const uint8_t *value_bytes; + size_t value_size; + const TokenType *token; + + if (ethereum_isStandardERC20Transfer(msg)) { + value_bytes = msg->data_initial_chunk.bytes + 4 + 32; + value_size = 32; + token = tokenByChainAddress(chain_id, msg->to.bytes); + } else { + value_bytes = msg->value.bytes; + value_size = msg->value.size; + token = NULL; + } + + bignum256 value; + bn_from_bytes(value_bytes, value_size, &value); + + char amount_str[128 + sizeof(msg->token_shortcut) + 3]; + ethereumFormatAmount(&value, token, chain_id, amount_str, sizeof(amount_str)); + + if (!confirm_transfer_output( + ButtonRequestType_ButtonRequest_ConfirmTransferToAccount, amount_str, + node_str)) + return TXOUT_CANCEL; + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->to_address_n, + msg->to_address_n_count, NULL); + if (!node) return TXOUT_COMPILE_ERROR; + + uint8_t to_bytes[20]; + if (!hdnode_get_ethereum_pubkeyhash(node, to_bytes)) + return TXOUT_COMPILE_ERROR; + + if (ethereum_isStandardERC20Transfer(msg)) { + if (memcmp(msg->data_initial_chunk.bytes + 4 + (32 - 20), to_bytes, 20) != + 0) + return TXOUT_COMPILE_ERROR; + } else { + msg->has_to = true; + msg->to.size = 20; + memcpy(msg->to.bytes, to_bytes, sizeof(to_bytes)); + } + + memzero((void *)node, sizeof(HDNode)); + return TXOUT_OK; +} - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->to_address_n, - msg->to_address_n_count, /*whole_account=*/false, - /*show_addridx=*/false)) - return TXOUT_COMPILE_ERROR; - - if (!coin->has_forkid) - return TXOUT_COMPILE_ERROR; - - const uint32_t chain_id = coin->forkid; - - const uint8_t *value_bytes; - size_t value_size; - const TokenType *token; - - if (ethereum_isStandardERC20Transfer(msg)) { - value_bytes = msg->data_initial_chunk.bytes + 4 + 32; - value_size = 32; - token = tokenByChainAddress(chain_id, msg->to.bytes); - } else { - value_bytes = msg->value.bytes; - value_size = msg->value.size; - token = NULL; - } +static int process_ethereum_msg(EthereumSignTx *msg, bool *needs_confirm) { + const CoinType *coin = fsm_getCoin(true, ETHEREUM); + if (!coin) return TXOUT_COMPILE_ERROR; - bignum256 value; - bn_from_bytes(value_bytes, value_size, &value); + switch (msg->address_type) { + case OutputAddressType_EXCHANGE: { + // prep for exchange type transaction + HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); + if (!root_node) return TXOUT_COMPILE_ERROR; + + int ret = run_policy_compile_output(coin, root_node, (void *)msg, + (void *)NULL, true); + if (ret < TXOUT_OK) { + memzero((void *)root_node, sizeof(HDNode)); + } + *needs_confirm = false; + return ret; + } + case OutputAddressType_TRANSFER: { + // prep transfer type transaction + *needs_confirm = false; + return process_ethereum_xfer(coin, msg); + } + default: + return TXOUT_OK; + } +} - char amount_str[128+sizeof(msg->token_shortcut)+3]; - ethereumFormatAmount(&value, token, chain_id, amount_str, sizeof(amount_str)); +void fsm_msgEthereumSignTx(EthereumSignTx *msg) { + CHECK_INITIALIZED - if (!confirm_transfer_output(ButtonRequestType_ButtonRequest_ConfirmTransferToAccount, - amount_str, node_str)) - return TXOUT_CANCEL; + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->to_address_n, msg->to_address_n_count, NULL); - if (!node) - return TXOUT_COMPILE_ERROR; + bool needs_confirm = true; + int msg_result = process_ethereum_msg(msg, &needs_confirm); - uint8_t to_bytes[20]; - if (!hdnode_get_ethereum_pubkeyhash(node, to_bytes)) - return TXOUT_COMPILE_ERROR; + if (msg_result < TXOUT_OK) { + ethereum_signing_abort(); + send_fsm_co_error_message(msg_result); + layoutHome(); + return; + } - if (ethereum_isStandardERC20Transfer(msg)) { - if (memcmp(msg->data_initial_chunk.bytes + 4 + (32 - 20), to_bytes, 20) != 0) - return TXOUT_COMPILE_ERROR; - } else { - msg->has_to = true; - msg->to.size = 20; - memcpy(msg->to.bytes, to_bytes, sizeof(to_bytes)); - } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - memzero((void *)node, sizeof(HDNode)); - return TXOUT_OK; + ethereum_signing_init(msg, node, needs_confirm); + memzero(node, sizeof(*node)); } -static int process_ethereum_msg(EthereumSignTx *msg, bool *needs_confirm) -{ - const CoinType *coin = fsm_getCoin(true, ETHEREUM); - if (!coin) - return TXOUT_COMPILE_ERROR; +void fsm_msgEthereumTxAck(EthereumTxAck *msg) { ethereum_signing_txack(msg); } - switch (msg->address_type) { - case OutputAddressType_EXCHANGE: { - // prep for exchange type transaction - HDNode *root_node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0, NULL); - if (!root_node) - return TXOUT_COMPILE_ERROR; - - int ret = run_policy_compile_output(coin, root_node, (void *)msg, (void *)NULL, true); - if(ret < TXOUT_OK) { - memzero((void *)root_node, sizeof(HDNode)); - } - *needs_confirm = false; - return ret; - } - case OutputAddressType_TRANSFER: { - // prep transfer type transaction - *needs_confirm = false; - return process_ethereum_xfer(coin, msg); - } - default: - return TXOUT_OK; - } -} +void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) { + RESP_INIT(EthereumAddress); -void fsm_msgEthereumSignTx(EthereumSignTx *msg) -{ - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - bool needs_confirm = true; - int msg_result = process_ethereum_msg(msg, &needs_confirm); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - if (msg_result < TXOUT_OK) { - ethereum_signing_abort(); - send_fsm_co_error_message(msg_result); - layoutHome(); - return; - } + resp->address.size = 20; - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { + memzero(node, sizeof(*node)); + return; + } - ethereum_signing_init(msg, node, needs_confirm); - memzero(node, sizeof(*node)); -} + const CoinType *coin = NULL; + bool rskip60 = false; + uint32_t chain_id = 0; -void fsm_msgEthereumTxAck(EthereumTxAck *msg) -{ - ethereum_signing_txack(msg); -} + if (msg->address_n_count == 5) { + coin = coinBySlip44(msg->address_n[1]); + uint32_t slip44 = msg->address_n[1] & 0x7fffffff; + // constants from trezor-common/defs/ethereum/networks.json + switch (slip44) { + case 137: + rskip60 = true; + chain_id = 30; + break; + case 37310: + rskip60 = true; + chain_id = 31; + break; + } + } + + char address[43] = {'0', 'x'}; + ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, + chain_id); + + resp->has_address_str = true; + strlcpy(resp->address_str, address, sizeof(resp->address_str)); + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!(coin && isEthereumLike(coin->coin_name) && + bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/false)) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + if (!confirm_ethereum_address(node_str, address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Show address cancelled")); + layoutHome(); + return; + } + } -void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) -{ - RESP_INIT(EthereumAddress); - - CHECK_INITIALIZED - - CHECK_PIN - - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - resp->address.size = 20; - - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { - memzero(node, sizeof(*node)); - return; - } - - const CoinType *coin = NULL; - bool rskip60 = false; - uint32_t chain_id = 0; - - if (msg->address_n_count == 5) { - coin = coinBySlip44(msg->address_n[1]); - uint32_t slip44 = msg->address_n[1] & 0x7fffffff; - // constants from trezor-common/defs/ethereum/networks.json - switch (slip44) { - case 137: rskip60 = true; chain_id = 30; break; - case 37310: rskip60 = true; chain_id = 31; break; - } - } - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, chain_id); - - resp->has_address_str = true; - strlcpy(resp->address_str, address, sizeof(resp->address_str)); - - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!(coin && isEthereumLike(coin->coin_name) && - bip32_node_to_string(node_str, sizeof(node_str), coin, - msg->address_n, - msg->address_n_count, - /*whole_account=*/false, - /*show_addridx=*/false)) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - - if (!confirm_ethereum_address(node_str, address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Show address cancelled")); - layoutHome(); - return; - } - } - - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_EthereumAddress, resp); - layoutHome(); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_EthereumAddress, resp); + layoutHome(); } -void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) -{ - RESP_INIT(EthereumMessageSignature); +void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) { + RESP_INIT(EthereumMessageSignature); - CHECK_INITIALIZED + CHECK_INITIALIZED - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Sign Message"), - "%s", msg->message.bytes)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Sign Message"), + "%s", msg->message.bytes)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - ethereum_message_sign(msg, node, resp); - memzero(node, sizeof(*node)); - layoutHome(); + ethereum_message_sign(msg, node, resp); + memzero(node, sizeof(*node)); + layoutHome(); } -void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - - if (ethereum_message_verify(msg) != 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Invalid signature")); - return; - } - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); - if (!confirm_address(_("Confirm Signer"), address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - if (!confirm(ButtonRequestType_ButtonRequest_Other, _("Message Verified"), "%s", - msg->message.bytes)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); - - layoutHome(); +void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) { + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + + if (ethereum_message_verify(msg) != 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Invalid signature")); + return; + } + + char address[43] = {'0', 'x'}; + ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); + if (!confirm_address(_("Confirm Signer"), address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + if (!confirm(ButtonRequestType_ButtonRequest_Other, _("Message Verified"), + "%s", msg->message.bytes)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + + layoutHome(); } diff --git a/lib/firmware/fsm_msg_nano.h b/lib/firmware/fsm_msg_nano.h index 922fae0f0..67a0d82d8 100644 --- a/lib/firmware/fsm_msg_nano.h +++ b/lib/firmware/fsm_msg_nano.h @@ -1,157 +1,160 @@ #include "keepkey/firmware/nano.h" -void fsm_msgNanoGetAddress(NanoGetAddress *msg) -{ - RESP_INIT(NanoAddress); - - CHECK_INITIALIZED - - CHECK_PIN - - const char *coin_name = msg->has_coin_name ? msg->coin_name : "Nano"; - const CoinType *coin = fsm_getCoin(true, coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); - - char address[MAX_NANO_ADDR_SIZE]; - if (!nano_get_address( - &node->public_key[1], - coin->nanoaddr_prefix, strlen(coin->nanoaddr_prefix), - address, sizeof(address))) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); - layoutHome(); - return; - } - - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!nano_bip32_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - - bool mismatch = nano_path_mismatched(coin, msg->address_n, msg->address_n_count); - - if (mismatch) { - if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", "Wrong address path for selected coin. Continue at your own risk!")) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if(!confirm_nano_address(node_str, address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); - layoutHome(); - return; - } - } +void fsm_msgNanoGetAddress(NanoGetAddress *msg) { + RESP_INIT(NanoAddress); - resp->has_address = true; - strlcpy(resp->address, address, sizeof(resp->address)); - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_NanoAddress, resp); - layoutHome(); -} + CHECK_INITIALIZED -void fsm_msgNanoSignTx(NanoSignTx *msg) -{ - CHECK_INITIALIZED + CHECK_PIN - CHECK_PIN + const char *coin_name = msg->has_coin_name ? msg->coin_name : "Nano"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); - const char *coin_name = msg->has_coin_name ? msg->coin_name : "Nano"; - const CoinType *coin = fsm_getCoin(true, coin_name); - if (!coin) return; - - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, - msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); - - if (!nano_signingInit(msg, node, coin)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Block data invalid")); - layoutHome(); - return; + char address[MAX_NANO_ADDR_SIZE]; + if (!nano_get_address(&node->public_key[1], coin->nanoaddr_prefix, + strlen(coin->nanoaddr_prefix), address, + sizeof(address))) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!nano_bip32_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); } - memzero(node, sizeof(*node)); + bool mismatch = + nano_path_mismatched(coin, msg->address_n, msg->address_n_count); - if (!nano_parentHash(msg)) { - nano_signingAbort(); + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", + "Wrong address path for selected coin. Continue at your own " + "risk!")) { memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Parent block data invalid")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; + } } - HDNode *recip = NULL; - if (msg->link_recipient_n_count > 0) { - recip = fsm_getDerivedNode(coin->curve_name, - msg->link_recipient_n, - msg->link_recipient_n_count, - NULL); - if (!recip) { - nano_signingAbort(); - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Could not derive node")); - layoutHome(); - return; - } - hdnode_fill_public_key(recip); + if (!confirm_nano_address(node_str, address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Show address cancelled"); + layoutHome(); + return; } + } - if (!nano_currentHash(msg, recip)) { - nano_signingAbort(); - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Current block data invalid")); - layoutHome(); - return; - } + resp->has_address = true; + strlcpy(resp->address, address, sizeof(resp->address)); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_NanoAddress, resp); + layoutHome(); +} - if (recip) { - memzero(recip, sizeof(*recip)); - recip = NULL; - } +void fsm_msgNanoSignTx(NanoSignTx *msg) { + CHECK_INITIALIZED - if (!nano_sanityCheck(msg)) { - nano_signingAbort(); - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Failed sanity check")); - layoutHome(); - return; - } + CHECK_PIN - RESP_INIT(NanoSignedTx); + const char *coin_name = msg->has_coin_name ? msg->coin_name : "Nano"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) return; - memset(resp->signature.bytes, 0, sizeof(resp->signature.bytes)); - _Static_assert(sizeof(resp->signature.bytes) >= 64, "Signature field not large enough"); - _Static_assert(sizeof(resp->block_hash.bytes) >= 32, "Block hash field not large enough"); + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); - // Sign hash and return the signature - node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) { - nano_signingAbort(); - fsm_sendFailure(FailureType_Failure_Other, _("Could not derive node")); - layoutHome(); - return; - } + if (!nano_signingInit(msg, node, coin)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Block data invalid")); + layoutHome(); + return; + } - if (!nano_signTx(msg, node, resp)) { - memzero(node, sizeof(*node)); - return; + memzero(node, sizeof(*node)); + + if (!nano_parentHash(msg)) { + nano_signingAbort(); + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Parent block data invalid")); + layoutHome(); + return; + } + + HDNode *recip = NULL; + if (msg->link_recipient_n_count > 0) { + recip = fsm_getDerivedNode(coin->curve_name, msg->link_recipient_n, + msg->link_recipient_n_count, NULL); + if (!recip) { + nano_signingAbort(); + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Could not derive node")); + layoutHome(); + return; } + hdnode_fill_public_key(recip); + } + if (!nano_currentHash(msg, recip)) { + nano_signingAbort(); memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Current block data invalid")); + layoutHome(); + return; + } + + if (recip) { + memzero(recip, sizeof(*recip)); + recip = NULL; + } - msg_write(MessageType_MessageType_NanoSignedTx, resp); + if (!nano_sanityCheck(msg)) { + nano_signingAbort(); + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Failed sanity check")); layoutHome(); + return; + } + + RESP_INIT(NanoSignedTx); + + memset(resp->signature.bytes, 0, sizeof(resp->signature.bytes)); + _Static_assert(sizeof(resp->signature.bytes) >= 64, + "Signature field not large enough"); + _Static_assert(sizeof(resp->block_hash.bytes) >= 32, + "Block hash field not large enough"); + + // Sign hash and return the signature + node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) { + nano_signingAbort(); + fsm_sendFailure(FailureType_Failure_Other, _("Could not derive node")); + layoutHome(); + return; + } + + if (!nano_signTx(msg, node, resp)) { + memzero(node, sizeof(*node)); + return; + } + + memzero(node, sizeof(*node)); + + msg_write(MessageType_MessageType_NanoSignedTx, resp); + layoutHome(); } diff --git a/lib/firmware/fsm_msg_ripple.h b/lib/firmware/fsm_msg_ripple.h index 2535a268b..109b22e6a 100644 --- a/lib/firmware/fsm_msg_ripple.h +++ b/lib/firmware/fsm_msg_ripple.h @@ -17,110 +17,109 @@ * along with this library. If not, see . */ -void fsm_msgRippleGetAddress(const RippleGetAddress *msg) -{ - RESP_INIT(RippleAddress); +void fsm_msgRippleGetAddress(const RippleGetAddress *msg) { + RESP_INIT(RippleAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); - const CoinType *coin = fsm_getCoin(true, "Ripple"); + const CoinType *coin = fsm_getCoin(true, "Ripple"); - if (!ripple_getAddress(node->public_key, resp->address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_Other, _("Address derivation failed")); - layoutHome(); - return; + if (!ripple_getAddress(node->public_key, resp->address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_Other, _("Address derivation failed")); + layoutHome(); + return; + } + + resp->has_address = true; + + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!(bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/false)) && + !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, + msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); } - resp->has_address = true; - - if (msg->has_show_display && msg->show_display) { - char node_str[NODE_STRING_LENGTH]; - if (!(bip32_node_to_string(node_str, sizeof(node_str), coin, - msg->address_n, - msg->address_n_count, - /*whole_account=*/false, - /*show_addridx=*/false)) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } - - if (!confirm_ethereum_address(node_str, resp->address)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Show address cancelled")); - layoutHome(); - return; - } + if (!confirm_ethereum_address(node_str, resp->address)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Show address cancelled")); + layoutHome(); + return; } + } - memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_RippleAddress, resp); - layoutHome(); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_RippleAddress, resp); + layoutHome(); } -void fsm_msgRippleSignTx(RippleSignTx *msg) -{ - RESP_INIT(RippleSignedTx); - - CHECK_INITIALIZED +void fsm_msgRippleSignTx(RippleSignTx *msg) { + RESP_INIT(RippleSignedTx); - CHECK_PIN + CHECK_INITIALIZED - bool needs_confirm = true; + CHECK_PIN - // TODO: handle trades and transfers + bool needs_confirm = true; - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, - msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); + // TODO: handle trades and transfers - if (!msg->has_fee || msg->fee < RIPPLE_MIN_FEE || msg->fee > RIPPLE_MAX_FEE) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_SyntaxError, - _("Fee must be between 10 and 1,000,000 drops")); - return; - } - - char amount_string[20 + 4 + 1]; - ripple_formatAmount(amount_string, sizeof(amount_string), msg->payment.amount); - - char fee_string[20 + 4 + 1]; - ripple_formatAmount(fee_string, sizeof(fee_string), msg->fee); - - if (needs_confirm) { - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Send", msg->payment.has_destination_tag - ? "Send %s to %s, with destination tag %" PRIu32 "?" - : "Send %s to %s?", - amount_string, - msg->payment.destination, - msg->payment.destination_tag)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; - } - } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, - "Transaction", "Really send %s, with a transaction fee of %s?", - amount_string, fee_string)) { - memzero(node, sizeof(*node)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; + if (!msg->has_fee || msg->fee < RIPPLE_MIN_FEE || msg->fee > RIPPLE_MAX_FEE) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Fee must be between 10 and 1,000,000 drops")); + return; + } + + char amount_string[20 + 4 + 1]; + ripple_formatAmount(amount_string, sizeof(amount_string), + msg->payment.amount); + + char fee_string[20 + 4 + 1]; + ripple_formatAmount(fee_string, sizeof(fee_string), msg->fee); + + if (needs_confirm) { + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, "Send", + msg->payment.has_destination_tag + ? "Send %s to %s, with destination tag %" PRIu32 "?" + : "Send %s to %s?", + amount_string, msg->payment.destination, + msg->payment.destination_tag)) { + memzero(node, sizeof(*node)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); + layoutHome(); + return; } + } - ripple_signTx(node, msg, resp); + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transaction", + "Really send %s, with a transaction fee of %s?", amount_string, + fee_string)) { memzero(node, sizeof(*node)); - msg_write(MessageType_MessageType_RippleSignedTx, resp); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); layoutHome(); + return; + } + + ripple_signTx(node, msg, resp); + memzero(node, sizeof(*node)); + msg_write(MessageType_MessageType_RippleSignedTx, resp); + layoutHome(); } diff --git a/lib/firmware/home_sm.c b/lib/firmware/home_sm.c index 98964ac31..107b1105a 100644 --- a/lib/firmware/home_sm.c +++ b/lib/firmware/home_sm.c @@ -30,16 +30,16 @@ static HomeState home_state = AT_HOME; static uint32_t idle_time = 0; -static void layoutLockedState(void) -{ - const Font *font = get_body_font(); - const char *state = (!storage_hasPin() || session_isPinCached()) ? "\x02" : "\x03"; - DrawableParams sp; - sp.x = 2; - sp.y = KEEPKEY_DISPLAY_HEIGHT - 1 * font_height(font) - 6; - sp.color = 0x22; - draw_string(layout_get_canvas(), font, state, &sp, KEEPKEY_DISPLAY_WIDTH, - font_height(font)); +static void layoutLockedState(void) { + const Font *font = get_body_font(); + const char *state = + (!storage_hasPin() || session_isPinCached()) ? "\x02" : "\x03"; + DrawableParams sp; + sp.x = 2; + sp.y = KEEPKEY_DISPLAY_HEIGHT - 1 * font_height(font) - 6; + sp.color = 0x22; + draw_string(layout_get_canvas(), font, state, &sp, KEEPKEY_DISPLAY_WIDTH, + font_height(font)); } /* @@ -50,22 +50,20 @@ static void layoutLockedState(void) * OUTPUT * none */ -void layoutHome(void) -{ - switch(home_state) - { - case AWAY_FROM_HOME: - layoutHomeForced(); - break; - - case SCREENSAVER: - case AT_HOME: - default: - /* no action required */ - break; - } - - layoutLockedState(); +void layoutHome(void) { + switch (home_state) { + case AWAY_FROM_HOME: + layoutHomeForced(); + break; + + case SCREENSAVER: + case AT_HOME: + default: + /* no action required */ + break; + } + + layoutLockedState(); } /* @@ -76,12 +74,11 @@ void layoutHome(void) * OUTPUT * none */ -void layoutHomeForced(void) -{ - layout_home(); - layoutLockedState(); - reset_idle_time(); - home_state = AT_HOME; +void layoutHomeForced(void) { + layout_home(); + layoutLockedState(); + reset_idle_time(); + home_state = AT_HOME; } /* @@ -92,25 +89,23 @@ void layoutHomeForced(void) * OUTPUT * none */ -void leave_home(void) -{ - switch(home_state) - { - case AT_HOME: - layout_home_reversed(); - reset_idle_time(); - home_state = AWAY_FROM_HOME; - break; - - case SCREENSAVER: - home_state = AWAY_FROM_HOME; - break; - - case AWAY_FROM_HOME: - default: - /* no action requires */ - break; - } +void leave_home(void) { + switch (home_state) { + case AT_HOME: + layout_home_reversed(); + reset_idle_time(); + home_state = AWAY_FROM_HOME; + break; + + case SCREENSAVER: + home_state = AWAY_FROM_HOME; + break; + + case AWAY_FROM_HOME: + default: + /* no action requires */ + break; + } } /* @@ -121,33 +116,31 @@ void leave_home(void) * OUTPUT * none */ -void toggle_screensaver(void) -{ - switch(home_state) - { - case AT_HOME: - if (idle_time >= storage_getAutoLockDelayMs()) { - session_clear(/*clear_pin=*/true); - layout_screensaver(); - home_state = SCREENSAVER; - } - - break; - - case SCREENSAVER: - if (idle_time < storage_getAutoLockDelayMs()) { - layout_home(); - layoutLockedState(); - home_state = AT_HOME; - } - - break; - - case AWAY_FROM_HOME: - default: - /* no action requires */ - break; - } +void toggle_screensaver(void) { + switch (home_state) { + case AT_HOME: + if (idle_time >= storage_getAutoLockDelayMs()) { + session_clear(/*clear_pin=*/true); + layout_screensaver(); + home_state = SCREENSAVER; + } + + break; + + case SCREENSAVER: + if (idle_time < storage_getAutoLockDelayMs()) { + layout_home(); + layoutLockedState(); + home_state = AT_HOME; + } + + break; + + case AWAY_FROM_HOME: + default: + /* no action requires */ + break; + } } /* @@ -158,10 +151,7 @@ void toggle_screensaver(void) * OUTPUT * none */ -void increment_idle_time(uint32_t increment_ms) -{ - idle_time += increment_ms; -} +void increment_idle_time(uint32_t increment_ms) { idle_time += increment_ms; } /* * reset_idle_time() - Resets idle time @@ -171,7 +161,4 @@ void increment_idle_time(uint32_t increment_ms) * OUTPUT * none */ -void reset_idle_time(void) -{ - idle_time = 0; -} +void reset_idle_time(void) { idle_time = 0; } diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index 289e8f1d0..8fe11fecb 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -4,6 +4,7 @@ MSG_IN(MessageType_MessageType_GetCoinTable, GetCoinTable, fsm_msgGetCoinTable) MSG_IN(MessageType_MessageType_Ping, Ping, fsm_msgPing) MSG_IN(MessageType_MessageType_ChangePin, ChangePin, fsm_msgChangePin) + MSG_IN(MessageType_MessageType_ChangeWipeCode, ChangeWipeCode, fsm_msgChangeWipeCode) MSG_IN(MessageType_MessageType_WipeDevice, WipeDevice, fsm_msgWipeDevice) MSG_IN(MessageType_MessageType_FirmwareErase, FirmwareErase, fsm_msgFirmwareErase) MSG_IN(MessageType_MessageType_FirmwareUpload, FirmwareUpload, fsm_msgFirmwareUpload) diff --git a/lib/firmware/nano.c b/lib/firmware/nano.c index a7b9b82f5..9d18dafbd 100644 --- a/lib/firmware/nano.c +++ b/lib/firmware/nano.c @@ -12,7 +12,7 @@ #include #include #ifdef EMULATOR -# include +#include #endif static ed25519_public_key account_pk; @@ -30,346 +30,342 @@ static char recipient_address[MAX_NANO_ADDR_SIZE]; static const CoinType *coin = NULL; static uint8_t const NANO_BLOCK_HASH_PREAMBLE[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, }; -bool nano_path_mismatched(const CoinType *_coin, - const uint32_t *address_n, - const uint32_t address_n_count) -{ - // m/44' : BIP44-like path - // m / purpose' / bip44_account_path' / account' - bool mismatch = false; - mismatch |= address_n_count != 3; - mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); - mismatch |= address_n_count > 1 && (address_n[1] != _coin->bip44_account_path); - mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; - return mismatch; +bool nano_path_mismatched(const CoinType *_coin, const uint32_t *address_n, + const uint32_t address_n_count) { + // m/44' : BIP44-like path + // m / purpose' / bip44_account_path' / account' + bool mismatch = false; + mismatch |= address_n_count != 3; + mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); + mismatch |= + address_n_count > 1 && (address_n[1] != _coin->bip44_account_path); + mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; + return mismatch; } -bool nano_bip32_to_string(char *node_str, size_t len, - const CoinType *_coin, +bool nano_bip32_to_string(char *node_str, size_t len, const CoinType *_coin, const uint32_t *address_n, - const size_t address_n_count) -{ - if (address_n_count != 3) - return false; + const size_t address_n_count) { + if (address_n_count != 3) return false; - if (nano_path_mismatched(_coin, address_n, address_n_count)) - return false; + if (nano_path_mismatched(_coin, address_n, address_n_count)) return false; - snprintf(node_str, len, "%s Account #%" PRIu32, _coin->coin_name, - address_n[2] & 0x7ffffff); - return true; + snprintf(node_str, len, "%s Account #%" PRIu32, _coin->coin_name, + address_n[2] & 0x7ffffff); + return true; } void nano_hash_block_data(const uint8_t _account_pk[32], const uint8_t _parent_hash[32], const uint8_t _link[32], const uint8_t _representative_pk[32], - const uint8_t _balance[16], - uint8_t _out_hash[32]) -{ - blake2b_state ctx; - blake2b_Init(&ctx, 32); - - blake2b_Update(&ctx, NANO_BLOCK_HASH_PREAMBLE, sizeof(NANO_BLOCK_HASH_PREAMBLE)); - blake2b_Update(&ctx, _account_pk, 32); - blake2b_Update(&ctx, _parent_hash, 32); - blake2b_Update(&ctx, _representative_pk, 32); - blake2b_Update(&ctx, _balance, 16); - blake2b_Update(&ctx, _link, 32); - - blake2b_Final(&ctx, _out_hash, 32); + const uint8_t _balance[16], uint8_t _out_hash[32]) { + blake2b_state ctx; + blake2b_Init(&ctx, 32); + + blake2b_Update(&ctx, NANO_BLOCK_HASH_PREAMBLE, + sizeof(NANO_BLOCK_HASH_PREAMBLE)); + blake2b_Update(&ctx, _account_pk, 32); + blake2b_Update(&ctx, _parent_hash, 32); + blake2b_Update(&ctx, _representative_pk, 32); + blake2b_Update(&ctx, _balance, 16); + blake2b_Update(&ctx, _link, 32); + + blake2b_Final(&ctx, _out_hash, 32); } const char *nano_getKnownRepName(const char *addr) { - static const struct { - const char *name; - const char *addr; - } reps[] = { - { "@meltingice ", "xrb_1x7biz69cem95oo7gxkrw6kzhfywq4x5dupw4z1bdzkb74dk9kpxwzjbdhhs" }, - { "@nanovault-rep ", "xrb_3rw4un6ys57hrb39sy1qx8qy5wukst1iiponztrz9qiz6qqa55kxzx4491or" }, - { "@nanowallet_rep1 ", "xrb_3pczxuorp48td8645bs3m6c3xotxd3idskrenmi65rbrga5zmkemzhwkaznh" }, - { "Binance Rep ", "xrb_3jwrszth46rk1mu7rmb4rhm54us8yg1gw3ipodftqtikf5yqdyr7471nsg1k" }, - { "BrainBlocks Rep ", "xrb_1brainb3zz81wmhxndsbrjb94hx3fhr1fyydmg6iresyk76f3k7y7jiazoji" }, - { "Genesis ", "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3" }, - { "KuCoin 1 ", "xrb_1niabkx3gbxit5j5yyqcpas71dkffggbr6zpd3heui8rpoocm5xqbdwq44oh" }, - { "NanoWallet Bot Rep ", "xrb_16k5pimotz9zehjk795wa4qcx54mtusk8hc5mdsjgy57gnhbj3hj6zaib4ic" }, - { "Nanode Rep ", "xrb_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg" }, - { "OKEx Rep ", "xrb_1tig1rio7iskejqgy6ap75rima35f9mexjazdqqquthmyu48118jiewny7zo" }, - { "Official Rep 1 ", "xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4" }, - { "Official Rep 2 ", "xrb_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou" }, - { "Official Rep 3 ", "xrb_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p" }, - { "Official Rep 4 ", "xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m" }, - { "Official Rep 5 ", "xrb_3hd4ezdgsp15iemx7h81in7xz5tpxi43b6b41zn3qmwiuypankocw3awes5k" }, - { "Official Rep 6 ", "xrb_1awsn43we17c1oshdru4azeqjz9wii41dy8npubm4rg11so7dx3jtqgoeahy" }, - { "Official Rep 7 ", "xrb_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs" }, - { "Official Rep 8 ", "xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1" }, - }; - - for (size_t i = 0; i < sizeof(reps)/sizeof(reps[0]); i++) { - if (strcmp(addr, reps[i].addr) == 0) - return reps[i].name; - } - - return NULL; + static const struct { + const char *name; + const char *addr; + } reps[] = { + {"@meltingice ", + "xrb_1x7biz69cem95oo7gxkrw6kzhfywq4x5dupw4z1bdzkb74dk9kpxwzjbdhhs"}, + {"@nanovault-rep ", + "xrb_3rw4un6ys57hrb39sy1qx8qy5wukst1iiponztrz9qiz6qqa55kxzx4491or"}, + {"@nanowallet_rep1 ", + "xrb_3pczxuorp48td8645bs3m6c3xotxd3idskrenmi65rbrga5zmkemzhwkaznh"}, + {"Binance Rep ", + "xrb_3jwrszth46rk1mu7rmb4rhm54us8yg1gw3ipodftqtikf5yqdyr7471nsg1k"}, + {"BrainBlocks Rep ", + "xrb_1brainb3zz81wmhxndsbrjb94hx3fhr1fyydmg6iresyk76f3k7y7jiazoji"}, + {"Genesis ", + "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3"}, + {"KuCoin 1 ", + "xrb_1niabkx3gbxit5j5yyqcpas71dkffggbr6zpd3heui8rpoocm5xqbdwq44oh"}, + {"NanoWallet Bot Rep ", + "xrb_16k5pimotz9zehjk795wa4qcx54mtusk8hc5mdsjgy57gnhbj3hj6zaib4ic"}, + {"Nanode Rep ", + "xrb_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg"}, + {"OKEx Rep ", + "xrb_1tig1rio7iskejqgy6ap75rima35f9mexjazdqqquthmyu48118jiewny7zo"}, + {"Official Rep 1 ", + "xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4"}, + {"Official Rep 2 ", + "xrb_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou"}, + {"Official Rep 3 ", + "xrb_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p"}, + {"Official Rep 4 ", + "xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m"}, + {"Official Rep 5 ", + "xrb_3hd4ezdgsp15iemx7h81in7xz5tpxi43b6b41zn3qmwiuypankocw3awes5k"}, + {"Official Rep 6 ", + "xrb_1awsn43we17c1oshdru4azeqjz9wii41dy8npubm4rg11so7dx3jtqgoeahy"}, + {"Official Rep 7 ", + "xrb_1anrzcuwe64rwxzcco8dkhpyxpi8kd7zsjc1oeimpc3ppca4mrjtwnqposrs"}, + {"Official Rep 8 ", + "xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1"}, + }; + + for (size_t i = 0; i < sizeof(reps) / sizeof(reps[0]); i++) { + if (strcmp(addr, reps[i].addr) == 0) return reps[i].name; + } + + return NULL; } void nano_truncateAddress(const CoinType *_coin, char *str) { - const size_t prefix_len = strlen(_coin->nanoaddr_prefix); - const size_t str_len = strlen(str); + const size_t prefix_len = strlen(_coin->nanoaddr_prefix); + const size_t str_len = strlen(str); - if (str_len < prefix_len + 12) - return; + if (str_len < prefix_len + 12) return; - memset(&str[prefix_len + 5], '.', 2); - memmove(&str[prefix_len + 7], &str[str_len - 5], 5); - str[prefix_len+12] = '\0'; + memset(&str[prefix_len + 5], '.', 2); + memmove(&str[prefix_len + 7], &str[str_len - 5], 5); + str[prefix_len + 12] = '\0'; } -void nano_signingAbort(void) -{ - bn_zero(&parent_balance); - bn_zero(&balance); - bn_zero(&balance_delta); +void nano_signingAbort(void) { + bn_zero(&parent_balance); + bn_zero(&balance); + bn_zero(&balance_delta); - memset(block_hash, 0, sizeof(block_hash)); - memset(parent_hash, 0, sizeof(parent_hash)); - memset(link, 0, sizeof(link)); - memset(representative_pk, 0, sizeof(representative_pk)); - memset(balance_be, 0, sizeof(balance_be)); + memset(block_hash, 0, sizeof(block_hash)); + memset(parent_hash, 0, sizeof(parent_hash)); + memset(link, 0, sizeof(link)); + memset(representative_pk, 0, sizeof(representative_pk)); + memset(balance_be, 0, sizeof(balance_be)); - memset(recipient_address, 0, sizeof(recipient_address)); - memset(representative_address, 0, sizeof(representative_address)); + memset(recipient_address, 0, sizeof(recipient_address)); + memset(representative_address, 0, sizeof(representative_address)); - is_send = true; + is_send = true; } -bool nano_signingInit(const NanoSignTx *msg, const HDNode *node, const CoinType *_coin) -{ - nano_signingAbort(); - - memcpy(account_pk, &node->public_key[1], sizeof(account_pk)); - coin = _coin; - - // Validate input data - bool invalid = false; - if (msg->has_parent_block) { - invalid |= msg->parent_block.has_parent_hash - && msg->parent_block.parent_hash.size != 32; - invalid |= msg->parent_block.has_link - && msg->parent_block.link.size != 32; - invalid |= !msg->parent_block.has_representative; - invalid |= !msg->parent_block.has_balance - || msg->parent_block.balance.size != 16; - } - if (!msg->has_parent_block) { - invalid |= !msg->has_link_hash; // first block must be a receive block - } - invalid |= (int)msg->has_link_hash + (int)msg->has_link_recipient + (int)(msg->link_recipient_n_count != 0) > 1; - invalid |= msg->has_link_hash && msg->link_hash.size != 32; - invalid |= !msg->has_representative; - invalid |= !msg->has_balance || msg->balance.size != 16; - - return !invalid; +bool nano_signingInit(const NanoSignTx *msg, const HDNode *node, + const CoinType *_coin) { + nano_signingAbort(); + + memcpy(account_pk, &node->public_key[1], sizeof(account_pk)); + coin = _coin; + + // Validate input data + bool invalid = false; + if (msg->has_parent_block) { + invalid |= msg->parent_block.has_parent_hash && + msg->parent_block.parent_hash.size != 32; + invalid |= msg->parent_block.has_link && msg->parent_block.link.size != 32; + invalid |= !msg->parent_block.has_representative; + invalid |= + !msg->parent_block.has_balance || msg->parent_block.balance.size != 16; + } + if (!msg->has_parent_block) { + invalid |= !msg->has_link_hash; // first block must be a receive block + } + invalid |= (int)msg->has_link_hash + (int)msg->has_link_recipient + + (int)(msg->link_recipient_n_count != 0) > + 1; + invalid |= msg->has_link_hash && msg->link_hash.size != 32; + invalid |= !msg->has_representative; + invalid |= !msg->has_balance || msg->balance.size != 16; + + return !invalid; } -bool nano_parentHash(const NanoSignTx *msg) -{ - if (!msg->has_parent_block) - return true; +bool nano_parentHash(const NanoSignTx *msg) { + if (!msg->has_parent_block) return true; - if (msg->parent_block.has_parent_hash) { - memcpy(parent_hash, msg->parent_block.parent_hash.bytes, sizeof(parent_hash)); - } - memcpy(link, msg->parent_block.link.bytes, sizeof(link)); + if (msg->parent_block.has_parent_hash) { + memcpy(parent_hash, msg->parent_block.parent_hash.bytes, + sizeof(parent_hash)); + } + memcpy(link, msg->parent_block.link.bytes, sizeof(link)); - if (!nano_validate_address(coin->nanoaddr_prefix, - strlen(coin->nanoaddr_prefix), - msg->parent_block.representative, - strlen(msg->parent_block.representative), - representative_pk)) - return false; + if (!nano_validate_address( + coin->nanoaddr_prefix, strlen(coin->nanoaddr_prefix), + msg->parent_block.representative, + strlen(msg->parent_block.representative), representative_pk)) + return false; - memcpy(balance_be, msg->parent_block.balance.bytes, sizeof(balance_be)); - bn_from_bytes(balance_be, sizeof(balance_be), &parent_balance); + memcpy(balance_be, msg->parent_block.balance.bytes, sizeof(balance_be)); + bn_from_bytes(balance_be, sizeof(balance_be), &parent_balance); - nano_hash_block_data(account_pk, parent_hash, link, - representative_pk, balance_be, - block_hash); + nano_hash_block_data(account_pk, parent_hash, link, representative_pk, + balance_be, block_hash); - memcpy(parent_hash, block_hash, sizeof(parent_hash)); - memset(block_hash, 0, sizeof(parent_hash)); - memset(link, 0, sizeof(link)); - memset(representative_pk, 0, sizeof(representative_pk)); - memset(balance_be, 0, sizeof(balance_be)); + memcpy(parent_hash, block_hash, sizeof(parent_hash)); + memset(block_hash, 0, sizeof(parent_hash)); + memset(link, 0, sizeof(link)); + memset(representative_pk, 0, sizeof(representative_pk)); + memset(balance_be, 0, sizeof(balance_be)); - return true; + return true; } -bool nano_currentHash(const NanoSignTx *msg, const HDNode *recip) -{ - if (msg->has_link_hash) { - memcpy(link, msg->link_hash.bytes, sizeof(link)); - } else if (msg->link_recipient_n_count > 0) { - if (!recip) - return false; - memcpy(link, &recip->public_key[1], sizeof(link)); - } else if (msg->has_link_recipient) { - memcpy(link, msg->link_recipient, sizeof(link)); - if (!nano_validate_address(coin->nanoaddr_prefix, - strlen(coin->nanoaddr_prefix), - msg->link_recipient, - strlen(msg->link_recipient), - link)) - return false; - } - - if (!nano_validate_address(coin->nanoaddr_prefix, - strlen(coin->nanoaddr_prefix), - msg->representative, - strlen(msg->representative), - representative_pk)) - return false; - - memcpy(balance_be, msg->balance.bytes, sizeof(balance_be)); - bn_from_bytes(balance_be, sizeof(balance_be), &balance); - - nano_hash_block_data(account_pk, parent_hash, link, - representative_pk, balance_be, - block_hash); - - return true; +bool nano_currentHash(const NanoSignTx *msg, const HDNode *recip) { + if (msg->has_link_hash) { + memcpy(link, msg->link_hash.bytes, sizeof(link)); + } else if (msg->link_recipient_n_count > 0) { + if (!recip) return false; + memcpy(link, &recip->public_key[1], sizeof(link)); + } else if (msg->has_link_recipient) { + memcpy(link, msg->link_recipient, sizeof(link)); + if (!nano_validate_address( + coin->nanoaddr_prefix, strlen(coin->nanoaddr_prefix), + msg->link_recipient, strlen(msg->link_recipient), link)) + return false; + } + + if (!nano_validate_address(coin->nanoaddr_prefix, + strlen(coin->nanoaddr_prefix), msg->representative, + strlen(msg->representative), representative_pk)) + return false; + + memcpy(balance_be, msg->balance.bytes, sizeof(balance_be)); + bn_from_bytes(balance_be, sizeof(balance_be), &balance); + + nano_hash_block_data(account_pk, parent_hash, link, representative_pk, + balance_be, block_hash); + + return true; } /// Some additional sanity checks now that balance values are known -bool nano_sanityCheck(const NanoSignTx *msg) -{ - memset(recipient_address, 0, sizeof(recipient_address)); - - strlcpy(representative_address, msg->representative, sizeof(representative_address)); - if (msg->has_parent_block) { - if (!strncmp(representative_address, - msg->parent_block.representative, - sizeof(representative_address))) { - // Representative hasn't changed, zero it out - memset(representative_address, 0, sizeof(representative_address)); - } +bool nano_sanityCheck(const NanoSignTx *msg) { + memset(recipient_address, 0, sizeof(recipient_address)); + + strlcpy(representative_address, msg->representative, + sizeof(representative_address)); + if (msg->has_parent_block) { + if (!strncmp(representative_address, msg->parent_block.representative, + sizeof(representative_address))) { + // Representative hasn't changed, zero it out + memset(representative_address, 0, sizeof(representative_address)); } + } - if (bn_is_less(&balance, &parent_balance)) { - is_send = true; - bn_subtract(&parent_balance, &balance, &balance_delta); - } else { - is_send = false; - bn_subtract(&balance, &parent_balance, &balance_delta); - } - - bool invalid = false; - if (bn_is_zero(&balance_delta)) { - // Balance can only remain unchanged when the account exists already - invalid |= !msg->has_parent_block; - } else if (is_send) { - // For sends make fill out the link_recipient (or generate it from link bytes) - if (msg->has_link_recipient) { - strlcpy(recipient_address, msg->link_recipient, sizeof(recipient_address)); - } else { - nano_get_address(link, coin->nanoaddr_prefix, - strlen(coin->nanoaddr_prefix), - recipient_address, sizeof(recipient_address)); - } + if (bn_is_less(&balance, &parent_balance)) { + is_send = true; + bn_subtract(&parent_balance, &balance, &balance_delta); + } else { + is_send = false; + bn_subtract(&balance, &parent_balance, &balance_delta); + } + + bool invalid = false; + if (bn_is_zero(&balance_delta)) { + // Balance can only remain unchanged when the account exists already + invalid |= !msg->has_parent_block; + } else if (is_send) { + // For sends make fill out the link_recipient (or generate it from link + // bytes) + if (msg->has_link_recipient) { + strlcpy(recipient_address, msg->link_recipient, + sizeof(recipient_address)); } else { - // For receives make sure that the link_hash was specified and that it's - invalid |= !msg->has_link_hash; - uint8_t link_empty[sizeof(link)]; - memset(link_empty, 0, sizeof(link_empty)); - invalid |= !memcmp(link_empty, link, sizeof(link)); + nano_get_address(link, coin->nanoaddr_prefix, + strlen(coin->nanoaddr_prefix), recipient_address, + sizeof(recipient_address)); } - - return !invalid; + } else { + // For receives make sure that the link_hash was specified and that it's + invalid |= !msg->has_link_hash; + uint8_t link_empty[sizeof(link)]; + memset(link_empty, 0, sizeof(link_empty)); + invalid |= !memcmp(link_empty, link, sizeof(link)); + } + + return !invalid; } -bool nano_signTx(const NanoSignTx *msg, HDNode *node, NanoSignedTx *resp) -{ - // Determine what type of prompt to display - bool needs_confirm = true; - bool is_transfer = false; +bool nano_signTx(const NanoSignTx *msg, HDNode *node, NanoSignedTx *resp) { + // Determine what type of prompt to display + bool needs_confirm = true; + bool is_transfer = false; + if (strlen(representative_address) > 0) { + // always confirm representative change + } else if (!is_send) { + // don't bother confirming pure receives + needs_confirm = false; + } else if (msg->link_recipient_n_count > 0 && + !nano_path_mismatched(coin, msg->link_recipient_n, + msg->link_recipient_n_count)) { + is_transfer = true; + } + + if (needs_confirm) { if (strlen(representative_address) > 0) { - // always confirm representative change - } else if (!is_send) { - // don't bother confirming pure receives - needs_confirm = false; - } else if (msg->link_recipient_n_count > 0 && - !nano_path_mismatched(coin, msg->link_recipient_n, - msg->link_recipient_n_count)) { - is_transfer = true; + const char *rep_name = nano_getKnownRepName(representative_address); + if (rep_name) nano_truncateAddress(coin, representative_address); + if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, + "Representative", "Set account representative to\n%s%s?", + rep_name ? rep_name : "", representative_address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled"); + layoutHome(); + return false; + } } - if (needs_confirm) { - if (strlen(representative_address) > 0) { - const char *rep_name = nano_getKnownRepName(representative_address); - if (rep_name) - nano_truncateAddress(coin, representative_address); - if (!confirm(ButtonRequestType_ButtonRequest_ConfirmOutput, - "Representative", "Set account representative to\n%s%s?", - rep_name ? rep_name : "", representative_address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return false; - } - } - - char amount_string[60]; - memset(amount_string, 0, sizeof(amount_string)); - bn_format(&balance_delta, - NULL, NULL, - coin->decimals, 0, false, - amount_string, sizeof(amount_string)); - - if (is_transfer) { - // Confirm transfer between own accounts - char account_str[NODE_STRING_LENGTH]; - if (!nano_bip32_to_string(account_str, sizeof(account_str), coin, msg->link_recipient_n, - msg->link_recipient_n_count) && - !bip32_path_to_string(account_str, sizeof(account_str), - msg->link_recipient_n, msg->link_recipient_n_count)) { - strlcpy(account_str, recipient_address, sizeof(account_str)); - } - - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, - "Transfer", "Send %s %s to %s?", - amount_string, - coin->coin_shortcut, - account_str)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return false; - } - } else if (is_send) { - // Regular transfer - if (!confirm(ButtonRequestType_ButtonRequest_SignTx, - "Send", "Send %s %s to %s?", - amount_string, - coin->coin_shortcut, - recipient_address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return false; - } - } + char amount_string[60]; + memset(amount_string, 0, sizeof(amount_string)); + bn_format(&balance_delta, NULL, NULL, coin->decimals, 0, false, + amount_string, sizeof(amount_string)); + + if (is_transfer) { + // Confirm transfer between own accounts + char account_str[NODE_STRING_LENGTH]; + if (!nano_bip32_to_string(account_str, sizeof(account_str), coin, + msg->link_recipient_n, + msg->link_recipient_n_count) && + !bip32_path_to_string(account_str, sizeof(account_str), + msg->link_recipient_n, + msg->link_recipient_n_count)) { + strlcpy(account_str, recipient_address, sizeof(account_str)); + } + + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Transfer", + "Send %s %s to %s?", amount_string, coin->coin_shortcut, + account_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled"); + layoutHome(); + return false; + } + } else if (is_send) { + // Regular transfer + if (!confirm(ButtonRequestType_ButtonRequest_SignTx, "Send", + "Send %s %s to %s?", amount_string, coin->coin_shortcut, + recipient_address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled"); + layoutHome(); + return false; + } } + } - resp->has_signature = true; - resp->signature.size = 64; - hdnode_sign_digest(node, block_hash, resp->signature.bytes, NULL, NULL); + resp->has_signature = true; + resp->signature.size = 64; + hdnode_sign_digest(node, block_hash, resp->signature.bytes, NULL, NULL); - resp->has_block_hash = true; - resp->block_hash.size = sizeof(block_hash); - memcpy(resp->block_hash.bytes, block_hash, sizeof(block_hash)); - return true; + resp->has_block_hash = true; + resp->block_hash.size = sizeof(block_hash); + memcpy(resp->block_hash.bytes, block_hash, sizeof(block_hash)); + return true; } - diff --git a/lib/firmware/passphrase_sm.c b/lib/firmware/passphrase_sm.c index 5010279a1..e78e0fe9d 100644 --- a/lib/firmware/passphrase_sm.c +++ b/lib/firmware/passphrase_sm.c @@ -17,8 +17,7 @@ * along with this library. If not, see . */ - - +#include "keepkey/board/confirm_sm.h" #include "keepkey/board/layout.h" #include "keepkey/board/messages.h" #include "keepkey/board/timer.h" @@ -30,10 +29,8 @@ #include - extern bool reset_msg_stack; - /* * send_passphrase_request() - Send passphrase request to USB host * @@ -42,11 +39,10 @@ extern bool reset_msg_stack; * OUTPUT * none */ -static void send_passphrase_request(void) -{ - PassphraseRequest resp; - memset(&resp, 0, sizeof(PassphraseRequest)); - msg_write(MessageType_MessageType_PassphraseRequest, &resp); +static void send_passphrase_request(void) { + PassphraseRequest resp; + memset(&resp, 0, sizeof(PassphraseRequest)); + msg_write(MessageType_MessageType_PassphraseRequest, &resp); } /* @@ -57,34 +53,33 @@ static void send_passphrase_request(void) * OUTPUT * none */ -static void wait_for_passphrase_ack(PassphraseInfo *passphrase_info) -{ - /* Listen for tiny messages */ - uint8_t msg_tiny_buf[MSG_TINY_BFR_SZ]; - uint16_t tiny_msg = wait_for_tiny_msg(msg_tiny_buf); - - switch(tiny_msg) - { - /* Check for standard passphrase ack */ - case MessageType_MessageType_PassphraseAck : - passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_RECEIVED; - PassphraseAck *ppa = (PassphraseAck *)msg_tiny_buf; - - strlcpy(passphrase_info->passphrase, ppa->passphrase, PASSPHRASE_BUF); - break; - - case MessageType_MessageType_Cancel : /* Check for cancel or initialize messages */ - passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_CANCEL; - break; - - case MessageType_MessageType_Initialize : - passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_CANCEL_BY_INIT; - break; - - case MSG_TINY_TYPE_ERROR: - default: - break; - } +static void wait_for_passphrase_ack(PassphraseInfo *passphrase_info) { + /* Listen for tiny messages */ + uint8_t msg_tiny_buf[MSG_TINY_BFR_SZ]; + uint16_t tiny_msg = wait_for_tiny_msg(msg_tiny_buf); + + switch (tiny_msg) { + /* Check for standard passphrase ack */ + case MessageType_MessageType_PassphraseAck: + passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_RECEIVED; + PassphraseAck *ppa = (PassphraseAck *)msg_tiny_buf; + + strlcpy(passphrase_info->passphrase, ppa->passphrase, PASSPHRASE_BUF); + break; + + case MessageType_MessageType_Cancel: /* Check for cancel or initialize + messages */ + passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_CANCEL; + break; + + case MessageType_MessageType_Initialize: + passphrase_info->passphrase_ack_msg = PASSPHRASE_ACK_CANCEL_BY_INIT; + break; + + case MSG_TINY_TYPE_ERROR: + default: + break; + } } /* @@ -97,36 +92,32 @@ static void wait_for_passphrase_ack(PassphraseInfo *passphrase_info) * none */ static void run_passphrase_state(PassphraseState *passphrase_state, - PassphraseInfo *passphrase_info) -{ - switch(*passphrase_state) - { - - /* Send passphrase request */ - case PASSPHRASE_REQUEST: - send_passphrase_request(); - *passphrase_state = PASSPHRASE_WAITING; + PassphraseInfo *passphrase_info) { + switch (*passphrase_state) { + /* Send passphrase request */ + case PASSPHRASE_REQUEST: + send_passphrase_request(); + *passphrase_state = PASSPHRASE_WAITING; - layout_simple_message("Waiting for Passphrase..."); + layout_simple_message("Waiting for Passphrase..."); - break; + break; - /* Wait for a passphrase */ - case PASSPHRASE_WAITING: - wait_for_passphrase_ack(passphrase_info); + /* Wait for a passphrase */ + case PASSPHRASE_WAITING: + wait_for_passphrase_ack(passphrase_info); - if(passphrase_info->passphrase_ack_msg != PASSPHRASE_ACK_WAITING) - { - *passphrase_state = PASSPHRASE_FINISHED; - } + if (passphrase_info->passphrase_ack_msg != PASSPHRASE_ACK_WAITING) { + *passphrase_state = PASSPHRASE_FINISHED; + } - break; + break; - case PASSPHRASE_ACK: - case PASSPHRASE_FINISHED: - default: - break; - } + case PASSPHRASE_ACK: + case PASSPHRASE_FINISHED: + default: + break; + } } /* @@ -137,40 +128,38 @@ static void run_passphrase_state(PassphraseState *passphrase_state, * OUTPUT * true/false whether passphrase was received */ -static bool passphrase_request(PassphraseInfo *passphrase_info) -{ - bool ret = false; - reset_msg_stack = false; - PassphraseState passphrase_state = PASSPHRASE_REQUEST; - - /* Run SM */ - while(1) - { - run_passphrase_state(&passphrase_state, passphrase_info); - - if(passphrase_state == PASSPHRASE_FINISHED) - { - break; - } - } +static bool passphrase_request(PassphraseInfo *passphrase_info) { + bool ret = false; + reset_msg_stack = false; + PassphraseState passphrase_state = PASSPHRASE_REQUEST; + + /* Run SM */ + while (1) { + run_passphrase_state(&passphrase_state, passphrase_info); - /* Check for passphrase cancel */ - if(passphrase_info->passphrase_ack_msg == PASSPHRASE_ACK_RECEIVED) - { - ret = true; + if (passphrase_state == PASSPHRASE_FINISHED) { + break; } - else - { - if(passphrase_info->passphrase_ack_msg == PASSPHRASE_ACK_CANCEL_BY_INIT) - { - reset_msg_stack = true; - } + } + + /* Check for passphrase cancel */ + if (passphrase_info->passphrase_ack_msg == PASSPHRASE_ACK_RECEIVED) { + review(ButtonRequestType_ButtonRequest_Other, + "passphrase confirmation", + "If this is wrong, unplug/replug Keepkey:" + "%51s", + passphrase_info->passphrase + ); + ret = true; + } else { + if (passphrase_info->passphrase_ack_msg == PASSPHRASE_ACK_CANCEL_BY_INIT) { + reset_msg_stack = true; } + } - return (ret); + return (ret); } - /* * passphrase_protect() - Set passphrase protection * @@ -179,24 +168,19 @@ static bool passphrase_request(PassphraseInfo *passphrase_info) * OUTPUT * true/false whether passphrase was received */ -bool passphrase_protect(void) -{ - bool ret = false; - PassphraseInfo passphrase_info; - - if(storage_getPassphraseProtected() && !session_isPassphraseCached()) - { - /* Get passphrase and cache */ - if(passphrase_request(&passphrase_info)) - { - session_cachePassphrase(passphrase_info.passphrase); - ret = true; - } - } - else - { - ret = true; +bool passphrase_protect(void) { + bool ret = false; + PassphraseInfo passphrase_info; + + if (storage_getPassphraseProtected() && !session_isPassphraseCached()) { + /* Get passphrase and cache */ + if (passphrase_request(&passphrase_info)) { + session_cachePassphrase(passphrase_info.passphrase); + ret = true; } + } else { + ret = true; + } - return (ret); + return (ret); } diff --git a/lib/firmware/pin_sm.c b/lib/firmware/pin_sm.c index 3493825c7..116be6806 100644 --- a/lib/firmware/pin_sm.c +++ b/lib/firmware/pin_sm.c @@ -38,193 +38,168 @@ static char pin_matrix[PIN_BUF] = "XXXXXXXXX"; extern bool reset_msg_stack; /// Send USB request for PIN entry over USB port -static void send_pin_request(PinMatrixRequestType type) -{ - PinMatrixRequest resp; - memset(&resp, 0, sizeof(PinMatrixRequest)); - resp.has_type = true; - resp.type = type; - msg_write(MessageType_MessageType_PinMatrixRequest, &resp); +static void send_pin_request(PinMatrixRequestType type) { + PinMatrixRequest resp; + memset(&resp, 0, sizeof(PinMatrixRequest)); + resp.has_type = true; + resp.type = type; + msg_write(MessageType_MessageType_PinMatrixRequest, &resp); } /// Capture PIN entry from user over USB port -static void check_for_pin_ack(PINInfo *pin_info) -{ - /* Listen for tiny messages */ - uint8_t msg_tiny_buf[MSG_TINY_BFR_SZ]; - uint16_t tiny_msg; +static void check_for_pin_ack(PINInfo *pin_info) { + /* Listen for tiny messages */ + uint8_t msg_tiny_buf[MSG_TINY_BFR_SZ]; + uint16_t tiny_msg; - tiny_msg = check_for_tiny_msg(msg_tiny_buf); + tiny_msg = check_for_tiny_msg(msg_tiny_buf); - switch(tiny_msg) - { - case MessageType_MessageType_PinMatrixAck: - pin_info->pin_ack_msg = PIN_ACK_RECEIVED; - PinMatrixAck *pma = (PinMatrixAck *)msg_tiny_buf; + switch (tiny_msg) { + case MessageType_MessageType_PinMatrixAck: + pin_info->pin_ack_msg = PIN_ACK_RECEIVED; + PinMatrixAck *pma = (PinMatrixAck *)msg_tiny_buf; - strlcpy(pin_info->pin, pma->pin, PIN_BUF); - break; + strlcpy(pin_info->pin, pma->pin, PIN_BUF); + break; - case MessageType_MessageType_Cancel : /* Check for cancel or initialize messages */ - pin_info->pin_ack_msg = PIN_ACK_CANCEL; - break; + case MessageType_MessageType_Cancel: /* Check for cancel or initialize + messages */ + pin_info->pin_ack_msg = PIN_ACK_CANCEL; + break; - case MessageType_MessageType_Initialize: - pin_info->pin_ack_msg = PIN_ACK_CANCEL_BY_INIT; - break; + case MessageType_MessageType_Initialize: + pin_info->pin_ack_msg = PIN_ACK_CANCEL_BY_INIT; + break; #if DEBUG_LINK - case MessageType_MessageType_DebugLinkGetState: - call_msg_debug_link_get_state_handler((DebugLinkGetState *)msg_tiny_buf); - break; + case MessageType_MessageType_DebugLinkGetState: + call_msg_debug_link_get_state_handler((DebugLinkGetState *)msg_tiny_buf); + break; #endif - case MSG_TINY_TYPE_ERROR : - default: - break; - } + case MSG_TINY_TYPE_ERROR: + default: + break; + } } /// Request and receive PIN from user over USB port /// \param pin_state state of request /// \param pin_info buffer for user PIN -static void run_pin_state(PINState *pin_state, PINInfo *pin_info) -{ - switch(*pin_state) - { - - /* Send PIN request */ - case PIN_REQUEST: - if(pin_info->type) - { - send_pin_request(pin_info->type); - } - - pin_info->pin_ack_msg = PIN_ACK_WAITING; - *pin_state = PIN_WAITING; - break; - - /* Wait for a PIN */ - case PIN_WAITING: - check_for_pin_ack(pin_info); - - if(pin_info->pin_ack_msg != PIN_ACK_WAITING) - { - *pin_state = PIN_FINISHED; - } - - break; - - case PIN_FINISHED: - case PIN_ACK: - default: - break; - } +static void run_pin_state(PINState *pin_state, PINInfo *pin_info) { + switch (*pin_state) { + /* Send PIN request */ + case PIN_REQUEST: + if (pin_info->type) { + send_pin_request(pin_info->type); + } + + pin_info->pin_ack_msg = PIN_ACK_WAITING; + *pin_state = PIN_WAITING; + break; + + /* Wait for a PIN */ + case PIN_WAITING: + check_for_pin_ack(pin_info); + + if (pin_info->pin_ack_msg != PIN_ACK_WAITING) { + *pin_state = PIN_FINISHED; + } + + break; + + case PIN_FINISHED: + case PIN_ACK: + default: + break; + } } /// Make sure that PIN is at least one digit and a char from 1 to 9. /// \returns true iff the pin is in the correct format -static bool check_pin_input(PINInfo *pin_info) -{ - bool ret = true; - - /* Check that PIN is at least 1 digit and no more than 9 */ - if(!(strlen(pin_info->pin) >= 1 && strlen(pin_info->pin) <= 9)) - { - ret = false; - } +static bool check_pin_input(PINInfo *pin_info) { + bool ret = true; - /* Check that PIN char is a digit from 1 to 9 */ - for(uint8_t i = 0; i < strlen(pin_info->pin); i++) - { - uint8_t num = pin_info->pin[i] - '0'; + /* Check that PIN is at least 1 digit and no more than 9 */ + if (!(strlen(pin_info->pin) >= 1 && strlen(pin_info->pin) <= 9)) { + ret = false; + } - if(num < 1 || num > 9) - { - ret = false; - } + /* Check that PIN char is a digit from 1 to 9 */ + for (uint8_t i = 0; i < strlen(pin_info->pin); i++) { + uint8_t num = pin_info->pin[i] - '0'; + + if (num < 1 || num > 9) { + ret = false; } + } - return ret; + return ret; } /// Decode user PIN entry. -static void decode_pin(PINInfo *pin_info) -{ - for(uint32_t i = 0; i < strlen(pin_info->pin); i++) - { - int32_t j = pin_info->pin[i] - '1'; - - if(j >= 0 && (uint32_t)j < strlen(pin_matrix)) - { - pin_info->pin[i] = pin_matrix[j]; - } - else - { - pin_info->pin[i] = 'X'; - } +static void decode_pin(PINInfo *pin_info) { + for (uint32_t i = 0; i < strlen(pin_info->pin); i++) { + int32_t j = pin_info->pin[i] - '1'; + + if (j >= 0 && (uint32_t)j < strlen(pin_matrix)) { + pin_info->pin[i] = pin_matrix[j]; + } else { + pin_info->pin[i] = 'X'; } + } } /// Request user for PIN entry. /// \param prompt Text to display for the user along with PIN matrix. /// \returns true iff the pin was received. -static bool pin_request(const char *prompt, PINInfo *pin_info) -{ - bool ret = false; - reset_msg_stack = false; - PINState pin_state = PIN_REQUEST; - - /* Init and randomize pin matrix */ - strlcpy(pin_matrix, "123456789", PIN_BUF); - random_permute_char(pin_matrix, 9); - - /* Show layout */ - layout_pin(prompt, pin_matrix); - - /* Run SM */ - while(1) - { - animate(); - display_refresh(); - - run_pin_state(&pin_state, pin_info); - - if(pin_state == PIN_FINISHED) - { - break; - } - } +static bool pin_request(const char *prompt, PINInfo *pin_info) { + bool ret = false; + reset_msg_stack = false; + PINState pin_state = PIN_REQUEST; - /* Check for PIN cancel */ - if(pin_info->pin_ack_msg != PIN_ACK_RECEIVED) - { - if(pin_info->pin_ack_msg == PIN_ACK_CANCEL_BY_INIT) - { - reset_msg_stack = true; - } + /* Init and randomize pin matrix */ + strlcpy(pin_matrix, "123456789", PIN_BUF); + random_permute_char(pin_matrix, 9); - fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + /* Show layout */ + layout_pin(prompt, pin_matrix); + + /* Run SM */ + while (1) { + animate(); + display_refresh(); + + run_pin_state(&pin_state, pin_info); + + if (pin_state == PIN_FINISHED) { + break; } - else - { - if(check_pin_input(pin_info)) - { - /* Decode PIN */ - decode_pin(pin_info); - ret = true; - } - else - { - fsm_sendFailure(FailureType_Failure_PinCancelled, - "PIN must be at least 1 digit consisting of numbers from 1 to 9"); - } + } + + /* Check for PIN cancel */ + if (pin_info->pin_ack_msg != PIN_ACK_RECEIVED) { + if (pin_info->pin_ack_msg == PIN_ACK_CANCEL_BY_INIT) { + reset_msg_stack = true; } - /* Clear PIN matrix */ - strlcpy(pin_matrix, "XXXXXXXXX", PIN_BUF); + fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + } else { + if (check_pin_input(pin_info)) { + /* Decode PIN */ + decode_pin(pin_info); + ret = true; + } else { + fsm_sendFailure( + FailureType_Failure_PinCancelled, + "PIN must be at least 1 digit consisting of numbers from 1 to 9"); + } + } + + /* Clear PIN matrix */ + strlcpy(pin_matrix, "XXXXXXXXX", PIN_BUF); - return (ret); + return (ret); } static char warn_msg_fmt[MEDIUM_STR_BUF]; @@ -232,101 +207,127 @@ static volatile uint32_t total_wait = 0; static volatile uint32_t remaining_wait = 0; static void pin_fail_wait_handler(void) { - layoutProgress(warn_msg_fmt, (total_wait - remaining_wait) * 1000 / total_wait); + layoutProgress(warn_msg_fmt, + (total_wait - remaining_wait) * 1000 / total_wait); } -bool pin_protect(const char *prompt) -{ - if (!storage_hasPin()) { - return true; - } - - // Check for prior PIN failed attempts and apply exponentially longer delay - // for each subsequent failed attempt. - uint32_t fail_count = storage_getPinFails(); - if (fail_count > 2) { - uint32_t wait = (fail_count < 32) - ? (1u << fail_count) - : 0xFFFFFFFFu; - - // snprintf: 36 + 10 (%u) + 1 (NULL) = 47 - memzero(warn_msg_fmt, sizeof(warn_msg_fmt)); - snprintf(warn_msg_fmt, sizeof(warn_msg_fmt), - "Previous PIN Failures:\nWait %" PRIu32 " seconds", - wait); - layout_warning(warn_msg_fmt); - - remaining_wait = total_wait = wait; - - while (--remaining_wait > 0) { - delay_ms_with_callback(ONE_SEC, &pin_fail_wait_handler, 20); - } - } +bool pin_protect(const char *prompt) { + if (!storage_hasPin()) { + return true; + } - // Set request type - PINInfo pin_info; - pin_info.type = PinMatrixRequestType_PinMatrixRequestType_Current; + // Check for prior PIN failed attempts and apply exponentially longer delay + // for each subsequent failed attempt. + uint32_t fail_count = storage_getPinFails(); + if (fail_count > 2) { + uint32_t wait = (fail_count < 32) ? (1u << fail_count) : 0xFFFFFFFFu; - // Get PIN - if (!pin_request(prompt, &pin_info)) { - // PIN entry has been canceled by the user - return false; - } + // snprintf: 36 + 10 (%u) + 1 (NULL) = 47 + memzero(warn_msg_fmt, sizeof(warn_msg_fmt)); + snprintf(warn_msg_fmt, sizeof(warn_msg_fmt), + "Previous PIN Failures:\nWait %" PRIu32 " seconds", wait); + layout_warning(warn_msg_fmt); - // Preincrement the failed counter before authentication - storage_increasePinFails(); - bool pre_increment_cnt_flg = (fail_count >= storage_getPinFails()); + remaining_wait = total_wait = wait; - // Authenticate user PIN - if (!storage_isPinCorrect(pin_info.pin) || pre_increment_cnt_flg) { - fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); - return false; + while (--remaining_wait > 0) { + delay_ms_with_callback(ONE_SEC, &pin_fail_wait_handler, 20); } - - storage_resetPinFails(); - return true; + } + + // Set request type + PINInfo pin_info; + pin_info.type = PinMatrixRequestType_PinMatrixRequestType_Current; + + // Get PIN + if (!pin_request(prompt, &pin_info)) { + // PIN entry has been canceled by the user + return false; + } + + // Preincrement the failed counter before authentication + storage_increasePinFails(); + bool pre_increment_cnt_flg = (fail_count >= storage_getPinFails()); + + // Check if PIN entered is wipe code + if (storage_isWipeCodeCorrect(pin_info.pin)) { + session_clear(false); + storage_clearKeys(); + fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); + return false; + } + + // Authenticate user PIN + if (!storage_isPinCorrect(pin_info.pin) || pre_increment_cnt_flg) { + fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); + return false; + } + + storage_resetPinFails(); + return true; } bool pin_protect_cached(void) { if (session_isPinCached()) { return true; } - - return pin_protect("Enter Your PIN"); + + return pin_protect("Enter\nYour PIN"); } bool pin_protect_uncached(void) { - return pin_protect("Enter Your PIN"); + return pin_protect("Enter\nYour PIN"); } -bool change_pin(void) -{ - PINInfo pin_info_first, pin_info_second; +bool change_pin(void) { + PINInfo pin_info_first, pin_info_second; - /* Set request types */ - pin_info_first.type = PinMatrixRequestType_PinMatrixRequestType_NewFirst; - pin_info_second.type = PinMatrixRequestType_PinMatrixRequestType_NewSecond; + /* Set request types */ + pin_info_first.type = PinMatrixRequestType_PinMatrixRequestType_NewFirst; + pin_info_second.type = PinMatrixRequestType_PinMatrixRequestType_NewSecond; + + if (!pin_request("Enter New\nPIN", &pin_info_first)) { + return false; + } + + if (!pin_request("Re-Enter\nNew PIN", &pin_info_second)) { + return false; + } + + if (strcmp(pin_info_first.pin, pin_info_second.pin) != 0) { + return false; + } - if (!pin_request("Enter New PIN", &pin_info_first)) { + storage_setPin(pin_info_first.pin); + return true; +} + +bool change_wipe_code(void) { + PINInfo wipe_code_info_first, wipe_code_info_second; + + /* Set request types */ + wipe_code_info_first.type = + PinMatrixRequestType_PinMatrixRequestType_NewFirst; + wipe_code_info_second.type = + PinMatrixRequestType_PinMatrixRequestType_NewSecond; + + if (!pin_request("Enter New Wipe Code", &wipe_code_info_first)) { return false; } - - if (!pin_request("Re-Enter New PIN", &pin_info_second)) { + + if (!pin_request("Re-Enter New Wipe Code", &wipe_code_info_second)) { return false; } - - if (strcmp(pin_info_first.pin, pin_info_second.pin) != 0) { + + if (strcmp(wipe_code_info_first.pin, wipe_code_info_second.pin) != 0) { return false; } - - storage_setPin(pin_info_first.pin); + + storage_setWipeCode(wipe_code_info_first.pin); return true; } #if DEBUG_LINK /// Gets randomized PIN matrix -const char *get_pin_matrix(void) -{ - return pin_matrix; -} -#endif +const char *get_pin_matrix(void) { return pin_matrix; } +#endif \ No newline at end of file diff --git a/lib/firmware/policy.c b/lib/firmware/policy.c index 69679a3d4..0dd597a60 100644 --- a/lib/firmware/policy.c +++ b/lib/firmware/policy.c @@ -34,39 +34,36 @@ * - needs_confirm: whether confirm is required * OUTPUT * integer determining whether operation was succesful -*/ -int run_policy_compile_output(const CoinType *coin, const HDNode *root, void *vin, void *vout, bool needs_confirm) -{ - /* setup address type with respect to coin type */ - OutputAddressType addr_type; - if (isEthereumLike(coin->coin_name)) { - addr_type = ((EthereumSignTx *)vin)->address_type; - } else if (strcmp("Cosmos", coin->coin_name) == 0) { - addr_type = ((CosmosMsgSend *)vin)->address_type; - } else { - /* Bitcoin, Clones, Forks */ - if (vout == NULL) { - return TXOUT_COMPILE_ERROR; - } - addr_type = ((TxOutputType *)vin)->address_type; + */ +int run_policy_compile_output(const CoinType *coin, const HDNode *root, + void *vin, void *vout, bool needs_confirm) { + /* setup address type with respect to coin type */ + OutputAddressType addr_type; + if (isEthereumLike(coin->coin_name)) { + addr_type = ((EthereumSignTx *)vin)->address_type; + } else if (strcmp("Cosmos", coin->coin_name) == 0) { + addr_type = ((CosmosMsgSend *)vin)->address_type; + } else { + /* Bitcoin, Clones, Forks */ + if (vout == NULL) { + return TXOUT_COMPILE_ERROR; } + addr_type = ((TxOutputType *)vin)->address_type; + } - if (addr_type == OutputAddressType_EXCHANGE) - { - if (!storage_isPolicyEnabled("ShapeShift")) - return TXOUT_COMPILE_ERROR; + if (addr_type == OutputAddressType_EXCHANGE) { + if (!storage_isPolicyEnabled("ShapeShift")) return TXOUT_COMPILE_ERROR; - if (!process_exchange_contract(coin, vin, root, needs_confirm)) - return TXOUT_EXCHANGE_CONTRACT_ERROR; + if (!process_exchange_contract(coin, vin, root, needs_confirm)) + return TXOUT_EXCHANGE_CONTRACT_ERROR; - needs_confirm = false; - } + needs_confirm = false; + } - if (isEthereumLike(coin->coin_name)) - return TXOUT_OK; + if (isEthereumLike(coin->coin_name)) return TXOUT_OK; - if (strcmp("Cosmos", coin->coin_name) == 0) - return TXOUT_OK; + if (strcmp("Cosmos", coin->coin_name) == 0) return TXOUT_OK; - return compile_output(coin, root, (TxOutputType *)vin, (TxOutputBinType *)vout, needs_confirm); + return compile_output(coin, root, (TxOutputType *)vin, + (TxOutputBinType *)vout, needs_confirm); } diff --git a/lib/firmware/recovery_cipher.c b/lib/firmware/recovery_cipher.c index 4fd1c95de..188ce7288 100644 --- a/lib/firmware/recovery_cipher.c +++ b/lib/firmware/recovery_cipher.c @@ -38,7 +38,7 @@ #include #if DEBUG_LINK -# include +#include #endif #define MAX_UNCYPHERED_WORDS (3) @@ -50,7 +50,8 @@ static bool enforce_wordlist = true; static bool dry_run = true; static bool awaiting_character; static CONFIDENTIAL char mnemonic[MNEMONIC_BUF]; -static char english_alphabet[ENGLISH_ALPHABET_BUF] = "abcdefghijklmnopqrstuvwxyz"; +static char english_alphabet[ENGLISH_ALPHABET_BUF] = + "abcdefghijklmnopqrstuvwxyz"; static CONFIDENTIAL char cipher[ENGLISH_ALPHABET_BUF]; #if DEBUG_LINK @@ -61,18 +62,18 @@ static uint32_t get_current_word_pos(void); static void get_current_word(char *current_word); void recovery_cipher_abort(void) { - if (!dry_run) { - storage_reset(); - } - - recovery_started = false; - awaiting_character = false; - enforce_wordlist = true; - dry_run = true; - words_entered = 0; - word_count = 0; - memzero(mnemonic, sizeof(mnemonic)); - memzero(cipher, sizeof(cipher)); + if (!dry_run) { + storage_reset(); + } + + recovery_started = false; + awaiting_character = false; + enforce_wordlist = true; + dry_run = true; + words_entered = 0; + word_count = 0; + memzero(mnemonic, sizeof(mnemonic)); + memzero(cipher, sizeof(cipher)); } /// Formats the passed word to show position in mnemonic as well as characters @@ -81,25 +82,26 @@ void recovery_cipher_abort(void) { /// \param current_word[in] The string to format. /// \param auto_completed[in] Whether to format as an auto completed word. static void format_current_word(uint32_t word_pos, const char *current_word, - bool auto_completed, char (*formatted_word)[CURRENT_WORD_BUF + 10]) -{ - uint32_t word_num = word_pos + 1; - - snprintf(*formatted_word, sizeof(*formatted_word), "%" PRIu32 ".%s", word_num, current_word); - - /* Pad with dashes */ - size_t pos_len = strlen(current_word); - if (pos_len < 4) { - for (size_t i = 0; i < 4 - pos_len; i++) { - strlcat(*formatted_word, "-", sizeof(*formatted_word)); - } - } - - /* Mark as auto completed */ - if (auto_completed) { - (*formatted_word)[strlen(*formatted_word) + 1] = '\0'; - (*formatted_word)[strlen(*formatted_word)] = '~'; - } + bool auto_completed, + char (*formatted_word)[CURRENT_WORD_BUF + 10]) { + uint32_t word_num = word_pos + 1; + + snprintf(*formatted_word, sizeof(*formatted_word), "%" PRIu32 ".%s", word_num, + current_word); + + /* Pad with dashes */ + size_t pos_len = strlen(current_word); + if (pos_len < 4) { + for (size_t i = 0; i < 4 - pos_len; i++) { + strlcat(*formatted_word, "-", sizeof(*formatted_word)); + } + } + + /* Mark as auto completed */ + if (auto_completed) { + (*formatted_word)[strlen(*formatted_word) + 1] = '\0'; + (*formatted_word)[strlen(*formatted_word)] = '~'; + } } /* @@ -110,131 +112,122 @@ static void format_current_word(uint32_t word_pos, const char *current_word, * OUTPUT * position in mnemonic */ -static uint32_t get_current_word_pos(void) -{ - char *pos_num = strchr(mnemonic, ' '); - uint32_t word_pos = 0; - - while(pos_num != NULL) - { - word_pos++; - pos_num = strchr(++pos_num, ' '); - } +static uint32_t get_current_word_pos(void) { + char *pos_num = strchr(mnemonic, ' '); + uint32_t word_pos = 0; + + while (pos_num != NULL) { + word_pos++; + pos_num = strchr(++pos_num, ' '); + } - return word_pos; + return word_pos; } /// \returns the current word being entered by parsing the mnemonic thus far /// \param current_word[out] Array to populate with current word. -static void get_current_word(char *current_word) -{ - char *pos = strrchr(mnemonic, ' '); - - if(pos) - { - pos++; - strlcpy(current_word, pos, CURRENT_WORD_BUF); - } - else - { - strlcpy(current_word, mnemonic, CURRENT_WORD_BUF); - } +static void get_current_word(char *current_word) { + char *pos = strrchr(mnemonic, ' '); + + if (pos) { + pos++; + strlcpy(current_word, pos, CURRENT_WORD_BUF); + } else { + strlcpy(current_word, mnemonic, CURRENT_WORD_BUF); + } } -_Static_assert(BIP39_WORDLIST_PADDED, "bip39 wordlist must be padded to 9 characters"); - -bool exact_str_match(const char *str1, const char *str2, uint32_t len) -{ - volatile uint32_t match = 0; - - // Access through volatile ptrs to prevent compiler optimizations that - // might leak timing information. - const char volatile * volatile str1_v = str1; - const char volatile * volatile str2_v = str2; - - for(uint32_t i = 0; i < len && i < CURRENT_WORD_BUF && i <= BIP39_MAX_WORD_LEN; i++) - { - if(str1_v[i] == str2_v[i]) - { - match++; - } else { - match--; - } +_Static_assert(BIP39_WORDLIST_PADDED, + "bip39 wordlist must be padded to 9 characters"); + +bool exact_str_match(const char *str1, const char *str2, uint32_t len) { + volatile uint32_t match = 0; + + // Access through volatile ptrs to prevent compiler optimizations that + // might leak timing information. + const char volatile *volatile str1_v = str1; + const char volatile *volatile str2_v = str2; + + for (uint32_t i = 0; + i < len && i < CURRENT_WORD_BUF && i <= BIP39_MAX_WORD_LEN; i++) { + if (str1_v[i] == str2_v[i]) { + match++; + } else { + match--; } + } - return match == len; + return match == len; } #define BIP39_MAX_WORD_LEN 8 -bool attempt_auto_complete(char *partial_word) -{ - // Do lookup through volatile pointers to prevent the compiler from - // optimizing this loop into something that can leak timing information. - const char *const volatile * volatile words = - (const char *const volatile *)wordlist; +bool attempt_auto_complete(char *partial_word) { + // Do lookup through volatile pointers to prevent the compiler from + // optimizing this loop into something that can leak timing information. + const char *const volatile *volatile words = + (const char *const volatile *)wordlist; - uint32_t partial_word_len = strlen(partial_word), match = 0, found = 0; - bool precise_match = false; + uint32_t partial_word_len = strlen(partial_word), match = 0, found = 0; + bool precise_match = false; - // Because we build with -DBIP39_WORDLIST_PADDED=1, exact_str_match is - // allowed to read longer than the normal strlen of a given word, which has - // been null-padded to make constant-time comparisons possible. - if (partial_word_len > BIP39_MAX_WORD_LEN) { + // Because we build with -DBIP39_WORDLIST_PADDED=1, exact_str_match is + // allowed to read longer than the normal strlen of a given word, which has + // been null-padded to make constant-time comparisons possible. + if (partial_word_len > BIP39_MAX_WORD_LEN) { #if DEBUG_LINK && defined(EMULATOR) - assert(false); + assert(false); #endif - return false; - } - - - - static uint16_t CONFIDENTIAL permute[2049]; - for (int i = 0; i < 2049; i++) { - permute[i] = i; - } - random_permute_u16(permute, 2048); - - // We don't want the compiler to see through the fact that we're randomly - // permuting the order of iteration of the next few loops, in case it's - // smart enough to see through that and remove the permutation, so we tell - // it we've touched all of memory with some inline asm, and scare it off. - // This acts as an optimization barrier. - asm volatile ("" ::: "memory"); - - // Look for precise matches first (including null termination) - for (uint32_t volatile i = 0; words[permute[i]] != 0; i++) { - if (exact_str_match(partial_word, words[permute[i]], partial_word_len + 1)) { - strlcpy(partial_word, words[permute[i]], CURRENT_WORD_BUF); - precise_match = true; - } - } - - random_permute_u16(permute, 2048); - asm volatile ("" ::: "memory"); - - // Followed by partial matches (ignoring null termination) - for (uint32_t volatile i = 0; words[permute[i]] != 0; i++) { - if (exact_str_match(partial_word, words[permute[i]], partial_word_len)) { - match++; - found = i; - } - } - - if (precise_match) { - memzero(permute, sizeof(permute)); - return true; - } - - /* Autocomplete if we can */ - if (match == 1) { - strlcpy(partial_word, words[permute[found]], CURRENT_WORD_BUF); - memzero(permute, sizeof(permute)); - return true; - } + return false; + } + + static uint16_t CONFIDENTIAL permute[2049]; + for (int i = 0; i < 2049; i++) { + permute[i] = i; + } + random_permute_u16(permute, 2048); + + // We don't want the compiler to see through the fact that we're randomly + // permuting the order of iteration of the next few loops, in case it's + // smart enough to see through that and remove the permutation, so we tell + // it we've touched all of memory with some inline asm, and scare it off. + // This acts as an optimization barrier. + asm volatile("" ::: "memory"); + + // Look for precise matches first (including null termination) + for (uint32_t volatile i = 0; words[permute[i]] != 0; i++) { + if (exact_str_match(partial_word, words[permute[i]], + partial_word_len + 1)) { + strlcpy(partial_word, words[permute[i]], CURRENT_WORD_BUF); + precise_match = true; + } + } + + random_permute_u16(permute, 2048); + asm volatile("" ::: "memory"); + + // Followed by partial matches (ignoring null termination) + for (uint32_t volatile i = 0; words[permute[i]] != 0; i++) { + if (exact_str_match(partial_word, words[permute[i]], partial_word_len)) { + match++; + found = i; + } + } + + if (precise_match) { + memzero(permute, sizeof(permute)); + return true; + } + /* Autocomplete if we can */ + if (match == 1) { + strlcpy(partial_word, words[permute[found]], CURRENT_WORD_BUF); memzero(permute, sizeof(permute)); - return false; + return true; + } + + memzero(permute, sizeof(permute)); + return false; } /* @@ -250,62 +243,66 @@ bool attempt_auto_complete(char *partial_word) * OUTPUT * none */ -void recovery_cipher_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, - const char *language, const char *label, bool _enforce_wordlist, - uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter, bool _dry_run) -{ - // If word_count is known ahead of time, enforce that it's one of the standard ones: - if (_word_count && _word_count != 12 && _word_count != 18 && _word_count != 24) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (must be 12, 18 or 24)"); - layoutHome(); - return; - } +void recovery_cipher_init(uint32_t _word_count, bool passphrase_protection, + bool pin_protection, const char *language, + const char *label, bool _enforce_wordlist, + uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter, + bool _dry_run) { + // If word_count is known ahead of time, enforce that it's one of the standard + // ones: + if (_word_count && _word_count != 12 && _word_count != 18 && + _word_count != 24) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid word count (must be 12, 18 or 24)"); + layoutHome(); + return; + } - word_count = _word_count; - enforce_wordlist = _enforce_wordlist; - dry_run = _dry_run; + word_count = _word_count; + enforce_wordlist = _enforce_wordlist; + dry_run = _dry_run; - if (!dry_run) { - if (pin_protection) { - if (!change_pin()) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "PINs do not match"); - layoutHome(); - return; - } - } else { - storage_setPin(""); - } - - storage_setPassphraseProtected(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setAutoLockDelayMs(_auto_lock_delay_ms); - storage_setU2FCounter(_u2f_counter); - } else if (!pin_protect("Enter Your PIN")) { + if (!dry_run) { + if (pin_protection) { + if (!change_pin()) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "PINs do not match"); layoutHome(); return; + } + } else { + storage_setPin(""); } - if (!confirm(ButtonRequestType_ButtonRequest_Other, - dry_run ? "Recovery Dry Run" : "Recovery", - "When entering your recovery seed, use the substitution cipher " - "and check that each word shows up correctly on the screen.")) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Recovery cancelled"); - if (!dry_run) - storage_reset(); - layoutHome(); - return; - } + storage_setPassphraseProtected(passphrase_protection); + storage_setLanguage(language); + storage_setLabel(label); + storage_setAutoLockDelayMs(_auto_lock_delay_ms); + storage_setU2FCounter(_u2f_counter); + } else if (!pin_protect("Enter Your PIN")) { + layoutHome(); + return; + } + + if (!confirm(ButtonRequestType_ButtonRequest_Other, + dry_run ? "Recovery Dry Run" : "Recovery", + "When entering your recovery seed, use the substitution cipher " + "and check that each word shows up correctly on the screen.")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Recovery cancelled"); + if (!dry_run) storage_reset(); + layoutHome(); + return; + } - /* Clear mnemonic */ - memset(mnemonic, 0, sizeof(mnemonic) / sizeof(char)); + /* Clear mnemonic */ + memset(mnemonic, 0, sizeof(mnemonic) / sizeof(char)); - /* Set to recovery cipher mode and generate and show next cipher */ - awaiting_character = true; - recovery_started = true; - words_entered = 1; - next_character(); + /* Set to recovery cipher mode and generate and show next cipher */ + awaiting_character = true; + recovery_started = true; + words_entered = 1; + next_character(); } /* @@ -316,71 +313,72 @@ void recovery_cipher_init(uint32_t _word_count, bool passphrase_protection, bool * OUTPUT * none */ -void next_character(void) -{ - if (!recovery_started) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } +void next_character(void) { + if (!recovery_started) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in Recovery mode"); + layoutHome(); + return; + } - /* Scramble cipher */ - strlcpy(cipher, english_alphabet, ENGLISH_ALPHABET_BUF); - random_permute_char(cipher, strlen(cipher)); + /* Scramble cipher */ + strlcpy(cipher, english_alphabet, ENGLISH_ALPHABET_BUF); + random_permute_char(cipher, strlen(cipher)); - static char CONFIDENTIAL current_word[CURRENT_WORD_BUF]; - get_current_word(current_word); + static char CONFIDENTIAL current_word[CURRENT_WORD_BUF]; + get_current_word(current_word); - /* Words should never be longer than 4 characters */ - if (strlen(current_word) > 4) { - memzero(current_word, sizeof(current_word)); + /* Words should never be longer than 4 characters */ + if (strlen(current_word) > 4) { + memzero(current_word, sizeof(current_word)); - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, - "Words were not entered correctly. Make sure you are using the substition cipher."); - layoutHome(); - return; - } + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Words were not entered correctly. Make sure you are using " + "the substition cipher."); + layoutHome(); + return; + } - uint32_t word_pos = get_current_word_pos(); - if (word_pos + 1 != words_entered) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Sanity check failed"); - layoutHome(); - return; - } + uint32_t word_pos = get_current_word_pos(); + if (word_pos + 1 != words_entered) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Sanity check failed"); + layoutHome(); + return; + } - CharacterRequest resp; - memset(&resp, 0, sizeof(CharacterRequest)); + CharacterRequest resp; + memset(&resp, 0, sizeof(CharacterRequest)); - resp.word_pos = word_pos; - resp.character_pos = strlen(current_word); + resp.word_pos = word_pos; + resp.character_pos = strlen(current_word); - msg_write(MessageType_MessageType_CharacterRequest, &resp); + msg_write(MessageType_MessageType_CharacterRequest, &resp); - /* Attempt to auto complete if we have at least 3 characters */ - bool auto_completed = false; - if (strlen(current_word) >= 3) { - auto_completed = attempt_auto_complete(current_word); - } + /* Attempt to auto complete if we have at least 3 characters */ + bool auto_completed = false; + if (strlen(current_word) >= 3) { + auto_completed = attempt_auto_complete(current_word); + } #if DEBUG_LINK - if (auto_completed) { - strlcpy(auto_completed_word, current_word, CURRENT_WORD_BUF); - } else { - auto_completed_word[0] = '\0'; - } + if (auto_completed) { + strlcpy(auto_completed_word, current_word, CURRENT_WORD_BUF); + } else { + auto_completed_word[0] = '\0'; + } #endif - /* Format current word and display it along with cipher */ - static char CONFIDENTIAL formatted_word[CURRENT_WORD_BUF + 10]; - format_current_word(word_pos, current_word, auto_completed, &formatted_word); - memzero(current_word, sizeof(current_word)); + /* Format current word and display it along with cipher */ + static char CONFIDENTIAL formatted_word[CURRENT_WORD_BUF + 10]; + format_current_word(word_pos, current_word, auto_completed, &formatted_word); + memzero(current_word, sizeof(current_word)); - /* Show cipher and partial word */ - layout_cipher(formatted_word, cipher); - memzero(formatted_word, sizeof(formatted_word)); + /* Show cipher and partial word */ + layout_cipher(formatted_word, cipher); + memzero(formatted_word, sizeof(formatted_word)); } /* @@ -391,100 +389,103 @@ void next_character(void) * OUTPUT * none */ -void recovery_character(const char *character) -{ - if (!awaiting_character || !recovery_started) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } +void recovery_character(const char *character) { + if (!awaiting_character || !recovery_started) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in Recovery mode"); + layoutHome(); + return; + } - if (strlen(mnemonic) + 1 > MNEMONIC_BUF - 1) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, - "Too many characters attempted during recovery"); - layoutHome(); - return; - } + if (strlen(mnemonic) + 1 > MNEMONIC_BUF - 1) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Too many characters attempted during recovery"); + layoutHome(); + return; + } - char *pos = strchr(cipher, character[0]); + char *pos = strchr(cipher, character[0]); - // If not a space and not a legitmate cipher character, send failure. - if (character[0] != ' ' && pos == NULL) { + // If not a space and not a legitmate cipher character, send failure. + if (character[0] != ' ' && pos == NULL) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Character must be from a to z"); + layoutHome(); + return; + } + + // Count of words we think the user has entered without using the cipher: + static int uncyphered_word_count = 0; + static bool definitely_using_cipher = false; + static CONFIDENTIAL char coded_word[12]; + static CONFIDENTIAL char decoded_word[12]; + + if (!mnemonic[0]) { + uncyphered_word_count = 0; + definitely_using_cipher = false; + memzero(coded_word, sizeof(coded_word)); + memzero(decoded_word, sizeof(decoded_word)); + } + + char decoded_character[2] = " "; + if (character[0] != ' ') { + // Decode character using cipher if not space + decoded_character[0] = english_alphabet[(int)(pos - cipher)]; + + strlcat(coded_word, character, sizeof(coded_word)); + strlcat(decoded_word, decoded_character, sizeof(decoded_word)); + + if (enforce_wordlist && 4 <= strlen(coded_word)) { + // Check & bail if the user is entering their seed without using the + // cipher. Note that for each word, this can give false positives about + // ~0.4% of the time (2048/26^4). + + bool maybe_not_using_cipher = attempt_auto_complete(coded_word); + bool maybe_using_cipher = attempt_auto_complete(decoded_word); + + if (!maybe_not_using_cipher && maybe_using_cipher) { + // Decrease the overall false positive rate by detecting that a + // user has entered a word which is definitely using the + // cipher. + definitely_using_cipher = true; + } else if (maybe_not_using_cipher && !definitely_using_cipher && + MAX_UNCYPHERED_WORDS < uncyphered_word_count++) { recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Character must be from a to z"); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Words were not entered correctly. Make sure you are " + "using the substition cipher."); layoutHome(); return; + } } + } else { + memzero(coded_word, sizeof(coded_word)); + memzero(decoded_word, sizeof(decoded_word)); - // Count of words we think the user has entered without using the cipher: - static int uncyphered_word_count = 0; - static bool definitely_using_cipher = false; - static CONFIDENTIAL char coded_word[12]; - static CONFIDENTIAL char decoded_word[12]; - - if (!mnemonic[0]) { - uncyphered_word_count = 0; - definitely_using_cipher = false; - memzero(coded_word, sizeof(coded_word)); - memzero(decoded_word, sizeof(decoded_word)); + if (word_count && words_entered == word_count) { + strlcat(mnemonic, " ", MNEMONIC_BUF); + recovery_cipher_finalize(); + return; } - char decoded_character[2] = " "; - if (character[0] != ' ') { - // Decode character using cipher if not space - decoded_character[0] = english_alphabet[(int)(pos - cipher)]; - - strlcat(coded_word, character, sizeof(coded_word)); - strlcat(decoded_word, decoded_character, sizeof(decoded_word)); - - if (enforce_wordlist && 4 <= strlen(coded_word)) { - // Check & bail if the user is entering their seed without using the - // cipher. Note that for each word, this can give false positives about - // ~0.4% of the time (2048/26^4). - - bool maybe_not_using_cipher = attempt_auto_complete(coded_word); - bool maybe_using_cipher = attempt_auto_complete(decoded_word); - - if (!maybe_not_using_cipher && maybe_using_cipher) { - // Decrease the overall false positive rate by detecting that a - // user has entered a word which is definitely using the - // cipher. - definitely_using_cipher = true; - } else if (maybe_not_using_cipher && !definitely_using_cipher && - MAX_UNCYPHERED_WORDS < uncyphered_word_count++) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, - "Words were not entered correctly. Make sure you are using the substition cipher."); - layoutHome(); - return; - } - } - } else { - memzero(coded_word, sizeof(coded_word)); - memzero(decoded_word, sizeof(decoded_word)); - - if (word_count && words_entered == word_count) { - strlcat(mnemonic, " ", MNEMONIC_BUF); - recovery_cipher_finalize(); - return; - } - - words_entered++; - - if (words_entered > 24 || (word_count && words_entered > word_count)) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Too many words entered"); - layoutHome(); - return; - } + words_entered++; + + if (words_entered > 24 || (word_count && words_entered > word_count)) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Too many words entered"); + layoutHome(); + return; } + } - // concat to mnemonic - strlcat(mnemonic, decoded_character, MNEMONIC_BUF); + // concat to mnemonic + strlcat(mnemonic, decoded_character, MNEMONIC_BUF); - next_character(); + next_character(); } /* @@ -495,25 +496,23 @@ void recovery_character(const char *character) * OUTPUT * none */ -void recovery_delete_character(void) -{ - if (!recovery_started) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } +void recovery_delete_character(void) { + if (!recovery_started) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in Recovery mode"); + layoutHome(); + return; + } - size_t len = strlen(mnemonic); - if (len > 0) - { - if (mnemonic[len - 1] == ' ') - words_entered--; + size_t len = strlen(mnemonic); + if (len > 0) { + if (mnemonic[len - 1] == ' ') words_entered--; - mnemonic[len - 1] = '\0'; - } + mnemonic[len - 1] = '\0'; + } - next_character(); + next_character(); } /* @@ -524,112 +523,119 @@ void recovery_delete_character(void) * OUTPUT * none */ -void recovery_cipher_finalize(void) -{ - if (!recovery_started) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } +void recovery_cipher_finalize(void) { + if (!recovery_started) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Not in Recovery mode"); + layoutHome(); + return; + } - if (word_count) { - // If word_count is known ahead of time, also enforce that the correct - // number of words has been entered: - if (words_entered != word_count) { - recovery_cipher_abort(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Not enough words entered"); - layoutHome(); - return; - } - } else { - // Otherwise just enforce that the number of words entered is a standard count: - if (words_entered != 12 && words_entered != 18 && words_entered != 24) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (must be 12, 18 or 24)"); - layoutHome(); - return; - } + if (word_count) { + // If word_count is known ahead of time, also enforce that the correct + // number of words has been entered: + if (words_entered != word_count) { + recovery_cipher_abort(); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Not enough words entered"); + layoutHome(); + return; + } + } else { + // Otherwise just enforce that the number of words entered is a standard + // count: + if (words_entered != 12 && words_entered != 18 && words_entered != 24) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid word count (must be 12, 18 or 24)"); + layoutHome(); + return; } + } - static char CONFIDENTIAL new_mnemonic[MNEMONIC_BUF] = ""; - static char CONFIDENTIAL temp_word[CURRENT_WORD_BUF]; - volatile bool auto_completed = true; + static char CONFIDENTIAL new_mnemonic[MNEMONIC_BUF] = ""; + static char CONFIDENTIAL temp_word[CURRENT_WORD_BUF]; + volatile bool auto_completed = true; - memzero(new_mnemonic, sizeof(new_mnemonic)); - memzero(temp_word, sizeof(temp_word)); + memzero(new_mnemonic, sizeof(new_mnemonic)); + memzero(temp_word, sizeof(temp_word)); - /* Attempt to autocomplete each word */ - char *tok = strtok(mnemonic, " "); + /* Attempt to autocomplete each word */ + char *tok = strtok(mnemonic, " "); - while(tok) { - strlcpy(temp_word, tok, CURRENT_WORD_BUF); + while (tok) { + strlcpy(temp_word, tok, CURRENT_WORD_BUF); - auto_completed &= attempt_auto_complete(temp_word); + auto_completed &= attempt_auto_complete(temp_word); - strlcat(new_mnemonic, temp_word, MNEMONIC_BUF); - strlcat(new_mnemonic, " ", MNEMONIC_BUF); + strlcat(new_mnemonic, temp_word, MNEMONIC_BUF); + strlcat(new_mnemonic, " ", MNEMONIC_BUF); - tok = strtok(NULL, " "); - } - memzero(temp_word, sizeof(temp_word)); + tok = strtok(NULL, " "); + } + memzero(temp_word, sizeof(temp_word)); - if (!auto_completed && !enforce_wordlist) { - if (!dry_run) { - storage_reset(); - } - fsm_sendFailure(FailureType_Failure_SyntaxError, - "Words were not entered correctly. Make sure you are using the substition cipher."); - awaiting_character = false; - layoutHome(); - return; + if (!auto_completed && !enforce_wordlist) { + if (!dry_run) { + storage_reset(); } + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Words were not entered correctly. Make sure you are using " + "the substition cipher."); + awaiting_character = false; + layoutHome(); + return; + } + + /* Truncate additional space at the end */ + new_mnemonic[MAX(0u, strnlen(new_mnemonic, sizeof(new_mnemonic)) - 1)] = '\0'; - /* Truncate additional space at the end */ - new_mnemonic[MAX(0u, strnlen(new_mnemonic, sizeof(new_mnemonic)) - 1)] = '\0'; - - if (!dry_run && (!enforce_wordlist || mnemonic_check(new_mnemonic))) { - storage_setMnemonic(new_mnemonic); - memzero(new_mnemonic, sizeof(new_mnemonic)); - if (!enforce_wordlist) { - // not enforcing => mark storage as imported - storage_setImported(true); - } - storage_commit(); - fsm_sendSuccess("Device recovered"); - } else if (dry_run) { - bool match = storage_isInitialized() && storage_containsMnemonic(new_mnemonic); - if (match) { - review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", - "The seed is valid and MATCHES the one in the device."); - fsm_sendSuccess("The seed is valid and matches the one in the device."); - } else if (mnemonic_check(new_mnemonic)) { - review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", - "The seed is valid, but DOES NOT MATCH the one in the device."); - fsm_sendFailure(FailureType_Failure_Other, - "The seed is valid, but does not match the one in the device."); - } else { - review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", - "The seed is INVALID, and DOES NOT MATCH the one in the device."); - fsm_sendFailure(FailureType_Failure_Other, - "The seed is invalid, and does not match the one in the device."); - } - memzero(new_mnemonic, sizeof(new_mnemonic)); + if (!dry_run && (!enforce_wordlist || mnemonic_check(new_mnemonic))) { + storage_setMnemonic(new_mnemonic); + memzero(new_mnemonic, sizeof(new_mnemonic)); + if (!enforce_wordlist) { + // not enforcing => mark storage as imported + storage_setImported(true); + } + storage_commit(); + fsm_sendSuccess("Device recovered"); + } else if (dry_run) { + bool match = + storage_isInitialized() && storage_containsMnemonic(new_mnemonic); + if (match) { + review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", + "The seed is valid and MATCHES the one in the device."); + fsm_sendSuccess("The seed is valid and matches the one in the device."); + } else if (mnemonic_check(new_mnemonic)) { + review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", + "The seed is valid, but DOES NOT MATCH the one in the device."); + fsm_sendFailure( + FailureType_Failure_Other, + "The seed is valid, but does not match the one in the device."); } else { - session_clear(true); - fsm_sendFailure(FailureType_Failure_SyntaxError, - "Invalid mnemonic, are words in correct order?"); - recovery_cipher_abort(); + review(ButtonRequestType_ButtonRequest_Other, "Recovery Dry Run", + "The seed is INVALID, and DOES NOT MATCH the one in the device."); + fsm_sendFailure( + FailureType_Failure_Other, + "The seed is invalid, and does not match the one in the device."); } - memzero(new_mnemonic, sizeof(new_mnemonic)); - awaiting_character = false; - enforce_wordlist = true; - dry_run = true; - words_entered = 0; - word_count = 0; - memzero(mnemonic, sizeof(mnemonic)); - memzero(cipher, sizeof(cipher)); - layoutHome(); + } else { + session_clear(true); + fsm_sendFailure(FailureType_Failure_SyntaxError, + "Invalid mnemonic, are words in correct order?"); + recovery_cipher_abort(); + } + + memzero(new_mnemonic, sizeof(new_mnemonic)); + awaiting_character = false; + enforce_wordlist = true; + dry_run = true; + words_entered = 0; + word_count = 0; + memzero(mnemonic, sizeof(mnemonic)); + memzero(cipher, sizeof(cipher)); + layoutHome(); } #if DEBUG_LINK @@ -641,10 +647,7 @@ void recovery_cipher_finalize(void) * OUTPUT * current cipher */ -const char *recovery_get_cipher(void) -{ - return cipher; -} +const char *recovery_get_cipher(void) { return cipher; } /* * recovery_get_auto_completed_word() - Gets last auto completed word @@ -654,8 +657,7 @@ const char *recovery_get_cipher(void) * OUTPUT * last auto completed word */ -const char *recovery_get_auto_completed_word(void) -{ - return auto_completed_word; +const char *recovery_get_auto_completed_word(void) { + return auto_completed_word; } #endif diff --git a/lib/firmware/reset.c b/lib/firmware/reset.c index 66a3c9d94..2f023c033 100644 --- a/lib/firmware/reset.c +++ b/lib/firmware/reset.c @@ -43,85 +43,88 @@ static bool awaiting_entropy = false; static char CONFIDENTIAL current_words[MNEMONIC_BY_SCREEN_BUF]; static bool no_backup; -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, - bool pin_protection, const char *language, const char *label, bool _no_backup, - uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter) -{ - if(_strength != 128 && _strength != 192 && _strength != 256) - { - fsm_sendFailure(FailureType_Failure_SyntaxError, - _("Invalid mnemonic strength (has to be 128, 192 or 256 bits)")); - layoutHome(); - return; - } +void reset_init(bool display_random, uint32_t _strength, + bool passphrase_protection, bool pin_protection, + const char *language, const char *label, bool _no_backup, + uint32_t _auto_lock_delay_ms, uint32_t _u2f_counter) { + if (_strength != 128 && _strength != 192 && _strength != 256) { + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Invalid mnemonic strength (has to be 128, 192 or 256 bits)")); + layoutHome(); + return; + } - strength = _strength; - no_backup = _no_backup; + strength = _strength; + no_backup = _no_backup; - if (display_random && no_backup) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Can't show internal entropy when backup is skipped")); - layoutHome(); - return; + if (display_random && no_backup) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Can't show internal entropy when backup is skipped")); + layoutHome(); + return; + } + + if (no_backup) { + // Double confirm, since this is a feature for advanced users only, and + // there is risk of loss of funds if this mode is used incorrectly + // (i.e. multisig is an absolute must with this scheme). + if (!confirm(ButtonRequestType_ButtonRequest_Other, _("WARNING"), + _("The 'No Backup' option was selected.\n" + "Recovery sentence will *NOT* be shown,\n" + "and recovery will be IMPOSSIBLE.\n")) || + !confirm(ButtonRequestType_ButtonRequest_Other, _("WARNING"), + _("The 'No Backup' option was selected.\n\n" + "I understand, and accept the risks.\n"))) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Reset cancelled")); + layoutHome(); + return; } - - if (no_backup) { - // Double confirm, since this is a feature for advanced users only, and - // there is risk of loss of funds if this mode is used incorrectly - // (i.e. multisig is an absolute must with this scheme). - if (!confirm(ButtonRequestType_ButtonRequest_Other, _("WARNING"), - _("The 'No Backup' option was selected.\n" - "Recovery sentence will *NOT* be shown,\n" - "and recovery will be IMPOSSIBLE.\n")) || - !confirm(ButtonRequestType_ButtonRequest_Other, _("WARNING"), - _("The 'No Backup' option was selected.\n\n" - "I understand, and accept the risks.\n"))) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Reset cancelled")); - layoutHome(); - return; - } + } + + random_buffer(int_entropy, 32); + + if (display_random) { + static char CONFIDENTIAL ent_str[4][17]; + data2hex(int_entropy, 8, ent_str[0]); + data2hex(int_entropy + 8, 8, ent_str[1]); + data2hex(int_entropy + 16, 8, ent_str[2]); + data2hex(int_entropy + 24, 8, ent_str[3]); + + if (!confirm(ButtonRequestType_ButtonRequest_ResetDevice, + _("Internal Entropy"), "%s %s %s %s", ent_str[0], ent_str[1], + ent_str[2], ent_str[3])) { + memzero(ent_str, sizeof(ent_str)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Reset cancelled")); + layoutHome(); + return; } - - random_buffer(int_entropy, 32); - - if (display_random) { - static char CONFIDENTIAL ent_str[4][17]; - data2hex(int_entropy , 8, ent_str[0]); - data2hex(int_entropy + 8, 8, ent_str[1]); - data2hex(int_entropy + 16, 8, ent_str[2]); - data2hex(int_entropy + 24, 8, ent_str[3]); - - if(!confirm(ButtonRequestType_ButtonRequest_ResetDevice, - _("Internal Entropy"), "%s %s %s %s", - ent_str[0], ent_str[1], ent_str[2], ent_str[3])) - { - memzero(ent_str, sizeof(ent_str)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Reset cancelled")); - layoutHome(); - return; - } - memzero(ent_str, sizeof(ent_str)); + memzero(ent_str, sizeof(ent_str)); + } + + if (pin_protection) { + if (!change_pin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("PINs do not match")); + layoutHome(); + return; } - - if (pin_protection) { - if (!change_pin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("PINs do not match")); - layoutHome(); - return; - } - } else { - storage_setPin(""); - } - - storage_setPassphraseProtected(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setAutoLockDelayMs(_auto_lock_delay_ms); - storage_setU2FCounter(_u2f_counter); - - EntropyRequest resp; - memset(&resp, 0, sizeof(EntropyRequest)); - msg_write(MessageType_MessageType_EntropyRequest, &resp); - awaiting_entropy = true; + } else { + storage_setPin(""); + } + + storage_setPassphraseProtected(passphrase_protection); + storage_setLanguage(language); + storage_setLabel(label); + storage_setAutoLockDelayMs(_auto_lock_delay_ms); + storage_setU2FCounter(_u2f_counter); + + EntropyRequest resp; + memset(&resp, 0, sizeof(EntropyRequest)); + msg_write(MessageType_MessageType_EntropyRequest, &resp); + awaiting_entropy = true; } void reset_entropy(const uint8_t *ext_entropy, uint32_t len) @@ -151,7 +154,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendSuccess(_("Device reset")); goto exit; } else { - if (!confirm(ButtonRequestType_ButtonRequest_Other, _("Recovery Seed Backup"), + if (!confirm(ButtonRequestType_ButtonRequest_Other, _("Recovery Seed Bakcup"), "This recovery seed will only be shown ONCE. " "Please write it down carefully,\n" "and DO NOT share it with anyone. ")) { @@ -169,8 +172,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) static char CONFIDENTIAL tokened_mnemonic[TOKENED_MNEMONIC_BUF]; static char CONFIDENTIAL mnemonic_by_screen[MAX_PAGES][MNEMONIC_BY_SCREEN_BUF]; static char CONFIDENTIAL formatted_mnemonic[MAX_PAGES][FORMATTED_MNEMONIC_BUF]; + static char CONFIDENTIAL mnemonic_display[FORMATTED_MNEMONIC_BUF]; static char CONFIDENTIAL formatted_word[MAX_WORD_LEN + ADDITIONAL_WORD_PAD]; - static char CONFIDENTIAL mnemonic_display[FORMATTED_MNEMONIC_BUF + 3 + sizeof(formatted_word)]; strlcpy(tokened_mnemonic, temp_mnemonic, TOKENED_MNEMONIC_BUF); @@ -178,11 +181,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) while(tok) { - snprintf(formatted_word, MAX_WORD_LEN + ADDITIONAL_WORD_PAD, "%lu.%s", + snprintf(formatted_word, MAX_WORD_LEN + ADDITIONAL_WORD_PAD, (word_count & 1) ? "%lu.%s\n" : "%lu.%s", (unsigned long)(word_count + 1), tok); /* Check that we have enough room on display to show word */ - snprintf(mnemonic_display, sizeof(mnemonic_display), "%s %s", + snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s %s", formatted_mnemonic[page_count], formatted_word); if(calc_str_line(get_body_font(), mnemonic_display, BODY_WIDTH) > 3) @@ -195,8 +198,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) goto exit; } - snprintf(mnemonic_display, sizeof(mnemonic_display), "%s %s", - formatted_mnemonic[page_count], formatted_word); + snprintf(mnemonic_display, FORMATTED_MNEMONIC_BUF, "%s %s", + formatted_mnemonic[page_count], formatted_word); } strlcpy(formatted_mnemonic[page_count], mnemonic_display, @@ -220,10 +223,12 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) // Switch from 0-indexing to 1-indexing page_count++; + display_constant_power(true); + /* Have user confirm mnemonic is sets of 12 words */ for(uint32_t current_page = 0; current_page < page_count; current_page++) { - char title[MEDIUM_STR_BUF] = _("Recovery Seed Backup"); + char title[MEDIUM_STR_BUF] = _("Backup"); /* make current screen mnemonic available via debuglink */ strlcpy(current_words, mnemonic_by_screen[current_page], MNEMONIC_BY_SCREEN_BUF); @@ -231,11 +236,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) if(page_count > 1) { /* snprintf: 20 + 10 (%d) + 1 (NULL) = 31 */ - snprintf(title, MEDIUM_STR_BUF, _("Recovery Seed Backup %" PRIu32 "/%" PRIu32 ""), current_page + 1, page_count); + snprintf(title, MEDIUM_STR_BUF, _("Backup %" PRIu32 "/%" PRIu32 ""), current_page + 1, page_count); } - if(!confirm(ButtonRequestType_ButtonRequest_ConfirmWord, title, "%s", - formatted_mnemonic[current_page])) + if(!confirm_constant_power(ButtonRequestType_ButtonRequest_ConfirmWord, title, "%s", + formatted_mnemonic[current_page])) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Reset cancelled")); storage_reset(); @@ -247,29 +252,23 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) storage_setMnemonic(temp_mnemonic); mnemonic_clear(); storage_commit(); - fsm_sendSuccess(_("Device reset")); exit: - memzero(&ctx, sizeof(ctx)); - memzero(tokened_mnemonic, sizeof(tokened_mnemonic)); - memzero(mnemonic_by_screen, sizeof(mnemonic_by_screen)); - memzero(formatted_mnemonic, sizeof(formatted_mnemonic)); - memzero(mnemonic_display, sizeof(mnemonic_display)); - memzero(formatted_word, sizeof(formatted_word)); - layoutHome(); + memzero(&ctx, sizeof(ctx)); + memzero(tokened_mnemonic, sizeof(tokened_mnemonic)); + memzero(mnemonic_by_screen, sizeof(mnemonic_by_screen)); + memzero(formatted_mnemonic, sizeof(formatted_mnemonic)); + memzero(mnemonic_display, sizeof(mnemonic_display)); + memzero(formatted_word, sizeof(formatted_word)); + layoutHome(); } - #if DEBUG_LINK -uint32_t reset_get_int_entropy(uint8_t *entropy) -{ - memcpy(entropy, int_entropy, 32); - return 32; +uint32_t reset_get_int_entropy(uint8_t *entropy) { + memcpy(entropy, int_entropy, 32); + return 32; } -const char *reset_get_word(void) -{ - return current_words; -} +const char *reset_get_word(void) { return current_words; } #endif diff --git a/lib/firmware/ripple.c b/lib/firmware/ripple.c index 871a4fc91..f1c5d60c6 100644 --- a/lib/firmware/ripple.c +++ b/lib/firmware/ripple.c @@ -25,264 +25,258 @@ #include -const RippleFieldMapping RFM_account = { .type = RFT_ACCOUNT, .key = 1 }; -const RippleFieldMapping RFM_amount = { .type = RFT_AMOUNT, .key = 1 }; -const RippleFieldMapping RFM_destination = { .type = RFT_ACCOUNT, .key = 3 }; -const RippleFieldMapping RFM_fee = { .type = RFT_AMOUNT, .key = 8 }; -const RippleFieldMapping RFM_sequence = { .type = RFT_INT32, .key = 4 }; -const RippleFieldMapping RFM_type = { .type = RFT_INT16, .key = 2 }; -const RippleFieldMapping RFM_signingPubKey = { .type = RFT_VL, .key = 3 }; -const RippleFieldMapping RFM_flags = { .type = RFT_INT32, .key = 2 }; -const RippleFieldMapping RFM_txnSignature = { .type = RFT_VL, .key = 4 }; -const RippleFieldMapping RFM_lastLedgerSequence = { .type = RFT_INT32, .key = 27 }; -const RippleFieldMapping RFM_destinationTag = { .type = RFT_INT32, .key = 14 }; - -bool ripple_getAddress(const uint8_t public_key[33], char address[MAX_ADDR_SIZE]) -{ - uint8_t buff[64]; - memset(buff, 0, sizeof(buff)); - - Hasher hasher; - hasher_Init(&hasher, HASHER_SHA2_RIPEMD); - hasher_Update(&hasher, public_key, 33); - hasher_Final(&hasher, buff + 1); - - if (!ripple_encode_check(buff, 21, HASHER_SHA2D, - address, MAX_ADDR_SIZE)) { - assert(false && "can't encode address"); - return false; - } - - return true; +const RippleFieldMapping RFM_account = {.type = RFT_ACCOUNT, .key = 1}; +const RippleFieldMapping RFM_amount = {.type = RFT_AMOUNT, .key = 1}; +const RippleFieldMapping RFM_destination = {.type = RFT_ACCOUNT, .key = 3}; +const RippleFieldMapping RFM_fee = {.type = RFT_AMOUNT, .key = 8}; +const RippleFieldMapping RFM_sequence = {.type = RFT_INT32, .key = 4}; +const RippleFieldMapping RFM_type = {.type = RFT_INT16, .key = 2}; +const RippleFieldMapping RFM_signingPubKey = {.type = RFT_VL, .key = 3}; +const RippleFieldMapping RFM_flags = {.type = RFT_INT32, .key = 2}; +const RippleFieldMapping RFM_txnSignature = {.type = RFT_VL, .key = 4}; +const RippleFieldMapping RFM_lastLedgerSequence = {.type = RFT_INT32, + .key = 27}; +const RippleFieldMapping RFM_destinationTag = {.type = RFT_INT32, .key = 14}; + +bool ripple_getAddress(const uint8_t public_key[33], + char address[MAX_ADDR_SIZE]) { + uint8_t buff[64]; + memset(buff, 0, sizeof(buff)); + + Hasher hasher; + hasher_Init(&hasher, HASHER_SHA2_RIPEMD); + hasher_Update(&hasher, public_key, 33); + hasher_Final(&hasher, buff + 1); + + if (!ripple_encode_check(buff, 21, HASHER_SHA2D, address, MAX_ADDR_SIZE)) { + assert(false && "can't encode address"); + return false; + } + + return true; } -void ripple_formatAmount(char *buf, size_t len, uint64_t amount) -{ - bignum256 val; - bn_read_uint64(amount, &val); - bn_format(&val, NULL, " XRP", RIPPLE_DECIMALS, 0, false, buf, len); +void ripple_formatAmount(char *buf, size_t len, uint64_t amount) { + bignum256 val; + bn_read_uint64(amount, &val); + bn_format(&val, NULL, " XRP", RIPPLE_DECIMALS, 0, false, buf, len); } -static void append_u8(bool *ok, uint8_t **buf, const uint8_t *end, uint8_t val) -{ - if (!*ok) { - return; - } +static void append_u8(bool *ok, uint8_t **buf, const uint8_t *end, + uint8_t val) { + if (!*ok) { + return; + } - if (*buf + 1 > end) { - *ok = false; - return; - } + if (*buf + 1 > end) { + *ok = false; + return; + } - **buf = val; - *buf += 1; + **buf = val; + *buf += 1; } -void ripple_serializeType(bool *ok, uint8_t **buf, const uint8_t *end, const RippleFieldMapping *m) -{ - if (m->key <= 0xf) { - append_u8(ok, buf, end, m->type << 4 | m->key); - return; - } +void ripple_serializeType(bool *ok, uint8_t **buf, const uint8_t *end, + const RippleFieldMapping *m) { + if (m->key <= 0xf) { + append_u8(ok, buf, end, m->type << 4 | m->key); + return; + } - append_u8(ok, buf, end, m->type << 4); - append_u8(ok, buf, end, m->key); + append_u8(ok, buf, end, m->type << 4); + append_u8(ok, buf, end, m->key); } void ripple_serializeInt16(bool *ok, uint8_t **buf, const uint8_t *end, - const RippleFieldMapping *m, int16_t val) -{ - assert(m->type == RFT_INT16 && "wrong type?"); + const RippleFieldMapping *m, int16_t val) { + assert(m->type == RFT_INT16 && "wrong type?"); - ripple_serializeType(ok, buf, end, m); - append_u8(ok, buf, end, (val >> 8) & 0xff); - append_u8(ok, buf, end, val & 0xff); + ripple_serializeType(ok, buf, end, m); + append_u8(ok, buf, end, (val >> 8) & 0xff); + append_u8(ok, buf, end, val & 0xff); } void ripple_serializeInt32(bool *ok, uint8_t **buf, const uint8_t *end, - const RippleFieldMapping *m, int32_t val) -{ - assert(m->type == RFT_INT32 && "wrong type?"); - - ripple_serializeType(ok, buf, end, m); - append_u8(ok, buf, end, (val >> 24) & 0xff); - append_u8(ok, buf, end, (val >> 16) & 0xff); - append_u8(ok, buf, end, (val >> 8) & 0xff); - append_u8(ok, buf, end, val & 0xff); + const RippleFieldMapping *m, int32_t val) { + assert(m->type == RFT_INT32 && "wrong type?"); + + ripple_serializeType(ok, buf, end, m); + append_u8(ok, buf, end, (val >> 24) & 0xff); + append_u8(ok, buf, end, (val >> 16) & 0xff); + append_u8(ok, buf, end, (val >> 8) & 0xff); + append_u8(ok, buf, end, val & 0xff); } void ripple_serializeAmount(bool *ok, uint8_t **buf, const uint8_t *end, - const RippleFieldMapping *m, int64_t amount) -{ - ripple_serializeType(ok, buf, end, m); - - assert(amount >= 0 && "amounts cannot be negative"); - assert(amount <= 100000000000 && "larger amounts not supported"); - uint8_t msb = (amount >> (7 * 8)) & 0xff; - msb &= 0x7f; // Clear first bit, indicating XRP - msb |= 0x40; // Clear second bit, indicating value is positive - - append_u8(ok, buf, end, msb); - append_u8(ok, buf, end, (amount >> (6 * 8)) & 0xff); - append_u8(ok, buf, end, (amount >> (5 * 8)) & 0xff); - append_u8(ok, buf, end, (amount >> (4 * 8)) & 0xff); - append_u8(ok, buf, end, (amount >> (3 * 8)) & 0xff); - append_u8(ok, buf, end, (amount >> (2 * 8)) & 0xff); - append_u8(ok, buf, end, (amount >> (1 * 8)) & 0xff); - append_u8(ok, buf, end, amount & 0xff); + const RippleFieldMapping *m, int64_t amount) { + ripple_serializeType(ok, buf, end, m); + + assert(amount >= 0 && "amounts cannot be negative"); + assert(amount <= 100000000000 && "larger amounts not supported"); + uint8_t msb = (amount >> (7 * 8)) & 0xff; + msb &= 0x7f; // Clear first bit, indicating XRP + msb |= 0x40; // Clear second bit, indicating value is positive + + append_u8(ok, buf, end, msb); + append_u8(ok, buf, end, (amount >> (6 * 8)) & 0xff); + append_u8(ok, buf, end, (amount >> (5 * 8)) & 0xff); + append_u8(ok, buf, end, (amount >> (4 * 8)) & 0xff); + append_u8(ok, buf, end, (amount >> (3 * 8)) & 0xff); + append_u8(ok, buf, end, (amount >> (2 * 8)) & 0xff); + append_u8(ok, buf, end, (amount >> (1 * 8)) & 0xff); + append_u8(ok, buf, end, amount & 0xff); } -void ripple_serializeVarint(bool *ok, uint8_t **buf, const uint8_t *end, int val) -{ - if (val < 0) { - assert(false && "can't serialize 0-valued varint"); - *ok = false; - return; - } - - if (val < 192) { - append_u8(ok, buf, end, val); - return; - } - - if (val <= 12480) { - val -= 193; - append_u8(ok, buf, end, 193 + (val >> 8)); - append_u8(ok, buf, end, val & 0xff); - return; - } - - if (val < 918744) { - assert(*buf + 3 < end && "buffer not long enough"); - val -= 12481; - append_u8(ok, buf, end, 241 + (val >> 16)); - append_u8(ok, buf, end, (val >> 8) & 0xff); - append_u8(ok, buf, end, val & 0xff); - return; - } - - assert(false && "value too large"); +void ripple_serializeVarint(bool *ok, uint8_t **buf, const uint8_t *end, + int val) { + if (val < 0) { + assert(false && "can't serialize 0-valued varint"); *ok = false; + return; + } + + if (val < 192) { + append_u8(ok, buf, end, val); + return; + } + + if (val <= 12480) { + val -= 193; + append_u8(ok, buf, end, 193 + (val >> 8)); + append_u8(ok, buf, end, val & 0xff); + return; + } + + if (val < 918744) { + assert(*buf + 3 < end && "buffer not long enough"); + val -= 12481; + append_u8(ok, buf, end, 241 + (val >> 16)); + append_u8(ok, buf, end, (val >> 8) & 0xff); + append_u8(ok, buf, end, val & 0xff); + return; + } + + assert(false && "value too large"); + *ok = false; } void ripple_serializeBytes(bool *ok, uint8_t **buf, const uint8_t *end, - const uint8_t *bytes, size_t count) -{ - ripple_serializeVarint(ok, buf, end, count); - - if (!*ok || *buf + count > end) { - *ok = false; - assert(false && "buffer not long enough"); - return; - } - - memcpy(*buf, bytes, count); - *buf += count; + const uint8_t *bytes, size_t count) { + ripple_serializeVarint(ok, buf, end, count); + + if (!*ok || *buf + count > end) { + *ok = false; + assert(false && "buffer not long enough"); + return; + } + + memcpy(*buf, bytes, count); + *buf += count; } void ripple_serializeAddress(bool *ok, uint8_t **buf, const uint8_t *end, - const RippleFieldMapping *m, const char *address) -{ - ripple_serializeType(ok, buf, end, m); - - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint32_t addr_raw_len = ripple_decode_check(address, HASHER_SHA2D, - addr_raw, MAX_ADDR_RAW_SIZE); - if (addr_raw_len != 21) { - assert(false && "address has wrong length?"); - *ok = false; - return; - } - - ripple_serializeBytes(ok, buf, end, addr_raw + 1, addr_raw_len - 1); + const RippleFieldMapping *m, const char *address) { + ripple_serializeType(ok, buf, end, m); + + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint32_t addr_raw_len = + ripple_decode_check(address, HASHER_SHA2D, addr_raw, MAX_ADDR_RAW_SIZE); + if (addr_raw_len != 21) { + assert(false && "address has wrong length?"); + *ok = false; + return; + } + + ripple_serializeBytes(ok, buf, end, addr_raw + 1, addr_raw_len - 1); } -void ripple_serializeVL(bool *ok, uint8_t **buf, const uint8_t *end, const RippleFieldMapping *m, - const uint8_t *bytes, size_t count) -{ - ripple_serializeType(ok, buf, end, m); - ripple_serializeBytes(ok, buf, end, bytes, count); +void ripple_serializeVL(bool *ok, uint8_t **buf, const uint8_t *end, + const RippleFieldMapping *m, const uint8_t *bytes, + size_t count) { + ripple_serializeType(ok, buf, end, m); + ripple_serializeBytes(ok, buf, end, bytes, count); } bool ripple_serialize(uint8_t **buf, const uint8_t *end, const RippleSignTx *tx, - const char *source_address, - const uint8_t *pubkey, const uint8_t *sig, size_t sig_len) -{ - bool ok = true; - ripple_serializeInt16(&ok, buf, end, &RFM_type, /*Payment*/0); - if (tx->has_flags) - ripple_serializeInt32(&ok, buf, end, &RFM_flags, tx->flags); - if (tx->has_sequence) - ripple_serializeInt32(&ok, buf, end, &RFM_sequence, tx->sequence); - if (tx->payment.has_destination_tag) - ripple_serializeInt32(&ok, buf, end, &RFM_destinationTag, tx->payment.destination_tag); - if (tx->has_last_ledger_sequence) - ripple_serializeInt32(&ok, buf, end, &RFM_lastLedgerSequence, tx->last_ledger_sequence); - if (tx->payment.has_amount) - ripple_serializeAmount(&ok, buf, end, &RFM_amount, tx->payment.amount); - if (tx->has_fee) - ripple_serializeAmount(&ok, buf, end, &RFM_fee, tx->fee); - if (pubkey) - ripple_serializeVL(&ok, buf, end, &RFM_signingPubKey, pubkey, 33); - if (sig) - ripple_serializeVL(&ok, buf, end, &RFM_txnSignature, sig, sig_len); - if (source_address) - ripple_serializeAddress(&ok, buf, end, &RFM_account, source_address); - if (tx->payment.has_destination) - ripple_serializeAddress(&ok, buf, end, &RFM_destination, tx->payment.destination); - return ok; + const char *source_address, const uint8_t *pubkey, + const uint8_t *sig, size_t sig_len) { + bool ok = true; + ripple_serializeInt16(&ok, buf, end, &RFM_type, /*Payment*/ 0); + if (tx->has_flags) + ripple_serializeInt32(&ok, buf, end, &RFM_flags, tx->flags); + if (tx->has_sequence) + ripple_serializeInt32(&ok, buf, end, &RFM_sequence, tx->sequence); + if (tx->payment.has_destination_tag) + ripple_serializeInt32(&ok, buf, end, &RFM_destinationTag, + tx->payment.destination_tag); + if (tx->has_last_ledger_sequence) + ripple_serializeInt32(&ok, buf, end, &RFM_lastLedgerSequence, + tx->last_ledger_sequence); + if (tx->payment.has_amount) + ripple_serializeAmount(&ok, buf, end, &RFM_amount, tx->payment.amount); + if (tx->has_fee) ripple_serializeAmount(&ok, buf, end, &RFM_fee, tx->fee); + if (pubkey) ripple_serializeVL(&ok, buf, end, &RFM_signingPubKey, pubkey, 33); + if (sig) ripple_serializeVL(&ok, buf, end, &RFM_txnSignature, sig, sig_len); + if (source_address) + ripple_serializeAddress(&ok, buf, end, &RFM_account, source_address); + if (tx->payment.has_destination) + ripple_serializeAddress(&ok, buf, end, &RFM_destination, + tx->payment.destination); + return ok; } -void ripple_signTx(const HDNode *node, RippleSignTx *tx, - RippleSignedTx *resp) { - const curve_info *curve = get_curve_by_name("secp256k1"); - if (!curve) return; - - // Set canonical flag, since trezor-crypto ECDSA implementation returns - // fully-canonical signatures, thereby enforcing it in the transaction - // using the designated flag. - // See: https://github.com/trezor/trezor-crypto/blob/3e8974ff8871263a70b7fbb9a27a1da5b0d810f7/ecdsa.c#L791 - if (!tx->has_flags) { - tx->flags = 0; - tx->has_flags = true; - } - tx->flags |= RIPPLE_FLAG_FULLY_CANONICAL; - - memset(resp->serialized_tx.bytes, 0, sizeof(resp->serialized_tx.bytes)); - - // 'STX' - memcpy(resp->serialized_tx.bytes, "\x53\x54\x58\x00", 4); - - char source_address[MAX_ADDR_SIZE]; - if (!ripple_getAddress(node->public_key, source_address)) - return; - - uint8_t *buf = resp->serialized_tx.bytes + 4; - size_t len = sizeof(resp->serialized_tx.bytes) - 4; - if (!ripple_serialize(&buf, buf + len, tx, source_address, node->public_key, NULL, 0)) - return; - - // Ripple uses the first half of SHA512 - uint8_t hash[64]; - sha512_Raw(resp->serialized_tx.bytes, buf - resp->serialized_tx.bytes, hash); - - uint8_t sig[64]; - if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, sig, NULL, NULL) != 0) { - // Failure - return; - } - - resp->signature.size = ecdsa_sig_to_der(sig, resp->signature.bytes); - resp->has_signature = true; - - memset(resp->serialized_tx.bytes, 0, sizeof(resp->serialized_tx.bytes)); - - buf = resp->serialized_tx.bytes; - len = sizeof(resp->serialized_tx); - if (!ripple_serialize(&buf, buf + len, tx, source_address, node->public_key, - resp->signature.bytes, resp->signature.size)) - return; - - resp->has_serialized_tx = true; - resp->serialized_tx.size = buf - resp->serialized_tx.bytes; +void ripple_signTx(const HDNode *node, RippleSignTx *tx, RippleSignedTx *resp) { + const curve_info *curve = get_curve_by_name("secp256k1"); + if (!curve) return; + + // Set canonical flag, since trezor-crypto ECDSA implementation returns + // fully-canonical signatures, thereby enforcing it in the transaction + // using the designated flag. + // See: + // https://github.com/trezor/trezor-crypto/blob/3e8974ff8871263a70b7fbb9a27a1da5b0d810f7/ecdsa.c#L791 + if (!tx->has_flags) { + tx->flags = 0; + tx->has_flags = true; + } + tx->flags |= RIPPLE_FLAG_FULLY_CANONICAL; + + memset(resp->serialized_tx.bytes, 0, sizeof(resp->serialized_tx.bytes)); + + // 'STX' + memcpy(resp->serialized_tx.bytes, "\x53\x54\x58\x00", 4); + + char source_address[MAX_ADDR_SIZE]; + if (!ripple_getAddress(node->public_key, source_address)) return; + + uint8_t *buf = resp->serialized_tx.bytes + 4; + size_t len = sizeof(resp->serialized_tx.bytes) - 4; + if (!ripple_serialize(&buf, buf + len, tx, source_address, node->public_key, + NULL, 0)) + return; + + // Ripple uses the first half of SHA512 + uint8_t hash[64]; + sha512_Raw(resp->serialized_tx.bytes, buf - resp->serialized_tx.bytes, hash); + + uint8_t sig[64]; + if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, sig, NULL, NULL) != + 0) { + // Failure + return; + } + + resp->signature.size = ecdsa_sig_to_der(sig, resp->signature.bytes); + resp->has_signature = true; + + memset(resp->serialized_tx.bytes, 0, sizeof(resp->serialized_tx.bytes)); + + buf = resp->serialized_tx.bytes; + len = sizeof(resp->serialized_tx); + if (!ripple_serialize(&buf, buf + len, tx, source_address, node->public_key, + resp->signature.bytes, resp->signature.size)) + return; + + resp->has_serialized_tx = true; + resp->serialized_tx.size = buf - resp->serialized_tx.bytes; } diff --git a/lib/firmware/ripple_base58.c b/lib/firmware/ripple_base58.c index 2bc221020..d699fa673 100644 --- a/lib/firmware/ripple_base58.c +++ b/lib/firmware/ripple_base58.c @@ -36,12 +36,11 @@ const char ripple_b58digits_ordered[] = const int8_t ripple_b58digits_map[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, 33, 7, 21, 41, 40, 27, 45, 8, - -1, -1, -1, -1, -1, -1, -1, 54, 10, 38, 12, 14, 47, 15, 16, -1, 17, 18, 19, - 20, 13, -1, 22, 23, 24, 25, 26, 11, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, - -1, 5, 34, 35, 36, 37, 6, 39, 3, 49, 42, 43, -1, 44, 4, 46, 1, 48, 0, 2, 51, - 52, 53, 9, 55, 56, 57, -1, -1, -1, -1, -1 -}; + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, 33, 7, 21, 41, 40, 27, 45, + 8, -1, -1, -1, -1, -1, -1, -1, 54, 10, 38, 12, 14, 47, 15, 16, -1, 17, 18, + 19, 20, 13, -1, 22, 23, 24, 25, 26, 11, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, 5, 34, 35, 36, 37, 6, 39, 3, 49, 42, 43, -1, 44, 4, 46, 1, 48, + 0, 2, 51, 52, 53, 9, 55, 56, 57, -1, -1, -1, -1, -1}; typedef uint64_t b58_maxint_t; typedef uint32_t b58_almostmaxint_t; @@ -180,7 +179,8 @@ bool ripple_b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { } if (zcount) memset(b58, 'r', zcount); - for (i = zcount; j < size; ++i, ++j) b58[i] = ripple_b58digits_ordered[buf[j]]; + for (i = zcount; j < size; ++i, ++j) + b58[i] = ripple_b58digits_ordered[buf[j]]; b58[i] = '\0'; *b58sz = i + 1; @@ -221,4 +221,3 @@ int ripple_decode_check(const char *str, HasherType hasher_type, uint8_t *data, memcpy(data, nd, res - 4); return res - 4; } - diff --git a/lib/firmware/signing.c b/lib/firmware/signing.c index 19b38f872..168bd8919 100644 --- a/lib/firmware/signing.c +++ b/lib/firmware/signing.c @@ -31,6 +31,7 @@ #include "keepkey/firmware/home_sm.h" #include "keepkey/firmware/policy.h" #include "keepkey/firmware/signing.h" +#include "keepkey/firmware/txin_check.h" #include "keepkey/firmware/transaction.h" #include "trezor/crypto/ecdsa.h" #include "trezor/crypto/memzero.h" @@ -48,18 +49,18 @@ static const HDNode *root; static CONFIDENTIAL HDNode node; static bool signing = false; enum { - STAGE_REQUEST_1_INPUT, - STAGE_REQUEST_2_PREV_META, - STAGE_REQUEST_2_PREV_INPUT, - STAGE_REQUEST_2_PREV_OUTPUT, - STAGE_REQUEST_2_PREV_EXTRADATA, - STAGE_REQUEST_3_OUTPUT, - STAGE_REQUEST_4_INPUT, - STAGE_REQUEST_4_OUTPUT, - STAGE_REQUEST_SEGWIT_INPUT, - STAGE_REQUEST_5_OUTPUT, - STAGE_REQUEST_SEGWIT_WITNESS, - STAGE_REQUEST_DECRED_WITNESS + STAGE_REQUEST_1_INPUT, + STAGE_REQUEST_2_PREV_META, + STAGE_REQUEST_2_PREV_INPUT, + STAGE_REQUEST_2_PREV_OUTPUT, + STAGE_REQUEST_2_PREV_EXTRADATA, + STAGE_REQUEST_3_OUTPUT, + STAGE_REQUEST_4_INPUT, + STAGE_REQUEST_4_OUTPUT, + STAGE_REQUEST_SEGWIT_INPUT, + STAGE_REQUEST_5_OUTPUT, + STAGE_REQUEST_SEGWIT_WITNESS, + STAGE_REQUEST_DECRED_WITNESS } signing_stage; static uint32_t idx1, idx2; static uint32_t signatures; @@ -70,10 +71,10 @@ static TxStruct to, tp, ti; static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; -static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; +static uint8_t hash_prevouts[32], hash_sequence[32], hash_outputs[32]; static uint8_t hash_prefix[32]; static uint8_t hash_check[32]; -static uint64_t to_spend, authorized_amount, spending, change_spend; +static uint64_t to_spend, authorized_bip143_in, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; static uint32_t expiry = 0; @@ -92,9 +93,9 @@ static uint32_t tx_weight; input */ #define BIP32_NOCHANGEALLOWED 1 /* The number of bip32 levels used in a wallet (chain and address) */ -#define BIP32_WALLET_DEPTH 2 +#define BIP32_WALLET_DEPTH 2 /* The chain id used for change */ -#define BIP32_CHANGE_CHAIN 1 +#define BIP32_CHANGE_CHAIN 1 /* The maximum allowed change address. This should be large enough for normal use and still allow to quickly brute-force the correct bip32 path. */ #define BIP32_MAX_LAST_ELEMENT 1000000 @@ -107,17 +108,16 @@ static uint32_t tx_weight; #define TXSIZE_SEGWIT_OVERHEAD 2 enum { - SIGHASH_ALL = 1, - SIGHASH_FORKID = 0x40, + SIGHASH_ALL = 1, + SIGHASH_FORKID = 0x40, }; enum { - DECRED_SERIALIZE_FULL = 0, - DECRED_SERIALIZE_NO_WITNESS = 1, - DECRED_SERIALIZE_WITNESS_SIGNING = 3, + DECRED_SERIALIZE_FULL = 0, + DECRED_SERIALIZE_NO_WITNESS = 1, + DECRED_SERIALIZE_WITNESS_SIGNING = 3, }; - /* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. */ @@ -131,60 +131,75 @@ enum { * OUTPUT * none */ -void send_fsm_co_error_message(int co_error) -{ - struct { - int code; - const char *msg; - FailureType type; - } errorCodes[] = { - { TXOUT_COMPILE_ERROR, "Failed to compile output", FailureType_Failure_Other }, - { TXOUT_CANCEL, "Transaction cancelled", FailureType_Failure_ActionCancelled }, - }; - - for (size_t i = 0; i < sizeof(errorCodes)/sizeof(errorCodes[0]); i++) { - if (errorCodes[i].code == co_error) { +void send_fsm_co_error_message(int co_error) { + struct { + int code; + const char *msg; + FailureType type; + } errorCodes[] = { + {TXOUT_COMPILE_ERROR, "Failed to compile output", + FailureType_Failure_Other}, + {TXOUT_CANCEL, "Transaction cancelled", + FailureType_Failure_ActionCancelled}, + }; + + for (size_t i = 0; i < sizeof(errorCodes) / sizeof(errorCodes[0]); i++) { + if (errorCodes[i].code == co_error) { #if DEBUG_LINK - fsm_sendFailureDebug(errorCodes[i].type, errorCodes[i].msg, get_exchange_msg()); + fsm_sendFailureDebug(errorCodes[i].type, errorCodes[i].msg, + get_exchange_msg()); #else - fsm_sendFailure(errorCodes[i].type, errorCodes[i].msg); + fsm_sendFailure(errorCodes[i].type, errorCodes[i].msg); #endif - return; - } - } - - struct { - ExchangeError code; - const char *msg; - FailureType type; - } exchangeCodes[] = { - { ERROR_EXCHANGE_SIGNATURE, "Exchange signature error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_DEPOSIT_COINTYPE, "Exchange deposit coin type error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_DEPOSIT_ADDRESS, "Exchange deposit address error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_DEPOSIT_AMOUNT, "Exchange deposit amount error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_WITHDRAWAL_COINTYPE, "Exchange withdrawal coin type error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_WITHDRAWAL_ADDRESS, "Exchange withdrawal address error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_WITHDRAWAL_AMOUNT, "Exchange withdrawal amount error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_RETURN_ADDRESS, "Exchange return address error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_RETURN_COINTYPE, "Exchange return coin type error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_CANCEL, "Exchange transaction cancelled", FailureType_Failure_ActionCancelled }, - { ERROR_EXCHANGE_RESPONSE_STRUCTURE, "Obsolete Response structure error", FailureType_Failure_Other }, - { ERROR_EXCHANGE_TYPE, "Unknown exchange type", FailureType_Failure_Other }, - }; - - ExchangeError error = get_exchange_error(); - for (size_t i = 0; i < sizeof(exchangeCodes)/sizeof(exchangeCodes[0]); i++) { - if (exchangeCodes[i].code == error) { + return; + } + } + + struct { + ExchangeError code; + const char *msg; + FailureType type; + } exchangeCodes[] = { + {ERROR_EXCHANGE_SIGNATURE, "Exchange signature error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_DEPOSIT_COINTYPE, "Exchange deposit coin type error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_DEPOSIT_ADDRESS, "Exchange deposit address error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_DEPOSIT_AMOUNT, "Exchange deposit amount error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_WITHDRAWAL_COINTYPE, + "Exchange withdrawal coin type error", FailureType_Failure_Other}, + {ERROR_EXCHANGE_WITHDRAWAL_ADDRESS, "Exchange withdrawal address error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_WITHDRAWAL_AMOUNT, "Exchange withdrawal amount error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_RETURN_ADDRESS, "Exchange return address error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_RETURN_COINTYPE, "Exchange return coin type error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_CANCEL, "Exchange transaction cancelled", + FailureType_Failure_ActionCancelled}, + {ERROR_EXCHANGE_RESPONSE_STRUCTURE, "Obsolete Response structure error", + FailureType_Failure_Other}, + {ERROR_EXCHANGE_TYPE, "Unknown exchange type", FailureType_Failure_Other}, + }; + + ExchangeError error = get_exchange_error(); + for (size_t i = 0; i < sizeof(exchangeCodes) / sizeof(exchangeCodes[0]); + i++) { + if (exchangeCodes[i].code == error) { #if DEBUG_LINK - fsm_sendFailureDebug(exchangeCodes[i].type, exchangeCodes[i].msg, get_exchange_msg()); + fsm_sendFailureDebug(exchangeCodes[i].type, exchangeCodes[i].msg, + get_exchange_msg()); #else - fsm_sendFailure(exchangeCodes[i].type, exchangeCodes[i].msg); + fsm_sendFailure(exchangeCodes[i].type, exchangeCodes[i].msg); #endif - return; - } - } + return; + } + } - fsm_sendFailure(FailureType_Failure_Other, "Unknown TxOut compilation error"); + fsm_sendFailure(FailureType_Failure_Other, "Unknown TxOut compilation error"); } /* @@ -201,29 +216,20 @@ Phase1 - check inputs, previous transactions, and outputs ========================================================= foreach I (idx1): - Request I STAGE_REQUEST_1_INPUT - Add I to segwit hash_prevouts, hash_sequence + Request I STAGE_REQUEST_1_INPUT Add I to segwit hash_prevouts, hash_sequence Add I to Decred hash_prefix Add I to TransactionChecksum (prevout and type) if (Decred) Return I If not segwit, Calculate amount of I: - Request prevhash I, META STAGE_REQUEST_2_PREV_META - foreach prevhash I (idx2): - Request prevhash I STAGE_REQUEST_2_PREV_INPUT - foreach prevhash O (idx2): - Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT - Add amount of prevhash O (which is amount of I) - Request prevhash extra data (if applicable) STAGE_REQUEST_2_PREV_EXTRADATA - Calculate hash of streamed tx, compare to prevhash I -foreach O (idx1): - Request O STAGE_REQUEST_3_OUTPUT - Add O to Decred hash_prefix - Add O to TransactionChecksum - if (Decred) - Return O - Display output - Ask for confirmation + Request prevhash I, META STAGE_REQUEST_2_PREV_META foreach prevhash I +(idx2): Request prevhash I STAGE_REQUEST_2_PREV_INPUT foreach prevhash O (idx2): + Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT Add amount of +prevhash O (which is amount of I) Request prevhash extra data (if applicable) +STAGE_REQUEST_2_PREV_EXTRADATA Calculate hash of streamed tx, compare to +prevhash I foreach O (idx1): Request O STAGE_REQUEST_3_OUTPUT Add O to Decred +hash_prefix Add O to TransactionChecksum if (Decred) Return O Display output Ask +for confirmation Check tx fee Ask for confirmation @@ -236,21 +242,17 @@ if (Decred) foreach I (idx1): // input to sign if (idx1 is segwit) - Request I STAGE_REQUEST_SEGWIT_INPUT - Return serialized input chunk + Request I STAGE_REQUEST_SEGWIT_INPUT Return serialized input chunk else foreach I (idx2): - Request I STAGE_REQUEST_4_INPUT - If idx1 == idx2 - Fill scriptsig + Request I STAGE_REQUEST_4_INPUT If idx1 == idx2 Fill scriptsig Remember key for signing Add I to StreamTransactionSign Add I to TransactionChecksum foreach O (idx2): - Request O STAGE_REQUEST_4_OUTPUT - Add O to StreamTransactionSign - Add O to TransactionChecksum + Request O STAGE_REQUEST_4_OUTPUT Add O to StreamTransactionSign Add +O to TransactionChecksum Compare TransactionChecksum with checksum computed in Phase 1 If different: @@ -259,208 +261,191 @@ foreach I (idx1): // input to sign Return signed chunk foreach O (idx1): - Request O STAGE_REQUEST_5_OUTPUT - Rewrite change address - Return O + Request O STAGE_REQUEST_5_OUTPUT Rewrite change address Return O Phase3: sign segwit inputs, check that nothing changed =============================================== foreach I (idx1): // input to sign - Request I STAGE_REQUEST_SEGWIT_WITNESS - Check amount - Sign segwit prevhash, sequence, amount, outputs - Return witness + Request I STAGE_REQUEST_SEGWIT_WITNESS Check amount Sign segwit prevhash, +sequence, amount, outputs Return witness Phase3: sign Decred inputs ========================== -foreach I (idx1): // input to sign STAGE_REQUEST_DECRED_WITNESS - Request I - Fill scriptSig - Compute hash_witness +foreach I (idx1): // input to sign STAGE_REQUEST_DECRED_WITNESS Request I Fill +scriptSig Compute hash_witness Sign (hash_type || hash_prefix || hash_witness) Return witness */ -void send_req_1_input(void) -{ - signing_stage = STAGE_REQUEST_1_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_1_input(void) { + signing_stage = STAGE_REQUEST_1_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_meta(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_META; - resp.has_request_type = true; - resp.request_type = RequestType_TXMETA; - resp.has_details = true; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, input.prev_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_meta(void) { + signing_stage = STAGE_REQUEST_2_PREV_META; + resp.has_request_type = true; + resp.request_type = RequestType_TXMETA; + resp.has_details = true; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + input.prev_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_input(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_input(void) { + signing_stage = STAGE_REQUEST_2_PREV_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_output(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_output(void) { + signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) -{ - signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; - resp.has_request_type = true; - resp.request_type = RequestType_TXEXTRADATA; - resp.has_details = true; - resp.details.has_extra_data_offset = true; - resp.details.extra_data_offset = chunk_offset; - resp.details.has_extra_data_len = true; - resp.details.extra_data_len = chunk_len; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) { + signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; + resp.has_request_type = true; + resp.request_type = RequestType_TXEXTRADATA; + resp.has_details = true; + resp.details.has_extra_data_offset = true; + resp.details.extra_data_offset = chunk_offset; + resp.details.has_extra_data_len = true; + resp.details.extra_data_len = chunk_len; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_3_output(void) -{ - signing_stage = STAGE_REQUEST_3_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_3_output(void) { + signing_stage = STAGE_REQUEST_3_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_4_input(void) -{ - signing_stage = STAGE_REQUEST_4_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_4_input(void) { + signing_stage = STAGE_REQUEST_4_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_4_output(void) -{ - signing_stage = STAGE_REQUEST_4_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_4_output(void) { + signing_stage = STAGE_REQUEST_4_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_segwit_input(void) -{ - signing_stage = STAGE_REQUEST_SEGWIT_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_segwit_input(void) { + signing_stage = STAGE_REQUEST_SEGWIT_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_segwit_witness(void) -{ - signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_segwit_witness(void) { + signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_decred_witness(void) -{ - signing_stage = STAGE_REQUEST_DECRED_WITNESS; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_decred_witness(void) { + signing_stage = STAGE_REQUEST_DECRED_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_5_output(void) -{ - signing_stage = STAGE_REQUEST_5_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_5_output(void) { + signing_stage = STAGE_REQUEST_5_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_finished(void) -{ - resp.has_request_type = true; - resp.request_type = RequestType_TXFINISHED; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_finished(void) { + resp.has_request_type = true; + resp.request_type = RequestType_TXFINISHED; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void phase1_request_next_input(void) -{ - if (idx1 < inputs_count - 1) { - idx1++; - send_req_1_input(); - } else { - // compute segwit hashPrevouts & hashSequence - hasher_Final(&hasher_prevouts, hash_prevouts); - hasher_Final(&hasher_sequence, hash_sequence); - hasher_Final(&hasher_check, hash_check); - // init hashOutputs - hasher_Reset(&hasher_outputs); - idx1 = 0; - send_req_3_output(); - } +void phase1_request_next_input(void) { + if (idx1 < inputs_count - 1) { + idx1++; + send_req_1_input(); + } else { + // compute segwit hashPrevouts & hashSequence + hasher_Final(&hasher_prevouts, hash_prevouts); + hasher_Final(&hasher_sequence, hash_sequence); + hasher_Final(&hasher_check, hash_check); + // init hashOutputs + hasher_Reset(&hasher_outputs); + idx1 = 0; + send_req_3_output(); + } } -void phase2_request_next_input(void) -{ - if (idx1 == next_nonsegwit_input) { - idx2 = 0; - send_req_4_input(); - } else { - send_req_segwit_input(); - } +void phase2_request_next_input(void) { + if (idx1 == next_nonsegwit_input) { + idx2 = 0; + send_req_4_input(); + } else { + send_req_segwit_input(); + } } /// Compares two BIP32 paths, returning true iff there is something mismatched @@ -468,1165 +453,1477 @@ void phase2_request_next_input(void) static bool isCrossAccountSegwitChangeForbidden( const uint32_t *lhs_address_n, size_t lhs_address_n_count, const uint32_t *rhs_address_n, size_t rhs_address_n_count, - OutputScriptType rhs_script_type) -{ - (void)lhs_address_n; + OutputScriptType rhs_script_type) { + (void)lhs_address_n; - size_t count = rhs_address_n_count; - if (count < 5) - return false; + size_t count = rhs_address_n_count; + if (count < 5) return false; - if (count != lhs_address_n_count) - return false; + if (count != lhs_address_n_count) return false; - // purpose - uint32_t out_purpose = rhs_address_n[count - 5]; + // purpose + uint32_t out_purpose = rhs_address_n[count - 5]; - // Don't allow *creating* mixed-mode change if the script type doesn't - // match the purpose. On the other hand, we allow spending it even if - // it is "wrong". - if (out_purpose == (0x80000000|44) && - rhs_script_type != OutputScriptType_PAYTOADDRESS) - return true; + // Don't allow *creating* mixed-mode change if the script type doesn't + // match the purpose. On the other hand, we allow spending it even if + // it is "wrong". + if (out_purpose == (0x80000000 | 44) && + rhs_script_type != OutputScriptType_PAYTOADDRESS) + return true; - if (out_purpose == (0x80000000|49) && - rhs_script_type != OutputScriptType_PAYTOP2SHWITNESS) - return true; + if (out_purpose == (0x80000000 | 49) && + rhs_script_type != OutputScriptType_PAYTOP2SHWITNESS) + return true; - if (out_purpose == (0x80000000|84) && - rhs_script_type != OutputScriptType_PAYTOWITNESS) - return true; + if (out_purpose == (0x80000000 | 84) && + rhs_script_type != OutputScriptType_PAYTOWITNESS) + return true; - return false; + return false; } /// Compares two BIP32 paths, returning true iff the paths match for mixed-mode /// p2pkh + ph2sh-p2wsh + p2wsh accounts. -static bool isCrossAccountSegwitChangeAllowed( - const uint32_t *lhs_address_n, size_t lhs_address_n_count, - const uint32_t *rhs_address_n, size_t rhs_address_n_count) -{ - size_t count = rhs_address_n_count; - if (count < 5) - return false; - - if (count != lhs_address_n_count) - return false; - - // Only do this for coins that support segwit - if (!coin->has_segwit || !coin->segwit) - return false; - - // purpose - uint32_t in_purpose = lhs_address_n[count - 5]; - if (in_purpose != (0x80000000|44) && - in_purpose != (0x80000000|49) && - in_purpose != (0x80000000|84)) - return false; - - uint32_t out_purpose = rhs_address_n[count - 5]; - if (out_purpose != (0x80000000|44) && - out_purpose != (0x80000000|49) && - out_purpose != (0x80000000|84)) - return false; - - // coin_type - if (lhs_address_n[count - 4] != rhs_address_n[count - 4]) - return false; - - // account - if (lhs_address_n[count - 3] != rhs_address_n[count - 3]) - return false; - - // change - if (BIP32_CHANGE_CHAIN < lhs_address_n[count - 2] || - BIP32_CHANGE_CHAIN < rhs_address_n[count - 2]) - return false; - - // address_index - if (BIP32_MAX_LAST_ELEMENT < lhs_address_n[count - 1] || - BIP32_MAX_LAST_ELEMENT < rhs_address_n[count - 1]) - return false; - - return true; +static bool isCrossAccountSegwitChangeAllowed(const uint32_t *lhs_address_n, + size_t lhs_address_n_count, + const uint32_t *rhs_address_n, + size_t rhs_address_n_count) { + size_t count = rhs_address_n_count; + if (count < 5) return false; + + if (count != lhs_address_n_count) return false; + + // Only do this for coins that support segwit + if (!coin->has_segwit || !coin->segwit) return false; + + // purpose + uint32_t in_purpose = lhs_address_n[count - 5]; + if (in_purpose != (0x80000000 | 44) && in_purpose != (0x80000000 | 49) && + in_purpose != (0x80000000 | 84)) + return false; + + uint32_t out_purpose = rhs_address_n[count - 5]; + if (out_purpose != (0x80000000 | 44) && out_purpose != (0x80000000 | 49) && + out_purpose != (0x80000000 | 84)) + return false; + + // coin_type + if (lhs_address_n[count - 4] != rhs_address_n[count - 4]) return false; + + // account + if (lhs_address_n[count - 3] != rhs_address_n[count - 3]) return false; + + // change + if (BIP32_CHANGE_CHAIN < lhs_address_n[count - 2] || + BIP32_CHANGE_CHAIN < rhs_address_n[count - 2]) + return false; + + // address_index + if (BIP32_MAX_LAST_ELEMENT < lhs_address_n[count - 1] || + BIP32_MAX_LAST_ELEMENT < rhs_address_n[count - 1]) + return false; + + return true; +} + +void extract_input_bip32_path(const TxInputType *tinput) { + if (in_address_n_count == BIP32_NOCHANGEALLOWED) { + return; + } + size_t count = tinput->address_n_count; + if (count < BIP32_WALLET_DEPTH) { + // no change address allowed + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } + if (in_address_n_count == 0) { + // initialize in_address_n on first input seen + in_address_n_count = count; + // store the bip32 path up to the account + memcpy(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)); + return; + } + // check that all addresses use a path of same length + if (in_address_n_count != count) { + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } + if (isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, + tinput->address_n, + tinput->address_n_count)) + return; + // check that the bip32 path up to the account matches + if (memcmp(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) != 0) { + // mismatch -> no change address allowed + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } } -void extract_input_bip32_path(const TxInputType *tinput) -{ - if (in_address_n_count == BIP32_NOCHANGEALLOWED) { - return; - } - size_t count = tinput->address_n_count; - if (count < BIP32_WALLET_DEPTH) { - // no change address allowed - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } - if (in_address_n_count == 0) { - // initialize in_address_n on first input seen - in_address_n_count = count; - // store the bip32 path up to the account - memcpy(in_address_n, tinput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)); - return; - } - // check that all addresses use a path of same length - if (in_address_n_count != count) { - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } - if (isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, - tinput->address_n, tinput->address_n_count)) - return; - // check that the bip32 path up to the account matches - if (memcmp(in_address_n, tinput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) != 0) { - // mismatch -> no change address allowed - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } +bool check_change_bip32_path(const TxOutputType *toutput) { + if (isCrossAccountSegwitChangeForbidden( + in_address_n, in_address_n_count, toutput->address_n, + toutput->address_n_count, toutput->script_type)) + return false; + + if (isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, + toutput->address_n, + toutput->address_n_count)) + return true; + + size_t count = toutput->address_n_count; + + // Check that the change path has the same bip32 path length, + // the same path up to the account, and that the wallet components + // (chain id and address) are as expected. + // Note: count >= BIP32_WALLET_DEPTH and count == in_address_n_count + // imply that in_address_n_count != BIP32_NOCHANGEALLOWED + return (count >= BIP32_WALLET_DEPTH && count == in_address_n_count && + 0 == memcmp(in_address_n, toutput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) && + toutput->address_n[count - 2] <= BIP32_CHANGE_CHAIN && + toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } -bool check_change_bip32_path(const TxOutputType *toutput) -{ - if (isCrossAccountSegwitChangeForbidden( - in_address_n, in_address_n_count, - toutput->address_n, toutput->address_n_count, - toutput->script_type)) - return false; - - if (isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, - toutput->address_n, toutput->address_n_count)) - return true; - - size_t count = toutput->address_n_count; - - // Check that the change path has the same bip32 path length, - // the same path up to the account, and that the wallet components - // (chain id and address) are as expected. - // Note: count >= BIP32_WALLET_DEPTH and count == in_address_n_count - // imply that in_address_n_count != BIP32_NOCHANGEALLOWED - return (count >= BIP32_WALLET_DEPTH - && count == in_address_n_count - && 0 == memcmp(in_address_n, toutput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) - && toutput->address_n[count - 2] <= BIP32_CHANGE_CHAIN - && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); +bool compile_input_script_sig(TxInputType *tinput) { + if (!multisig_fp_mismatch) { + // check that this is still multisig + uint8_t h[32]; + if (!tinput->has_multisig || + cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 || + memcmp(multisig_fp, h, 32) != 0) { + // Transaction has changed during signing + return false; + } + } + if (in_address_n_count != BIP32_NOCHANGEALLOWED) { + // check that input address didn't change + size_t count = tinput->address_n_count; + if (count < 2 || count != in_address_n_count || + (0 != memcmp(in_address_n, tinput->address_n, + (count - 2) * sizeof(uint32_t)) && + !isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, + tinput->address_n, + tinput->address_n_count))) { + return false; + } + } + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, tinput->address_n, + tinput->address_n_count, NULL) == 0) { + // Failed to derive private key + return false; + } + hdnode_fill_public_key(&node); + if (tinput->has_multisig) { + tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), + tinput->script_sig.bytes); + } else { // SPENDADDRESS + uint8_t hash[20]; + ecdsa_get_pubkeyhash(node.public_key, curve->hasher_pubkey, hash); + tinput->script_sig.size = + compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); + } + return tinput->script_sig.size > 0; } -bool compile_input_script_sig(TxInputType *tinput) -{ - if (!multisig_fp_mismatch) { - // check that this is still multisig - uint8_t h[32]; - if (!tinput->has_multisig - || cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 - || memcmp(multisig_fp, h, 32) != 0) { - // Transaction has changed during signing - return false; - } - } - if (in_address_n_count != BIP32_NOCHANGEALLOWED) { - // check that input address didn't change - size_t count = tinput->address_n_count; - if (count < 2 - || count != in_address_n_count - || (0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) && - !isCrossAccountSegwitChangeAllowed(in_address_n, in_address_n_count, - tinput->address_n, tinput->address_n_count))) { - return false; - } - } - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count, NULL) == 0) { - // Failed to derive private key - return false; - } - hdnode_fill_public_key(&node); - if (tinput->has_multisig) { - tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), tinput->script_sig.bytes); - } else { // SPENDADDRESS - uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, curve->hasher_pubkey, hash); - tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); - } - return tinput->script_sig.size > 0; +void signing_init(const SignTx *msg, const CoinType *_coin, + const HDNode *_root) { + inputs_count = msg->inputs_count; + outputs_count = msg->outputs_count; + coin = _coin; + root = _root; + version = msg->version; + lock_time = msg->lock_time; + expiry = msg->expiry; + overwintered = msg->has_overwintered && msg->overwintered; + version_group_id = msg->version_group_id; + branch_id = msg->branch_id; + // set default values for Zcash if branch_id is unset + if (overwintered && (branch_id == 0)) { + switch (version) { + case 3: + branch_id = 0x5BA81B19; // Overwinter + break; + case 4: + branch_id = 0x76B809BB; // Sapling + break; + } + } + + uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + + ser_length_size(inputs_count) + + ser_length_size(outputs_count); + if (coin->decred) { + size += 4; // Decred expiry + size += ser_length_size(inputs_count); // Witness inputs count + } + + tx_weight = 4 * size; + + signatures = 0; + idx1 = 0; + to_spend = 0; + spending = 0; + change_spend = 0; + authorized_bip143_in = 0; + memset(&input, 0, sizeof(TxInputType)); + memset(&resp, 0, sizeof(TxRequest)); + + signing = true; + progress = 0; + // we step by 500/inputs_count per input in phase1 and phase2 + // this means 50 % per phase. + progress_step = (500 << PROGRESS_PRECISION) / inputs_count; + + in_address_n_count = 0; + multisig_fp_set = false; + multisig_fp_mismatch = false; + next_nonsegwit_input = 0xffffffff; + + curve = get_curve_by_name(coin->curve_name); + if (!curve) curve = get_curve_by_name(SECP256K1_NAME); + + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, + curve->hasher_sign, overwintered, version_group_id); + + if (coin->decred) { + to.version |= (DECRED_SERIALIZE_FULL << 16); + to.is_decred = true; + + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + curve->hasher_sign, overwintered, version_group_id); + ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + ti.is_decred = true; + } + + // segwit hashes for hashPrevouts and hashSequence + if (overwintered) { + hasher_InitParam(&hasher_prevouts, HASHER_BLAKE2B_PERSONAL, + "ZcashPrevoutHash", 16); + hasher_InitParam(&hasher_sequence, HASHER_BLAKE2B_PERSONAL, + "ZcashSequencHash", 16); + hasher_InitParam(&hasher_outputs, HASHER_BLAKE2B_PERSONAL, + "ZcashOutputsHash", 16); + hasher_Init(&hasher_check, curve->hasher_sign); + } else { + hasher_Init(&hasher_prevouts, curve->hasher_sign); + hasher_Init(&hasher_sequence, curve->hasher_sign); + hasher_Init(&hasher_outputs, curve->hasher_sign); + hasher_Init(&hasher_check, curve->hasher_sign); + } + + layoutProgressSwipe(_("Signing transaction"), 0); + + send_req_1_input(); + set_exchange_error(NO_EXCHANGE_ERROR); } -void signing_init(const SignTx *msg, const CoinType *_coin, const HDNode *_root) -{ - inputs_count = msg->inputs_count; - outputs_count = msg->outputs_count; - coin = _coin; - root = _root; - version = msg->version; - lock_time = msg->lock_time; - expiry = msg->expiry; - overwintered = msg->has_overwintered && msg->overwintered; - version_group_id = msg->version_group_id; - branch_id = msg->branch_id; - // set default values for Zcash if branch_id is unset - if (overwintered && (branch_id == 0)) { - switch (version) { - case 3: - branch_id = 0x5BA81B19; // Overwinter - break; - case 4: - branch_id = 0x76B809BB; // Sapling - break; - } - } - - uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); - if (coin->decred) { - size += 4; // Decred expiry - size += ser_length_size(inputs_count); // Witness inputs count - } - - tx_weight = 4 * size; - - signatures = 0; - idx1 = 0; - to_spend = 0; - spending = 0; - change_spend = 0; - authorized_amount = 0; - memset(&input, 0, sizeof(TxInputType)); - memset(&resp, 0, sizeof(TxRequest)); - - signing = true; - progress = 0; - // we step by 500/inputs_count per input in phase1 and phase2 - // this means 50 % per phase. - progress_step = (500 << PROGRESS_PRECISION) / inputs_count; - - in_address_n_count = 0; - multisig_fp_set = false; - multisig_fp_mismatch = false; - next_nonsegwit_input = 0xffffffff; - - curve = get_curve_by_name(coin->curve_name); - if (!curve) - curve = get_curve_by_name(SECP256K1_NAME); - - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, curve->hasher_sign, overwintered, version_group_id); - - if (coin->decred) { - to.version |= (DECRED_SERIALIZE_FULL << 16); - to.is_decred = true; - - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, curve->hasher_sign, overwintered, version_group_id); - ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); - ti.is_decred = true; - } - - // segwit hashes for hashPrevouts and hashSequence - if (overwintered) { - hasher_InitParam(&hasher_prevouts, HASHER_BLAKE2B_PERSONAL, "ZcashPrevoutHash", 16); - hasher_InitParam(&hasher_sequence, HASHER_BLAKE2B_PERSONAL, "ZcashSequencHash", 16); - hasher_InitParam(&hasher_outputs, HASHER_BLAKE2B_PERSONAL, "ZcashOutputsHash", 16); - hasher_Init(&hasher_check, curve->hasher_sign); - } else { - hasher_Init(&hasher_prevouts, curve->hasher_sign); - hasher_Init(&hasher_sequence, curve->hasher_sign); - hasher_Init(&hasher_outputs, curve->hasher_sign); - hasher_Init(&hasher_check, curve->hasher_sign); - } - - layoutProgressSwipe(_("Signing transaction"), 0); - - send_req_1_input(); - set_exchange_error(NO_EXCHANGE_ERROR); +static bool is_multisig_input_script_type(const TxInputType *txinput) { + if (txinput->script_type == InputScriptType_SPENDMULTISIG || + txinput->script_type == InputScriptType_SPENDP2SHWITNESS || + txinput->script_type == InputScriptType_SPENDWITNESS) { + return true; + } + return false; +} + +static bool is_multisig_output_script_type(const TxOutputType *txoutput) { + if (txoutput->script_type == OutputScriptType_PAYTOMULTISIG || + txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS || + txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + return true; + } + return false; +} + +static bool is_internal_input_script_type(const TxInputType *txinput) { + if (txinput->script_type == InputScriptType_SPENDADDRESS || + txinput->script_type == InputScriptType_SPENDMULTISIG || + txinput->script_type == InputScriptType_SPENDP2SHWITNESS || + txinput->script_type == InputScriptType_SPENDWITNESS) { + return true; + } + return false; +} + +static bool is_change_output_script_type(const TxOutputType *txoutput) { + if (txoutput->script_type == OutputScriptType_PAYTOADDRESS || + txoutput->script_type == OutputScriptType_PAYTOMULTISIG || + txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS || + txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + return true; + } + return false; +} + +static bool is_segwit_input_script_type(const TxInputType *txinput) { + if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS || + txinput->script_type == InputScriptType_SPENDWITNESS) { + return true; + } + return false; +} + +static bool signing_validate_input(const TxInputType *txinput) { + if (txinput->prev_hash.size != 32) { + fsm_sendFailure(FailureType_Failure_Other, + _("Encountered invalid prevhash")); + signing_abort(); + return false; + } + if (txinput->has_multisig && !is_multisig_input_script_type(txinput)) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Multisig field provided but not expected.")); + signing_abort(); + return false; + } + if (txinput->address_n_count > 0 && !is_internal_input_script_type(txinput)) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + "Input's address_n provided but not expected."); + signing_abort(); + return false; + } + if (!coin->decred && txinput->has_decred_script_version) { + fsm_sendFailure( + FailureType_Failure_UnexpectedMessage, + _("Decred details provided but Decred coin not specified.")); + signing_abort(); + return false; + } + + if (coin->force_bip143 || overwintered) { + if (!txinput->has_amount) { + fsm_sendFailure(FailureType_Failure_Other, + _("Expected input with amount")); + signing_abort(); + return false; + } + } + + if (is_segwit_input_script_type(txinput)) { + if (!coin->has_segwit) { + fsm_sendFailure(FailureType_Failure_Other, + _("Segwit not enabled on this coin")); + signing_abort(); + return false; + } + if (!txinput->has_amount) { + fsm_sendFailure(FailureType_Failure_Other, + _("Segwit input without amount")); + signing_abort(); + return false; + } + } + + return true; +} + +static bool signing_validate_output(TxOutputType *txoutput) { + if (txoutput->has_multisig && !is_multisig_output_script_type(txoutput)) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Multisig field provided but not expected.")); + signing_abort(); + return false; + } + + if (txoutput->address_n_count > 0 && + !is_change_output_script_type(txoutput)) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Output's address_n provided but not expected.")); + signing_abort(); + return false; + } + + if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { + if (txoutput->has_address || (txoutput->address_n_count > 0) || + txoutput->has_multisig) { + fsm_sendFailure(FailureType_Failure_Other, + _("OP_RETURN output with address or multisig")); + signing_abort(); + return false; + } + if (txoutput->amount != 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("OP_RETURN output with non-zero amount")); + signing_abort(); + return false; + } + } else { + if (txoutput->has_op_return_data) { + fsm_sendFailure( + FailureType_Failure_UnexpectedMessage, + _("OP RETURN data provided but not OP RETURN script type.")); + signing_abort(); + return false; + } + if (txoutput->has_address && txoutput->address_n_count > 0) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Both address and address_n provided.")); + signing_abort(); + return false; + } else if (!txoutput->has_address && txoutput->address_n_count == 0) { + fsm_sendFailure(FailureType_Failure_Other, _("Missing address")); + signing_abort(); + return false; + } + } + return true; +} + +static bool signing_validate_bin_output(TxOutputBinType *tx_bin_output) { + if (!coin->decred && tx_bin_output->has_decred_script_version) { + fsm_sendFailure( + FailureType_Failure_UnexpectedMessage, + _("Decred details provided but Decred coin not specified.")); + signing_abort(); + return false; + } + return true; } static bool signing_check_input(TxInputType *txinput) { - /* compute multisig fingerprint */ - /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (txinput->has_multisig && !multisig_fp_mismatch) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Error computing multisig fingerprint")); - signing_abort(); - return false; - } - if (multisig_fp_set) { - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - memcpy(multisig_fp, h, 32); - multisig_fp_set = true; - } - } else { // single signature - multisig_fp_mismatch = true; - } - // remember the input bip32 path - // change addresses must use the same bip32 path as all inputs - extract_input_bip32_path(txinput); - // compute segwit hashPrevouts & hashSequence - tx_prevout_hash(&hasher_prevouts, txinput); - tx_sequence_hash(&hasher_sequence, txinput); - if (coin->decred) { - if (txinput->decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Decred v1+ scripts are not supported")); - signing_abort(); - return false; - } - - // serialize Decred prefix in Phase 1 - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_input(&to, txinput, resp.serialized.serialized_tx.bytes); - - // compute Decred hashPrefix - tx_serialize_input_hash(&ti, txinput); - } - // hash prevout and script type to check it later (relevant for fee computation) - tx_prevout_hash(&hasher_check, txinput); - hasher_Update(&hasher_check, (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); - return true; + /* compute multisig fingerprint */ + /* (if all input share the same fingerprint, outputs having the same + * fingerprint will be considered as change outputs) */ + if (txinput->has_multisig && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Error computing multisig fingerprint")); + signing_abort(); + return false; + } + if (multisig_fp_set) { + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + memcpy(multisig_fp, h, 32); + multisig_fp_set = true; + } + } else { // single signature + multisig_fp_mismatch = true; + } + // remember the input bip32 path + // change addresses must use the same bip32 path as all inputs + extract_input_bip32_path(txinput); + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hasher_prevouts, txinput); + tx_sequence_hash(&hasher_sequence, txinput); + if (coin->decred) { + if (txinput->decred_script_version > 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Decred v1+ scripts are not supported")); + signing_abort(); + return false; + } + + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = + tx_serialize_input(&to, txinput, resp.serialized.serialized_tx.bytes); + + // compute Decred hashPrefix + tx_serialize_input_hash(&ti, txinput); + } + // hash prevout and script type to check it later (relevant for fee + // computation) + tx_prevout_hash(&hasher_check, txinput); + hasher_Update(&hasher_check, (const uint8_t *)&txinput->script_type, + sizeof(&txinput->script_type)); + return true; } // check if the hash of the prevtx matches static bool signing_check_prevtx_hash(void) { - uint8_t hash[32]; - tx_hash_final(&tp, hash, true); - if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Encountered invalid prevhash")); - signing_abort(); - return false; - } - phase1_request_next_input(); - return true; + uint8_t hash[32]; + tx_hash_final(&tp, hash, true); + if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Encountered invalid prevhash")); + signing_abort(); + return false; + } + phase1_request_next_input(); + return true; } static bool signing_check_output(TxOutputType *txoutput) { - // Phase1: Check outputs - // add it to hash_outputs - // ask user for permission - - // check for change address - bool is_change = false; - if (txoutput->address_n_count > 0) { - if (txoutput->has_address) { - fsm_sendFailure(FailureType_Failure_Other, _("Address in change output")); - signing_abort(); - return false; - } - /* - * For multisig check that all inputs are multisig - */ - if (txoutput->has_multisig) { - uint8_t h[32]; - if (multisig_fp_set && !multisig_fp_mismatch - && cryptoMultisigFingerprint(&(txoutput->multisig), h) - && memcmp(multisig_fp, h, 32) == 0) { - is_change = check_change_bip32_path(txoutput); - } - } else { - is_change = check_change_bip32_path(txoutput); - } - } - - if (is_change) { - if (change_spend == 0) { // not set - change_spend = txoutput->amount; - } else { - /* We only skip confirmation for the first change output */ - is_change = false; - } - } - - if (spending + txoutput->amount < spending) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); - signing_abort(); - return false; - } - spending += txoutput->amount; - int co = run_policy_compile_output(coin, root, txoutput, &bin_output, !is_change); - if (!is_change) { - layoutProgress(_("Signing transaction"), progress); - } - if (co <= TXOUT_COMPILE_ERROR) { - send_fsm_co_error_message(co); - signing_abort(); - return false; - } else if (co < 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - signing_abort(); - return false; - } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Failed to compile output")); - signing_abort(); - return false; - } - if (coin->decred) { - // serialize Decred prefix in Phase 1 - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); - - // compute Decred hashPrefix - tx_serialize_output_hash(&ti, &bin_output); - } - // compute segwit hashOuts - tx_output_hash(&hasher_outputs, &bin_output, coin->decred); - return true; + // Phase1: Check outputs + // add it to hash_outputs + // ask user for permission + + // check for change address + bool is_change = false; + if (txoutput->address_n_count > 0) { + if (txoutput->has_address) { + fsm_sendFailure(FailureType_Failure_Other, _("Address in change output")); + signing_abort(); + return false; + } + /* + * For multisig check that all inputs are multisig + */ + if (txoutput->has_multisig) { + uint8_t h[32]; + if (multisig_fp_set && !multisig_fp_mismatch && + cryptoMultisigFingerprint(&(txoutput->multisig), h) && + memcmp(multisig_fp, h, 32) == 0) { + is_change = check_change_bip32_path(txoutput); + } + } else { + is_change = check_change_bip32_path(txoutput); + } + } + + if (is_change) { + if (change_spend == 0) { // not set + change_spend = txoutput->amount; + } else { + /* We only skip confirmation for the first change output */ + is_change = false; + } + } + + if (spending + txoutput->amount < spending) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); + signing_abort(); + return false; + } + spending += txoutput->amount; + int co = + run_policy_compile_output(coin, root, txoutput, &bin_output, !is_change); + if (!is_change) { + layoutProgress(_("Signing transaction"), progress); + } + if (co <= TXOUT_COMPILE_ERROR) { + send_fsm_co_error_message(co); + signing_abort(); + return false; + } else if (co < 0) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + signing_abort(); + return false; + } else if (co == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Failed to compile output")); + signing_abort(); + return false; + } + if (coin->decred) { + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output( + &to, &bin_output, resp.serialized.serialized_tx.bytes); + + // compute Decred hashPrefix + tx_serialize_output_hash(&ti, &bin_output); + } + // compute segwit hashOuts + tx_output_hash(&hasher_outputs, &bin_output, coin->decred); + return true; } static bool signing_check_fee(void) { - // check fees - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); - signing_abort(); - return false; - } - uint64_t fee = to_spend - spending; - char total_amount_str[32]; - char fee_str[32]; - coin_amnt_to_str(coin, fee, fee_str, sizeof(fee_str)); - if (fee > ((uint64_t) tx_weight * coin->maxfee_kb)/4000) { - if (!confirm(ButtonRequestType_ButtonRequest_FeeOverThreshold, - "Confirm Fee", "Really spend %s on fees? Except in times of high " - "network congestion, fees should be less than %" PRIu64 " sat/byte.", - fee_str, coin->maxfee_kb / 1000)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - signing_abort(); - return false; - } - } - // last confirmation - coin_amnt_to_str(coin, to_spend - change_spend, total_amount_str, sizeof(total_amount_str)); - if (!confirm_transaction(total_amount_str, fee_str)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user."); - signing_abort(); - return false; - } - return true; + // check fees + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); + signing_abort(); + return false; + } + uint64_t fee = to_spend - spending; + char total_amount_str[32]; + char fee_str[32]; + coin_amnt_to_str(coin, fee, fee_str, sizeof(fee_str)); + if (fee > ((uint64_t)tx_weight * coin->maxfee_kb) / 4000) { + if (!confirm(ButtonRequestType_ButtonRequest_FeeOverThreshold, + "Confirm Fee", + "Really spend %s on fees? Except in times of high " + "network congestion, fees should be less than %" PRIu64 + " sat/byte.", + fee_str, coin->maxfee_kb / 1000)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Fee over threshold. Signing cancelled."); + signing_abort(); + return false; + } + } + // last confirmation + coin_amnt_to_str(coin, to_spend - change_spend, total_amount_str, + sizeof(total_amount_str)); + if (!confirm_transaction(total_amount_str, fee_str)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + "Signing cancelled by user."); + signing_abort(); + return false; + } + return true; } static uint32_t signing_hash_type(void) { - uint32_t hash_type = SIGHASH_ALL; + uint32_t hash_type = SIGHASH_ALL; - if (coin->has_forkid) { - hash_type |= (coin->forkid << 8) | SIGHASH_FORKID; - } + if (coin->has_forkid) { + hash_type |= (coin->forkid << 8) | SIGHASH_FORKID; + } - return hash_type; + return hash_type; } static void phase1_request_next_output(void) { - if (idx1 < outputs_count - 1) { - idx1++; - send_req_3_output(); - } else { - if (coin->decred) { - // compute Decred hashPrefix - tx_hash_final(&ti, hash_prefix, false); - } - hasher_Final(&hasher_outputs, hash_outputs); - if (!signing_check_fee()) { - return; - } - // Everything was checked, now phase 2 begins and the transaction is signed. - progress_meta_step = progress_step / (inputs_count + outputs_count); - layoutProgress(_("Signing transaction"), progress); - idx1 = 0; - if (coin->decred) { - // Decred prefix serialized in Phase 1, skip Phase 2 - send_req_decred_witness(); - } else { - phase2_request_next_input(); - } - } + if (idx1 < outputs_count - 1) { + idx1++; + send_req_3_output(); + } else { + if (coin->decred) { + // compute Decred hashPrefix + tx_hash_final(&ti, hash_prefix, false); + } + hasher_Final(&hasher_outputs, hash_outputs); + if (!signing_check_fee()) { + return; + } + // Everything was checked, now phase 2 begins and the transaction is signed. + progress_meta_step = progress_step / (inputs_count + outputs_count); + layoutProgress(_("Signing transaction"), progress); + idx1 = 0; + if (coin->decred) { + // Decred prefix serialized in Phase 1, skip Phase 2 + send_req_decred_witness(); + } else { + phase2_request_next_input(); + } + } } static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - Hasher hasher_preimage; - hasher_Init(&hasher_preimage, curve->hasher_sign); - hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion - hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence - tx_prevout_hash(&hasher_preimage, txinput); // outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*) &txinput->amount, 8); // amount - tx_sequence_hash(&hasher_preimage, txinput); // nSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // nHashType - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, curve->hasher_sign); + hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion + hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence + tx_prevout_hash(&hasher_preimage, txinput); // outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // amount + tx_sequence_hash(&hasher_preimage, txinput); // nSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // nHashType + hasher_Final(&hasher_preimage, hash); } static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - uint8_t personal[16]; - memcpy(personal, "ZcashSigHash", 12); - memcpy(personal + 12, &branch_id, 4); - Hasher hasher_preimage; - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); - uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered - hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); - hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId - hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs - // 6. hashJoinSplits - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 7. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 8. expiryHeight - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 9. nHashType - - tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 10b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 10c. value - tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence - - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); + Hasher hasher_preimage; + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, + sizeof(personal)); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, + 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, + 4); // 7. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, + 4); // 8. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, + 4); // 9. nHashType + + tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // 10b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // 10c. value + tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence + + hasher_Final(&hasher_preimage, hash); } static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - uint8_t personal[16]; - memcpy(personal, "ZcashSigHash", 12); - memcpy(personal + 12, &branch_id, 4); - Hasher hasher_preimage; - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); - uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered - hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); - hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId - hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs - // 6. hashJoinSplits - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - // 7. hashShieldedSpends - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - // 8. hashShieldedOutputs - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 9. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 10. expiryHeight - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); // 11. valueBalance - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 12. nHashType - - tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 13b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 13c. value - tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence - - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); + Hasher hasher_preimage; + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, + sizeof(personal)); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, + 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 7. hashShieldedSpends + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 8. hashShieldedOutputs + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, + 4); // 9. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, + 4); // 10. expiryHeight + hasher_Update(&hasher_preimage, + (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", + 8); // 11. valueBalance + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, + 4); // 12. nHashType + + tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // 13b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // 13c. value + tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence + + hasher_Final(&hasher_preimage, hash); } static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - Hasher hasher_preimage; - hasher_Init(&hasher_preimage, curve->hasher_sign); - hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); - hasher_Update(&hasher_preimage, hash_prefix, 32); - hasher_Update(&hasher_preimage, hash_witness, 32); - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, curve->hasher_sign); + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); + hasher_Update(&hasher_preimage, hash_prefix, 32); + hasher_Update(&hasher_preimage, hash_witness, 32); + hasher_Final(&hasher_preimage, hash); } -static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (!curve->params || ecdsa_sign_digest(curve->params, private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Signing failed")); - signing_abort(); - return false; - } - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - - uint8_t sighash = signing_hash_type() & 0xff; - if (txinput->has_multisig) { - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Pubkey not found in multisig script")); - signing_abort(); - return false; - } - memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - txinput->script_sig.size = serialize_script_multisig(coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); - if (txinput->script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize multisig script")); - signing_abort(); - return false; - } - } else { // SPENDADDRESS - txinput->script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, public_key, 33, sighash, txinput->script_sig.bytes); - } - return true; +static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key, + const uint8_t *public_key, const uint8_t *hash) { + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + if (!curve->params || ecdsa_sign_digest(curve->params, private_key, hash, sig, + NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, _("Signing failed")); + signing_abort(); + return false; + } + resp.serialized.signature.size = + ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + + uint8_t sighash = signing_hash_type() & 0xff; + if (txinput->has_multisig) { + // fill in the signature + int pubkey_idx = + cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Pubkey not found in multisig script")); + signing_abort(); + return false; + } + memcpy(txinput->multisig.signatures[pubkey_idx].bytes, + resp.serialized.signature.bytes, resp.serialized.signature.size); + txinput->multisig.signatures[pubkey_idx].size = + resp.serialized.signature.size; + txinput->script_sig.size = serialize_script_multisig( + coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); + if (txinput->script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize multisig script")); + signing_abort(); + return false; + } + } else { // SPENDADDRESS + txinput->script_sig.size = serialize_script_sig( + resp.serialized.signature.bytes, resp.serialized.signature.size, + public_key, 33, sighash, txinput->script_sig.bytes); + } + return true; } static bool signing_sign_input(void) { - uint8_t hash[32]; - hasher_Final(&hasher_check, hash); - if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Transaction has changed during signing")); - signing_abort(); - return false; - } - - uint32_t hash_type = signing_hash_type(); - hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); - tx_hash_final(&ti, hash, false); - resp.has_serialized = true; - if (!signing_sign_hash(&input, privkey, pubkey, hash)) - return false; - resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); - return true; + uint8_t hash[32]; + hasher_Final(&hasher_check, hash); + if (memcmp(hash, hash_outputs, 32) != 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Transaction has changed during signing")); + signing_abort(); + return false; + } + + uint32_t hash_type = signing_hash_type(); + hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); + tx_hash_final(&ti, hash, false); + resp.has_serialized = true; + if (!signing_sign_hash(&input, privkey, pubkey, hash)) return false; + resp.serialized.serialized_tx.size = + tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); + return true; } static bool signing_sign_segwit_input(TxInputType *txinput) { - // idx1: index to sign - uint8_t hash[32]; - - if (txinput->script_type == InputScriptType_SPENDWITNESS - || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return false; - } - if (txinput->amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Transaction has changed during signing")); - signing_abort(); - return false; - } - authorized_amount -= txinput->amount; - - signing_hash_bip143(txinput, hash); - - resp.has_serialized = true; - if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) - return false; - - uint8_t sighash = signing_hash_type() & 0xff; - if (txinput->has_multisig) { - uint32_t r = 1; // skip number of items (filled in later) - resp.serialized.serialized_tx.bytes[r] = 0; r++; - int nwitnesses = 2; - for (uint32_t i = 0; i < txinput->multisig.signatures_count; i++) { - if (txinput->multisig.signatures[i].size == 0) { - continue; - } - nwitnesses++; - txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = sighash; - r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); - } - uint32_t script_len = compile_script_multisig(coin, &txinput->multisig, 0); - r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); - r += compile_script_multisig(coin, &txinput->multisig, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.bytes[0] = nwitnesses; - resp.serialized.serialized_tx.size = r; - } else { // single signature - uint32_t r = 0; - r += ser_length(2, resp.serialized.serialized_tx.bytes + r); - resp.serialized.signature.bytes[resp.serialized.signature.size] = sighash; - r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); - r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - } else { - // empty witness - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.bytes[0] = 0; - resp.serialized.serialized_tx.size = 1; - } - // if last witness add tx footer - if (idx1 == inputs_count - 1) { - uint32_t r = resp.serialized.serialized_tx.size; - r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - return true; + // idx1: index to sign + uint8_t hash[32]; + + if (is_segwit_input_script_type(txinput)) { + if (!compile_input_script_sig(txinput)) { + fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); + signing_abort(); + return false; + } + if (txinput->amount > authorized_bip143_in) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Transaction has changed during signing")); + signing_abort(); + return false; + } + authorized_bip143_in -= txinput->amount; + + signing_hash_bip143(txinput, hash); + + resp.has_serialized = true; + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) + return false; + + uint8_t sighash = signing_hash_type() & 0xff; + if (txinput->has_multisig) { + uint32_t r = 1; // skip number of items (filled in later) + resp.serialized.serialized_tx.bytes[r] = 0; + r++; + int nwitnesses = 2; + for (uint32_t i = 0; i < txinput->multisig.signatures_count; i++) { + if (txinput->multisig.signatures[i].size == 0) { + continue; + } + nwitnesses++; + txinput->multisig.signatures[i] + .bytes[txinput->multisig.signatures[i].size] = sighash; + r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, + txinput->multisig.signatures[i].bytes, + resp.serialized.serialized_tx.bytes + r); + } + uint32_t script_len = + compile_script_multisig(coin, &txinput->multisig, 0); + r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(coin, &txinput->multisig, + resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.bytes[0] = nwitnesses; + resp.serialized.serialized_tx.size = r; + } else { // single signature + uint32_t r = 0; + r += ser_length(2, resp.serialized.serialized_tx.bytes + r); + resp.serialized.signature.bytes[resp.serialized.signature.size] = sighash; + r += tx_serialize_script(resp.serialized.signature.size + 1, + resp.serialized.signature.bytes, + resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(33, node.public_key, + resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + } else { + // empty witness + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.bytes[0] = 0; + resp.serialized.serialized_tx.size = 1; + } + // if last witness add tx footer + if (idx1 == inputs_count - 1) { + uint32_t r = resp.serialized.serialized_tx.size; + r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + return true; } static bool signing_sign_decred_input(TxInputType *txinput) { - uint8_t hash[32], hash_witness[32]; - tx_hash_final(&ti, hash_witness, false); - signing_hash_decred(hash_witness, hash); - resp.has_serialized = true; - if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) - return false; - resp.serialized.serialized_tx.size = tx_serialize_decred_witness(&to, txinput, resp.serialized.serialized_tx.bytes); - return true; + uint8_t hash[32], hash_witness[32]; + tx_hash_final(&ti, hash_witness, false); + signing_hash_decred(hash_witness, hash); + resp.has_serialized = true; + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) + return false; + resp.serialized.serialized_tx.size = tx_serialize_decred_witness( + &to, txinput, resp.serialized.serialized_tx.bytes); + return true; } -#define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 - -void signing_txack(TransactionType *tx) -{ - if (!signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); - layoutHome(); - return; - } - - static int update_ctr = 0; - if (update_ctr++ == 20) { - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - } - - memset(&resp, 0, sizeof(TxRequest)); - - switch (signing_stage) { - case STAGE_REQUEST_1_INPUT: - signing_check_input(&tx->inputs[0]); - - tx_weight += tx_input_weight(coin, &tx->inputs[0]); - if (coin->decred) { - tx_weight += tx_decred_witness_weight(&tx->inputs[0]); - } - - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - memcpy(&input, tx->inputs, sizeof(TxInputType)); +#define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 + +void signing_txack(TransactionType *tx) { + if (!signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Signing mode")); + layoutHome(); + return; + } + + static int update_ctr = 0; + if (update_ctr++ == 20) { + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + } + + memset(&resp, 0, sizeof(TxRequest)); + + switch (signing_stage) { + case STAGE_REQUEST_1_INPUT: + if (!signing_validate_input(&tx->inputs[0]) || + !signing_check_input(&tx->inputs[0])) { + return; + } + + tx_weight += tx_input_weight(coin, &tx->inputs[0]); + if (coin->decred) { + tx_weight += tx_decred_witness_weight(&tx->inputs[0]); + } + + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || + tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + memcpy(&input, tx->inputs, sizeof(TxInputType)); #if !ENABLE_SEGWIT_NONSEGWIT_MIXING - // don't mix segwit and non-segwit inputs - if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Mixing segwit and non-segwit inputs is not allowed")); - signing_abort(); - return; - } + // don't mix segwit and non-segwit inputs + if (idx1 > 0 && to.is_segwit == true) { + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Mixing segwit and non-segwit inputs is not allowed")); + signing_abort(); + return; + } #endif - if (coin->force_bip143 || overwintered) { - if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Expected input with amount")); - signing_abort(); - return; - } - if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); - signing_abort(); - return; - } - to_spend += tx->inputs[0].amount; - authorized_amount += tx->inputs[0].amount; - phase1_request_next_input(); - } else { - // remember the first non-segwit input -- this is the first input - // we need to sign during phase2 - if (next_nonsegwit_input == 0xffffffff) - next_nonsegwit_input = idx1; - send_req_2_prev_meta(); - } - } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - if (coin->decred) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Decred does not support Segwit")); - signing_abort(); - return; - } - if (!coin->has_segwit || !coin->segwit) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Segwit not enabled on this coin")); - signing_abort(); - return; - } - if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Segwit input without amount")); - signing_abort(); - return; - } - if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); - signing_abort(); - return; - } - if (!to.is_segwit) { - tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; - } + if (coin->force_bip143 || overwintered) { + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Expected input with amount")); + signing_abort(); + return; + } + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Value overflow")); + signing_abort(); + return; + } + to_spend += tx->inputs[0].amount; + authorized_bip143_in += tx->inputs[0].amount; + phase1_request_next_input(); + } else { + // remember the first non-segwit input -- this is the first input + // we need to sign during phase2 + if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1; + send_req_2_prev_meta(); + } + } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || + tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS) { + if (coin->decred) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Decred does not support Segwit")); + signing_abort(); + return; + } + if (!coin->has_segwit || !coin->segwit) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Segwit not enabled on this coin")); + signing_abort(); + return; + } + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Segwit input without amount")); + signing_abort(); + return; + } + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); + signing_abort(); + return; + } + if (!to.is_segwit) { + tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; + } #if !ENABLE_SEGWIT_NONSEGWIT_MIXING - // don't mix segwit and non-segwit inputs - if (idx1 == 0) { - to.is_segwit = true; - } else if (to.is_segwit == false) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Mixing segwit and non-segwit inputs is not allowed")); - signing_abort(); - return; - } + // don't mix segwit and non-segwit inputs + if (idx1 == 0) { + to.is_segwit = true; + } else if (to.is_segwit == false) { + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Mixing segwit and non-segwit inputs is not allowed")); + signing_abort(); + return; + } #else - to.is_segwit = true; + to.is_segwit = true; #endif - to_spend += tx->inputs[0].amount; - authorized_amount += tx->inputs[0].amount; - phase1_request_next_input(); - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Wrong input script type")); - signing_abort(); - return; - } - return; - case STAGE_REQUEST_2_PREV_META: - if (tx->outputs_cnt <= input.prev_index) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Not enough outputs in previous transaction.")); - signing_abort(); - return; - } - if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); - signing_abort(); - return; - } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, curve->hasher_sign, overwintered, version_group_id); - if (coin->decred) { - tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); - tp.is_decred = true; - } - progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); - idx2 = 0; - if (tp.inputs_len > 0) { - send_req_2_prev_input(); - } else { - tx_serialize_header_hash(&tp); - send_req_2_prev_output(); - } - return; - case STAGE_REQUEST_2_PREV_INPUT: - progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; - if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize input")); - signing_abort(); - return; - } - if (idx2 < tp.inputs_len - 1) { - idx2++; - send_req_2_prev_input(); - } else { - idx2 = 0; - send_req_2_prev_output(); - } - return; - case STAGE_REQUEST_2_PREV_OUTPUT: - progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; - if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize output")); - signing_abort(); - return; - } - if (idx2 == input.prev_index) { - if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); - signing_abort(); - return; - } - if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Decred script version does not match previous output")); - signing_abort(); - return; - } - to_spend += tx->bin_outputs[0].amount; - } - if (idx2 < tp.outputs_len - 1) { - /* Check prevtx of next input */ - idx2++; - send_req_2_prev_output(); - } else if (tp.extra_data_len > 0) { // has extra data - send_req_2_prev_extradata(0, MIN(1024U, tp.extra_data_len)); - return; - } else { - /* prevtx is done */ - signing_check_prevtx_hash(); - } - return; - case STAGE_REQUEST_2_PREV_EXTRADATA: - if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize extra data")); - signing_abort(); - return; - } - if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining - send_req_2_prev_extradata(tp.extra_data_received, MIN(1024U, tp.extra_data_len - tp.extra_data_received)); - } else { - signing_check_prevtx_hash(); - } - return; - case STAGE_REQUEST_3_OUTPUT: - if (!signing_check_output(&tx->outputs[0])) { - return; - } - tx_weight += tx_output_weight(coin, curve, &tx->outputs[0]); - phase1_request_next_output(); - return; - case STAGE_REQUEST_4_INPUT: - progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); - if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, curve->hasher_sign, overwintered, version_group_id); - hasher_Reset(&hasher_check); - } - // check prevouts and script type - tx_prevout_hash(&hasher_check, tx->inputs); - hasher_Update(&hasher_check, (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); - if (idx2 == idx1) { - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return; - } - memcpy(&input, &tx->inputs[0], sizeof(input)); - memcpy(privkey, node.private_key, 32); - memcpy(pubkey, node.public_key, 33); - } else { - if (next_nonsegwit_input == idx1 && idx2 > idx1 - && (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS - || tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG)) { - next_nonsegwit_input = idx2; - } - tx->inputs[0].script_sig.size = 0; - } - if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize input")); - signing_abort(); - return; - } - if (idx2 < inputs_count - 1) { - idx2++; - send_req_4_input(); - } else { - uint8_t hash[32]; - hasher_Final(&hasher_check, hash); - if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - hasher_Reset(&hasher_check); - idx2 = 0; - send_req_4_output(); - } - return; - case STAGE_REQUEST_4_OUTPUT: - progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); - int co = run_policy_compile_output(coin, root, tx->outputs, &bin_output, false); - if (co <= TXOUT_COMPILE_ERROR) { - send_fsm_co_error_message(co); - signing_abort(); - return; - } - // check hashOutputs - tx_output_hash(&hasher_check, &bin_output, coin->decred); - if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize output")); - signing_abort(); - return; - } - if (idx2 < outputs_count - 1) { - idx2++; - send_req_4_output(); - } else { - if (!signing_sign_input()) { - return; - } - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - phase2_request_next_input(); - } else { - idx1 = 0; - send_req_5_output(); - } - } - return; - - case STAGE_REQUEST_SEGWIT_INPUT: - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - if (!(coin->force_bip143 || overwintered)) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return; - } - if (tx->inputs[0].amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - authorized_amount -= tx->inputs[0].amount; - - uint8_t hash[32]; - if (overwintered) { - switch (version) { - case 3: - signing_hash_zip143(&tx->inputs[0], hash); - break; - case 4: - signing_hash_zip243(&tx->inputs[0], hash); - break; - default: - fsm_sendFailure(FailureType_Failure_SyntaxError, _("Unsupported version for overwintered transaction")); - signing_abort(); - return; - } - } else { - signing_hash_bip143(&tx->inputs[0], hash); - } - if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash)) - return; - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS - && !tx->inputs[0].has_multisig) { - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return; - } - // fixup normal p2pkh script into witness 0 p2wpkh script for p2sh - // we convert 76 A9 14 88 AC to 16 00 14 - // P2SH input pushes witness 0 script - tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes. - tx->inputs[0].script_sig.bytes[0] = 0x16; // push 22 bytes; replaces OP_DUP - tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script ; replaces OP_HASH160 - // digest is already in right place. - } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - // Prepare P2SH witness script. - tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: - tx->inputs[0].script_sig.bytes[0] = 0x22; // push 34 bytes (full witness script) - tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script - tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) - // compute digest of multisig script - if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return; - } - } else { - // direct witness scripts require zero scriptSig - tx->inputs[0].script_sig.size = 0; - } - resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); - if (idx1 < inputs_count - 1) { - idx1++; - phase2_request_next_input(); - } else { - idx1 = 0; - send_req_5_output(); - } - return; - - case STAGE_REQUEST_5_OUTPUT: - co = run_policy_compile_output(coin, root, tx->outputs, &bin_output, false); - if (co <= TXOUT_COMPILE_ERROR) { - send_fsm_co_error_message(co); - signing_abort(); - return; - } - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); - if (idx1 < outputs_count - 1) { - idx1++; - send_req_5_output(); - } else if (to.is_segwit) { - idx1 = 0; - send_req_segwit_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; - - case STAGE_REQUEST_SEGWIT_WITNESS: - if (!signing_sign_segwit_input(&tx->inputs[0])) { - return; - } - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - send_req_segwit_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; - - case STAGE_REQUEST_DECRED_WITNESS: - progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); - if (idx1 == 0) { - // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, curve->hasher_sign, overwintered, version_group_id); - to.is_decred = true; - } - - // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, curve->hasher_sign, overwintered, version_group_id); - ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); - ti.is_decred = true; - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to compile input")); - signing_abort(); - return; - } - - for (idx2 = 0; idx2 < inputs_count; idx2++) { - uint32_t r; - if (idx2 == idx1) { - r = tx_serialize_decred_witness_hash(&ti, &tx->inputs[0]); - } else { - r = tx_serialize_decred_witness_hash(&ti, NULL); - } - - if (!r) { - fsm_sendFailure(FailureType_Failure_Other, _("Failed to serialize input")); - signing_abort(); - return; - } - } - - if (!signing_sign_decred_input(&tx->inputs[0])) { - return; - } - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - send_req_decred_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; - } - - fsm_sendFailure(FailureType_Failure_Other, _("Signing error")); - signing_abort(); + to_spend += tx->inputs[0].amount; + authorized_bip143_in += tx->inputs[0].amount; + + txin_dgst_addto(tx->inputs[0].prev_hash.bytes, + sizeof(TxInputType_prev_hash_t)); + + phase1_request_next_input(); + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Wrong input script type")); + signing_abort(); + return; + } + + return; + case STAGE_REQUEST_2_PREV_META: + if (tx->outputs_cnt <= input.prev_index) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Not enough outputs in previous transaction.")); + signing_abort(); + return; + } + + if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); + signing_abort(); + return; + } + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, + tx->expiry, tx->extra_data_len, curve->hasher_sign, overwintered, + version_group_id); + if (coin->decred) { + tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + tp.is_decred = true; + } + progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); + idx2 = 0; + if (tp.inputs_len > 0) { + send_req_2_prev_input(); + } else { + tx_serialize_header_hash(&tp); + send_req_2_prev_output(); + } + return; + case STAGE_REQUEST_2_PREV_INPUT: + if (!signing_validate_input(&tx->inputs[0])) { + return; + } + progress = (idx1 * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION; + if (!tx_serialize_input_hash(&tp, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize input")); + signing_abort(); + return; + } + if (idx2 < tp.inputs_len - 1) { + idx2++; + send_req_2_prev_input(); + } else { + idx2 = 0; + send_req_2_prev_output(); + } + return; + case STAGE_REQUEST_2_PREV_OUTPUT: + if (!signing_validate_bin_output(&tx->bin_outputs[0])) { + return; + } + progress = (idx1 * progress_step + + (tp.inputs_len + idx2) * progress_meta_step) >> + PROGRESS_PRECISION; + if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize output")); + signing_abort(); + return; + } + if (idx2 == input.prev_index) { + if (to_spend + tx->bin_outputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_SyntaxError, _("Value overflow")); + signing_abort(); + return; + } + if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Decred script version does not match previous output")); + signing_abort(); + return; + } + to_spend += tx->bin_outputs[0].amount; + } + if (idx2 < tp.outputs_len - 1) { + /* Check prevtx of next input */ + idx2++; + send_req_2_prev_output(); + } else if (tp.extra_data_len > 0) { // has extra data + send_req_2_prev_extradata(0, MIN(1024U, tp.extra_data_len)); + return; + } else { + /* prevtx is done */ + signing_check_prevtx_hash(); + } + return; + case STAGE_REQUEST_2_PREV_EXTRADATA: + if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, + tx->extra_data.size)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize extra data")); + signing_abort(); + return; + } + if (tp.extra_data_received < + tp.extra_data_len) { // still some data remanining + send_req_2_prev_extradata( + tp.extra_data_received, + MIN(1024U, tp.extra_data_len - tp.extra_data_received)); + } else { + signing_check_prevtx_hash(); + } + return; + case STAGE_REQUEST_3_OUTPUT: + + txin_dgst_final(); + + if (!signing_validate_output(&tx->outputs[0]) || + !signing_check_output(&tx->outputs[0])) { + return; + } + tx_weight += tx_output_weight(coin, curve, &tx->outputs[0]); + phase1_request_next_output(); + return; + case STAGE_REQUEST_4_INPUT: + if (!signing_validate_input(&tx->inputs[0])) { + return; + } + progress = + 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION); + if (idx2 == 0) { + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + curve->hasher_sign, overwintered, version_group_id); + hasher_Reset(&hasher_check); + } + // check prevouts and script type + tx_prevout_hash(&hasher_check, tx->inputs); + hasher_Update(&hasher_check, (const uint8_t *)&tx->inputs[0].script_type, + sizeof(&tx->inputs[0].script_type)); + if (idx2 == idx1) { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to compile input")); + signing_abort(); + return; + } + memcpy(&input, &tx->inputs[0], sizeof(input)); + memcpy(privkey, node.private_key, 32); + memcpy(pubkey, node.public_key, 33); + } else { + if (next_nonsegwit_input == idx1 && idx2 > idx1 && + (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS || + tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG)) { + next_nonsegwit_input = idx2; + } + tx->inputs[0].script_sig.size = 0; + } + if (!tx_serialize_input_hash(&ti, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize input")); + signing_abort(); + return; + } + if (idx2 < inputs_count - 1) { + idx2++; + send_req_4_input(); + } else { + uint8_t hash[32]; + hasher_Final(&hasher_check, hash); + if (memcmp(hash, hash_check, 32) != 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + hasher_Reset(&hasher_check); + idx2 = 0; + send_req_4_output(); + } + return; + case STAGE_REQUEST_4_OUTPUT: + if (!signing_validate_output(&tx->outputs[0])) { + return; + } + progress = 500 + ((signatures * progress_step + + (inputs_count + idx2) * progress_meta_step) >> + PROGRESS_PRECISION); + int co = run_policy_compile_output(coin, root, tx->outputs, &bin_output, + false); + if (co <= TXOUT_COMPILE_ERROR) { + send_fsm_co_error_message(co); + signing_abort(); + return; + } + // check hashOutputs + tx_output_hash(&hasher_check, &bin_output, coin->decred); + if (!tx_serialize_output_hash(&ti, &bin_output)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize output")); + signing_abort(); + return; + } + if (idx2 < outputs_count - 1) { + idx2++; + send_req_4_output(); + } else { + if (!signing_sign_input()) { + return; + } + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + phase2_request_next_input(); + } else { + idx1 = 0; + send_req_5_output(); + } + } + return; + + case STAGE_REQUEST_SEGWIT_INPUT: + if (!signing_validate_input(&tx->inputs[0])) { + return; + } + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || + tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + if (!(coin->force_bip143 || overwintered)) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to compile input")); + signing_abort(); + return; + } + if (tx->inputs[0].amount > authorized_bip143_in) { + fsm_sendFailure(FailureType_Failure_SyntaxError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + authorized_bip143_in -= tx->inputs[0].amount; + + uint8_t hash[32]; + if (overwintered) { + switch (version) { + case 3: + signing_hash_zip143(&tx->inputs[0], hash); + break; + case 4: + signing_hash_zip243(&tx->inputs[0], hash); + break; + default: + fsm_sendFailure( + FailureType_Failure_SyntaxError, + _("Unsupported version for overwintered transaction")); + signing_abort(); + return; + } + } else { + signing_hash_bip143(&tx->inputs[0], hash); + } + if (!signing_sign_hash(&tx->inputs[0], node.private_key, + node.public_key, hash)) + return; + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + } else if (tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS && + !tx->inputs[0].has_multisig) { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to compile input")); + signing_abort(); + return; + } + // fixup normal p2pkh script into witness 0 p2wpkh script for p2sh + // we convert 76 A9 14 88 AC to 16 00 14 + // P2SH input pushes witness 0 script + tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes. + tx->inputs[0].script_sig.bytes[0] = + 0x16; // push 22 bytes; replaces OP_DUP + tx->inputs[0].script_sig.bytes[1] = + 0x00; // witness 0 script ; replaces OP_HASH160 + // digest is already in right place. + } else if (tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS) { + // Prepare P2SH witness script. + tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: + tx->inputs[0].script_sig.bytes[0] = + 0x22; // push 34 bytes (full witness script) + tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script + tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) + // compute digest of multisig script + if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, + tx->inputs[0].script_sig.bytes + 3)) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to compile input")); + signing_abort(); + return; + } + } else { + // direct witness scripts require zero scriptSig + tx->inputs[0].script_sig.size = 0; + } + resp.serialized.serialized_tx.size = tx_serialize_input( + &to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); + if (idx1 < inputs_count - 1) { + idx1++; + phase2_request_next_input(); + } else { + idx1 = 0; + send_req_5_output(); + } + return; + + case STAGE_REQUEST_5_OUTPUT: + if (!signing_validate_output(&tx->outputs[0])) { + return; + } + co = run_policy_compile_output(coin, root, tx->outputs, &bin_output, + false); + if (co <= TXOUT_COMPILE_ERROR) { + send_fsm_co_error_message(co); + signing_abort(); + return; + } + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output( + &to, &bin_output, resp.serialized.serialized_tx.bytes); + if (idx1 < outputs_count - 1) { + idx1++; + send_req_5_output(); + } else if (to.is_segwit) { + idx1 = 0; + send_req_segwit_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; + + case STAGE_REQUEST_SEGWIT_WITNESS: + if (!signing_validate_input(&tx->inputs[0])) { + return; + } + if (!signing_sign_segwit_input(&tx->inputs[0])) { + return; + } + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_segwit_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; + + case STAGE_REQUEST_DECRED_WITNESS: + if (!signing_validate_input(&tx->inputs[0])) { + return; + } + progress = + 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION); + if (idx1 == 0) { + // witness + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, + curve->hasher_sign, overwintered, version_group_id); + to.is_decred = true; + } + + // witness hash + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + curve->hasher_sign, overwintered, version_group_id); + ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); + ti.is_decred = true; + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to compile input")); + signing_abort(); + return; + } + + for (idx2 = 0; idx2 < inputs_count; idx2++) { + uint32_t r; + if (idx2 == idx1) { + r = tx_serialize_decred_witness_hash(&ti, &tx->inputs[0]); + } else { + r = tx_serialize_decred_witness_hash(&ti, NULL); + } + + if (!r) { + fsm_sendFailure(FailureType_Failure_Other, + _("Failed to serialize input")); + signing_abort(); + return; + } + } + + if (!signing_sign_decred_input(&tx->inputs[0])) { + return; + } + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_decred_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; + } + + fsm_sendFailure(FailureType_Failure_Other, _("Signing error")); + signing_abort(); } -void signing_abort(void) -{ - if (signing) { - layoutHome(); - signing = false; - } +void signing_abort(void) { + if (signing) { + layoutHome(); + signing = false; + } + memzero(&root, sizeof(root)); + memzero(&node, sizeof(node)); } diff --git a/lib/firmware/storage.c b/lib/firmware/storage.c index c54f40dd0..6ec9ad8ac 100644 --- a/lib/firmware/storage.c +++ b/lib/firmware/storage.c @@ -24,8 +24,8 @@ #include "variant.h" #ifndef EMULATOR -# include -# include +#include +#include #endif #include "aes_sca/aes128_cbc.h" @@ -56,12 +56,22 @@ #include #include +/* +The PIN_ITER defines below changed between storage version 15 and 16 to eliminate +the unacceptable multi-second wait while the pin was being stretched for a dubious +claim to better security. The defines help during upgrades from v15 to v16 +*/ + #if defined(EMULATOR) || defined(DEBUG_ON) -# define PIN_ITER_COUNT 1000 -# define PIN_ITER_CHUNK 10 +#define PIN_ITER_COUNT_v15 1000 +#define PIN_ITER_CHUNK_v15 10 +#define PIN_ITER_COUNT_v16 10 +#define PIN_ITER_CHUNK_v16 1 #else -# define PIN_ITER_COUNT 100000 -# define PIN_ITER_CHUNK 1000 +#define PIN_ITER_COUNT_v15 100000 +#define PIN_ITER_CHUNK_v15 1000 +#define PIN_ITER_COUNT_v16 10 +#define PIN_ITER_CHUNK_v16 1 #endif #define U2F_KEY_PATH 0x80553246 @@ -80,746 +90,900 @@ static ConfigFlash CONFIDENTIAL shadow_config; // These won't survive resets like the stuff in flash would, but thats a // reasonable compromise given how testing works. char debuglink_pin[10]; +char debuglink_wipe_code[10]; char debuglink_mnemonic[241]; HDNode debuglink_node; #endif -static void get_u2froot_callback(uint32_t iter, uint32_t total) -{ - layoutProgress(_("Updating"), 1000 * iter / total); +static void get_u2froot_callback(uint32_t iter, uint32_t total) { + layoutProgress(_("Updating"), 1000 * iter / total); } -static void storage_compute_u2froot(SessionState *ss, - const char *mnemonic, +static void storage_compute_u2froot(SessionState *ss, const char *mnemonic, HDNodeType *u2froot) { - static CONFIDENTIAL HDNode node; - mnemonic_to_seed(mnemonic, "", ss->seed, get_u2froot_callback); // BIP-0039 - hdnode_from_seed(ss->seed, 64, NIST256P1_NAME, &node); - hdnode_private_ckd(&node, U2F_KEY_PATH); - u2froot->depth = node.depth; - u2froot->child_num = U2F_KEY_PATH; - u2froot->chain_code.size = sizeof(node.chain_code); - memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); - u2froot->has_private_key = true; - u2froot->private_key.size = sizeof(node.private_key); - memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - memzero(&node, sizeof(node)); -} - -bool storage_getU2FRoot(HDNode *node) -{ - return shadow_config.storage.pub.has_u2froot && - hdnode_from_xprv(shadow_config.storage.pub.u2froot.depth, - shadow_config.storage.pub.u2froot.child_num, - shadow_config.storage.pub.u2froot.chain_code.bytes, - shadow_config.storage.pub.u2froot.private_key.bytes, - NIST256P1_NAME, node); + static CONFIDENTIAL HDNode node; + mnemonic_to_seed(mnemonic, "", ss->seed, get_u2froot_callback); // BIP-0039 + hdnode_from_seed(ss->seed, 64, NIST256P1_NAME, &node); + hdnode_private_ckd(&node, U2F_KEY_PATH); + u2froot->depth = node.depth; + u2froot->child_num = U2F_KEY_PATH; + u2froot->chain_code.size = sizeof(node.chain_code); + memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); + u2froot->has_private_key = true; + u2froot->private_key.size = sizeof(node.private_key); + memcpy(u2froot->private_key.bytes, node.private_key, + sizeof(node.private_key)); + memzero(&node, sizeof(node)); +} + +bool storage_getU2FRoot(HDNode *node) { + return shadow_config.storage.pub.has_u2froot && + hdnode_from_xprv(shadow_config.storage.pub.u2froot.depth, + shadow_config.storage.pub.u2froot.child_num, + shadow_config.storage.pub.u2froot.chain_code.bytes, + shadow_config.storage.pub.u2froot.private_key.bytes, + NIST256P1_NAME, node); } uint32_t storage_nextU2FCounter(void) { - shadow_config.storage.pub.u2f_counter++; - storage_commit(); - return shadow_config.storage.pub.u2f_counter; + shadow_config.storage.pub.u2f_counter++; + storage_commit(); + return shadow_config.storage.pub.u2f_counter; } void storage_setU2FCounter(uint32_t u2f_counter) { - shadow_config.storage.pub.u2f_counter = u2f_counter; - storage_commit(); + shadow_config.storage.pub.u2f_counter = u2f_counter; + storage_commit(); } static bool storage_isActiveSector(const char *flash) { - return memcmp(((const Metadata *)flash)->magic, STORAGE_MAGIC_STR, - STORAGE_MAGIC_LEN) == 0; + return memcmp(((const Metadata *)flash)->magic, STORAGE_MAGIC_STR, + STORAGE_MAGIC_LEN) == 0; } void storage_upgradePolicies(Storage *storage) { - for (int i = storage->pub.policies_count; i < (int)(POLICY_COUNT); ++i) { - memcpy(&storage->pub.policies[i], &policies[i], sizeof(storage->pub.policies[i])); - } - storage->pub.policies_count = POLICY_COUNT; + for (int i = storage->pub.policies_count; i < (int)(POLICY_COUNT); ++i) { + memcpy(&storage->pub.policies[i], &policies[i], + sizeof(storage->pub.policies[i])); + } + storage->pub.policies_count = POLICY_COUNT; } void storage_resetPolicies(Storage *storage) { - storage->pub.policies_count = 0; - storage_upgradePolicies(storage); + storage->pub.policies_count = 0; + storage_upgradePolicies(storage); } -void storage_resetCache(Cache *cache) -{ - memset(cache, 0, sizeof(*cache)); -} +void storage_resetCache(Cache *cache) { memset(cache, 0, sizeof(*cache)); } -static uint8_t read_u8(const char *ptr) { - return *ptr; -} +static uint8_t read_u8(const char *ptr) { return *ptr; } -static void write_u8(char *ptr, uint8_t val) { - *ptr = val; -} +static void write_u8(char *ptr, uint8_t val) { *ptr = val; } static uint32_t read_u32_le(const char *ptr) { - return ((uint32_t)ptr[0]) | - ((uint32_t)ptr[1]) << 8 | - ((uint32_t)ptr[2]) << 16 | - ((uint32_t)ptr[3]) << 24; + return ((uint32_t)ptr[0]) | ((uint32_t)ptr[1]) << 8 | + ((uint32_t)ptr[2]) << 16 | ((uint32_t)ptr[3]) << 24; } static void write_u32_le(char *ptr, uint32_t val) { - ptr[0] = val & 0xff; - ptr[1] = (val >> 8) & 0xff; - ptr[2] = (val >> 16) & 0xff; - ptr[3] = (val >> 24) & 0xff; + ptr[0] = val & 0xff; + ptr[1] = (val >> 8) & 0xff; + ptr[2] = (val >> 16) & 0xff; + ptr[3] = (val >> 24) & 0xff; } -static bool read_bool(const char *ptr) { - return *ptr; -} +static bool read_bool(const char *ptr) { return *ptr; } -static void write_bool(char *ptr, bool val) { - *ptr = val ? 1 : 0; -} +static void write_bool(char *ptr, bool val) { *ptr = val ? 1 : 0; } enum StorageVersion { - StorageVersion_NONE, - #define STORAGE_VERSION_ENTRY(VAL) \ - StorageVersion_ ##VAL, - #include "storage_versions.inc" + StorageVersion_NONE, +#define STORAGE_VERSION_ENTRY(VAL) StorageVersion_##VAL, +#include "storage_versions.inc" }; static enum StorageVersion version_from_int(int version) { - #define STORAGE_VERSION_LAST(VAL) \ - _Static_assert(VAL == STORAGE_VERSION, \ - "need to update storage_versions.inc"); - #include "storage_versions.inc" - - switch (version) { - #define STORAGE_VERSION_ENTRY(VAL) \ - case VAL: return StorageVersion_ ##VAL; - #include "storage_versions.inc" +#define STORAGE_VERSION_LAST(VAL) \ + _Static_assert(VAL == STORAGE_VERSION, "need to update " \ + "storage_versions.inc"); +#include "storage_versions.inc" + + switch (version) { +#define STORAGE_VERSION_ENTRY(VAL) \ + case VAL: \ + return StorageVersion_##VAL; +#include "storage_versions.inc" default: - return StorageVersion_NONE; - } + return StorageVersion_NONE; + } } void storage_readMeta(Metadata *meta, const char *ptr, size_t len) { - if (len < 16 + STORAGE_UUID_STR_LEN) - return; - memcpy(meta->magic, ptr, STORAGE_MAGIC_LEN); - memcpy(meta->uuid, ptr + 4, STORAGE_UUID_LEN); - memcpy(meta->uuid_str, ptr + 16, STORAGE_UUID_STR_LEN); + if (len < 16 + STORAGE_UUID_STR_LEN) return; + memcpy(meta->magic, ptr, STORAGE_MAGIC_LEN); + memcpy(meta->uuid, ptr + 4, STORAGE_UUID_LEN); + memcpy(meta->uuid_str, ptr + 16, STORAGE_UUID_STR_LEN); } void storage_writeMeta(char *ptr, size_t len, const Metadata *meta) { - if (len < 16 + STORAGE_UUID_STR_LEN) - return; - memcpy(ptr, meta->magic, STORAGE_MAGIC_LEN); - memcpy(ptr + 4, meta->uuid, STORAGE_UUID_LEN); - memcpy(ptr + 16, meta->uuid_str, STORAGE_UUID_STR_LEN); + if (len < 16 + STORAGE_UUID_STR_LEN) return; + memcpy(ptr, meta->magic, STORAGE_MAGIC_LEN); + memcpy(ptr + 4, meta->uuid, STORAGE_UUID_LEN); + memcpy(ptr + 16, meta->uuid_str, STORAGE_UUID_STR_LEN); } void storage_readPolicyV1(PolicyType *policy, const char *ptr, size_t len) { - if (len < 17) - return; - policy->has_policy_name = read_bool(ptr); - memset(policy->policy_name, 0, sizeof(policy->policy_name)); - memcpy(policy->policy_name, ptr + 1, 15); - policy->has_enabled = read_bool(ptr + 16); - policy->enabled = read_bool(ptr + 17); + if (len < 17) return; + policy->has_policy_name = read_bool(ptr); + memset(policy->policy_name, 0, sizeof(policy->policy_name)); + memcpy(policy->policy_name, ptr + 1, 15); + policy->has_enabled = read_bool(ptr + 16); + policy->enabled = read_bool(ptr + 17); } -void storage_readPolicyV2(PolicyType *policy, const char *policy_name, bool enabled) { - policy->has_policy_name = true; - memset(policy->policy_name, 0, sizeof(policy->policy_name)); - strncpy(policy->policy_name, policy_name, sizeof(policy->policy_name)); - policy->has_enabled = true; - policy->enabled = enabled; +void storage_readPolicyV2(PolicyType *policy, const char *policy_name, + bool enabled) { + policy->has_policy_name = true; + memset(policy->policy_name, 0, sizeof(policy->policy_name)); + strncpy(policy->policy_name, policy_name, sizeof(policy->policy_name)); + policy->has_enabled = true; + policy->enabled = enabled; } void storage_writePolicyV1(char *ptr, size_t len, const PolicyType *policy) { - if (len < 17) - return; - write_bool(ptr, policy->has_policy_name); - memcpy(ptr + 1, policy->policy_name, 15); - write_bool(ptr + 16, policy->has_enabled); - write_bool(ptr + 17, policy->enabled); + if (len < 17) return; + write_bool(ptr, policy->has_policy_name); + memcpy(ptr + 1, policy->policy_name, 15); + write_bool(ptr + 16, policy->has_enabled); + write_bool(ptr + 17, policy->enabled); } void storage_readHDNode(HDNodeType *node, const char *ptr, size_t len) { - if (len < 96 + 33) - return; - node->depth = read_u32_le(ptr); - node->fingerprint = read_u32_le(ptr + 4); - node->child_num = read_u32_le(ptr + 8); - node->chain_code.size = 32; - memcpy(node->chain_code.bytes, ptr + 16, 32); - node->has_private_key = read_bool(ptr + 48); - node->private_key.size = 32; - memcpy(node->private_key.bytes, ptr + 56, 32); - node->has_public_key = read_bool(ptr + 88); - node->public_key.size = 33; - memcpy(node->public_key.bytes, ptr + 96, 33); + if (len < 96 + 33) return; + node->depth = read_u32_le(ptr); + node->fingerprint = read_u32_le(ptr + 4); + node->child_num = read_u32_le(ptr + 8); + node->chain_code.size = 32; + memcpy(node->chain_code.bytes, ptr + 16, 32); + node->has_private_key = read_bool(ptr + 48); + node->private_key.size = 32; + memcpy(node->private_key.bytes, ptr + 56, 32); + node->has_public_key = read_bool(ptr + 88); + node->public_key.size = 33; + memcpy(node->public_key.bytes, ptr + 96, 33); } void storage_writeHDNode(char *ptr, size_t len, const HDNodeType *node) { - if (len < 96 + 33) - return; - write_u32_le(ptr, node->depth); - write_u32_le(ptr + 4, node->fingerprint); - write_u32_le(ptr + 8, node->child_num); - write_u32_le(ptr + 12, 32); - memcpy(ptr + 16, node->chain_code.bytes, 32); - write_bool(ptr + 48, node->has_private_key); - ptr[49] = 0; // reserved - ptr[50] = 0; // reserved - ptr[51] = 0; // reserved - write_u32_le(ptr + 52, 32); - memcpy(ptr + 56, node->private_key.bytes, 32); - write_bool(ptr + 88, node->has_public_key); - ptr[89] = 0; // reserved - ptr[90] = 0; // reserved - ptr[91] = 0; // reserved - write_u32_le(ptr + 92, 33); - memcpy(ptr + 96, node->public_key.bytes, 33); -} - -void storage_deriveWrappingKey( - const char *pin, uint8_t wrapping_key[64], bool sca_hardened, - uint8_t random_salt[RANDOM_SALT_LEN], - const char *message) -{ - size_t pin_len = strlen(pin); - if (sca_hardened && pin_len > 0) { - uint8_t salt[HW_ENTROPY_LEN + RANDOM_SALT_LEN]; - memset(salt, 0, sizeof(salt)); - flash_readHWEntropy(salt, sizeof(salt)); - memcpy(salt + HW_ENTROPY_LEN, random_salt, RANDOM_SALT_LEN); - - PBKDF2_HMAC_SHA256_CTX ctx = {0}; - pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*)pin, pin_len, salt, sizeof(salt), 1); - for (int i = 0; i < PIN_ITER_COUNT; i += PIN_ITER_CHUNK) { - layoutProgress(message, 1000 * i / (PIN_ITER_COUNT * 2)); - pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_CHUNK); - } - pbkdf2_hmac_sha256_Final(&ctx, wrapping_key); - memzero(&ctx, sizeof(ctx)); + if (len < 96 + 33) return; + write_u32_le(ptr, node->depth); + write_u32_le(ptr + 4, node->fingerprint); + write_u32_le(ptr + 8, node->child_num); + write_u32_le(ptr + 12, 32); + memcpy(ptr + 16, node->chain_code.bytes, 32); + write_bool(ptr + 48, node->has_private_key); + ptr[49] = 0; // reserved + ptr[50] = 0; // reserved + ptr[51] = 0; // reserved + write_u32_le(ptr + 52, 32); + memcpy(ptr + 56, node->private_key.bytes, 32); + write_bool(ptr + 88, node->has_public_key); + ptr[89] = 0; // reserved + ptr[90] = 0; // reserved + ptr[91] = 0; // reserved + write_u32_le(ptr + 92, 33); + memcpy(ptr + 96, node->public_key.bytes, 33); +} + +void storage_deriveWrappingKey(const char *pin, uint8_t wrapping_key[64], + bool sca_hardened, + bool v15_16_trans, + uint8_t random_salt[RANDOM_SALT_LEN], + const char *message) { + size_t pin_len = strlen(pin); + if (sca_hardened && pin_len > 0) { + uint8_t salt[HW_ENTROPY_LEN + RANDOM_SALT_LEN]; + int iterCount, iterChunk; + + if (v15_16_trans) { // can use new counts + iterCount = PIN_ITER_COUNT_v16; + iterChunk = PIN_ITER_CHUNK_v16; + } else { // need to use storage version 15 counts to derive wrap key + iterCount = PIN_ITER_COUNT_v15; + iterChunk = PIN_ITER_CHUNK_v15; + } - pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*)pin, pin_len, salt, sizeof(salt), 2); - for (int i = 0; i < PIN_ITER_COUNT; i += PIN_ITER_CHUNK) { - layoutProgress(message, 1000 * (i + PIN_ITER_COUNT) / (PIN_ITER_COUNT * 2)); - pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_CHUNK); - } - layoutProgress(message, 1000); - pbkdf2_hmac_sha256_Final(&ctx, wrapping_key + 32); - memzero(&ctx, sizeof(ctx)); + memset(salt, 0, sizeof(salt)); + flash_readHWEntropy(salt, sizeof(salt)); + memcpy(salt + HW_ENTROPY_LEN, random_salt, RANDOM_SALT_LEN); - memzero(salt, sizeof(salt)); - } else { - sha512_Raw((const uint8_t*)pin, pin_len, wrapping_key); + PBKDF2_HMAC_SHA256_CTX ctx = {0}; + pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)pin, pin_len, salt, + sizeof(salt), 1); + + for (int i = 0; i < iterCount; i += iterChunk) { + layoutProgress(message, 1000 * i / (iterCount * 2)); + pbkdf2_hmac_sha256_Update(&ctx, iterChunk); } + pbkdf2_hmac_sha256_Final(&ctx, wrapping_key); + memzero(&ctx, sizeof(ctx)); + + pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)pin, pin_len, salt, + sizeof(salt), 2); + for (int i = 0; i < iterCount; i += iterChunk) { + layoutProgress(message, + 1000 * (i + iterCount) / (iterCount * 2)); + pbkdf2_hmac_sha256_Update(&ctx, iterChunk); + } + layoutProgress(message, 1000); + pbkdf2_hmac_sha256_Final(&ctx, wrapping_key + 32); + memzero(&ctx, sizeof(ctx)); + + memzero(salt, sizeof(salt)); + } else { + sha512_Raw((const uint8_t *)pin, pin_len, wrapping_key); + } } -void storage_wrapStorageKey(const uint8_t wrapping_key[64], const uint8_t key[64], uint8_t wrapped_key[64]) { - uint8_t iv[64]; - memcpy(iv, wrapping_key, sizeof(iv)); - aes128_cbc_sca_encrypt(wrapping_key, key, wrapped_key, 64, iv + 32); - memzero(iv, sizeof(iv)); +void storage_wrapStorageKey(const uint8_t wrapping_key[64], + const uint8_t key[64], uint8_t wrapped_key[64]) { + uint8_t iv[64]; + memcpy(iv, wrapping_key, sizeof(iv)); + aes128_cbc_sca_encrypt(wrapping_key, key, wrapped_key, 64, iv + 32); + memzero(iv, sizeof(iv)); } -void storage_unwrapStorageKey(const uint8_t wrapping_key[64], const uint8_t wrapped_key[64], uint8_t key[64]) { - uint8_t iv[64]; - memcpy(iv, wrapping_key, sizeof(iv)); - aes128_cbc_sca_decrypt(wrapping_key, wrapped_key, key, 64, iv + 32); - memzero(iv, sizeof(iv)); +void storage_unwrapStorageKey(const uint8_t wrapping_key[64], + const uint8_t wrapped_key[64], uint8_t key[64]) { + uint8_t iv[64]; + memcpy(iv, wrapping_key, sizeof(iv)); + aes128_cbc_sca_decrypt(wrapping_key, wrapped_key, key, 64, iv + 32); + memzero(iv, sizeof(iv)); } -void storage_unwrapStorageKey256(const uint8_t wrapping_key[64], const uint8_t wrapped_key[64], uint8_t key[64]) { - uint8_t iv[64]; - memcpy(iv, wrapping_key, sizeof(iv)); - aes_decrypt_ctx ctx; - aes_decrypt_key256(wrapping_key, &ctx); - aes_cbc_decrypt(wrapped_key, key, 64, iv + 32, &ctx); - memzero(&ctx, sizeof(ctx)); - memzero(iv, sizeof(iv)); +void storage_unwrapStorageKey256(const uint8_t wrapping_key[64], + const uint8_t wrapped_key[64], + uint8_t key[64]) { + uint8_t iv[64]; + memcpy(iv, wrapping_key, sizeof(iv)); + aes_decrypt_ctx ctx; + aes_decrypt_key256(wrapping_key, &ctx); + aes_cbc_decrypt(wrapped_key, key, 64, iv + 32, &ctx); + memzero(&ctx, sizeof(ctx)); + memzero(iv, sizeof(iv)); } void storage_keyFingerprint(const uint8_t key[64], uint8_t fingerprint[32]) { - sha256_Raw(key, 64, fingerprint); + sha256_Raw(key, 64, fingerprint); +} + +pintest_t storage_isPinCorrect_impl(const char *pin, uint8_t wrapped_key[64], + const uint8_t fingerprint[32], + bool *sca_hardened, + bool *v15_16_trans, + uint8_t key[64], + uint8_t random_salt[RANDOM_SALT_LEN]) { + /* + This function tests whether the PIN is correct. It will return + PIN_WRONG - PIN is incorrect + PIN_GOOD - PIN is correct + PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING + FUNCTION SHOULD storage_commit() If the pin is correct, the storage key may + have been rewrapped and returned in the wrapped_key parameter. Since the + *_impl functions are assumed to not touch the stored config state, the + rewrapped storage key will not have been saved to flash on exit from this + function. Thus, if the return is PIN_REWRAP, then the calling function is + required to update the flash with a storage_commit(). + */ + uint8_t wrapping_key[64]; + storage_deriveWrappingKey(pin, wrapping_key, *sca_hardened, *v15_16_trans, random_salt, + _("Verifying PIN")); + + // unwrap the storage key for fingerprint test + if (*sca_hardened) { + // key was wrapped using the sca-hardened method + storage_unwrapStorageKey(wrapping_key, wrapped_key, key); + } else { + // key was wrapped using deprecated method, unwrap for test + storage_unwrapStorageKey256(wrapping_key, wrapped_key, key); + } + + uint8_t fp[32]; + storage_keyFingerprint(key, fp); + + pintest_t ret = PIN_WRONG; + if (memcmp_s(fp, fingerprint, 32) == 0) ret = PIN_GOOD; + + if (ret == PIN_GOOD) { + if (!*sca_hardened || (*sca_hardened && !*v15_16_trans)) { + // PIN is correct but: + // 1. wrapping key needs to be regenerated using stretched key + // 2. storage key needs a rewrap with new wrapping key and algorithm + storage_deriveWrappingKey(pin, wrapping_key, + true /* sca_hardened */, + true /* v15_16_trans */, + random_salt, _("Verifying PIN")); + storage_wrapStorageKey(wrapping_key, key, wrapped_key); + *sca_hardened = true; + *v15_16_trans = true; + ret = PIN_REWRAP; + } + } + + if (!ret) memzero(key, 64); + memzero(wrapping_key, 64); + memzero(fp, 32); + return ret; } -pintest_t storage_isPinCorrect_impl( - const char *pin, uint8_t wrapped_key[64], const uint8_t fingerprint[32], - bool *sca_hardened, uint8_t key[64], uint8_t random_salt[RANDOM_SALT_LEN]) -{ -/* - This function tests whether the PIN is correct. It will return - PIN_WRONG - PIN is incorrect - PIN_GOOD - PIN is correct - PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING FUNCTION SHOULD storage_commit() - - If the pin is correct, the storage key may have been rewrapped and returned in the wrapped_key parameter. - Since the *_impl functions are assumed to not touch the stored config state, the - rewrapped storage key will not have been saved to flash on exit from this function. Thus, if the return is - PIN_REWRAP, then the calling function is required to update the flash with a storage_commit(). -*/ - uint8_t wrapping_key[64]; - storage_deriveWrappingKey(pin, wrapping_key, *sca_hardened, random_salt, - _("Verifying PIN")); - - // unwrap the storage key for fingerprint test - if (*sca_hardened) { - // key was wrapped using the sca-hardened method - storage_unwrapStorageKey(wrapping_key, wrapped_key, key); - } else { - // key was wrapped using deprecated method, unwrap for test - storage_unwrapStorageKey256(wrapping_key, wrapped_key, key); - } +pintest_t storage_isWipeCodeCorrect_impl(const char *wipe_code, + uint8_t wrapped_key[64], + const uint8_t fingerprint[32], + uint8_t key[64], + uint8_t random_salt[RANDOM_SALT_LEN]) { + uint8_t wrapping_key[64]; + storage_deriveWrappingKey(wipe_code, wrapping_key, true, true, random_salt, + _("Verifying PIN")); - uint8_t fp[32]; - storage_keyFingerprint(key, fp); - - pintest_t ret = PIN_WRONG; - if (memcmp_s(fp, fingerprint, 32) == 0) - ret = PIN_GOOD; - - if (ret == PIN_GOOD) { - if (!*sca_hardened) { - // PIN is correct but: - // 1. wrapping key needs to be regenerated using stretched key - // 2. storage key needs a rewrap with new wrapping key and algorithm - storage_deriveWrappingKey(pin, wrapping_key, true/* sca_hardened */, random_salt, _("Verifying PIN")); - storage_wrapStorageKey(wrapping_key, key, wrapped_key); - *sca_hardened = true; - ret = PIN_REWRAP; - } - } + // unwrap the storage key for fingerprint test + storage_unwrapStorageKey(wrapping_key, wrapped_key, key); + + uint8_t fp[32]; + storage_keyFingerprint(key, fp); - if (!ret) - memzero(key, 64); - memzero(wrapping_key, 64); - memzero(fp, 32); - return ret; + pintest_t ret = PIN_WRONG; + if (memcmp_s(fp, fingerprint, 32) == 0) { + ret = PIN_GOOD; + } + + if (!ret) { + memzero(key, 64); + } + memzero(wrapping_key, 64); + memzero(fp, 32); + return ret; } void storage_secMigrate(SessionState *ss, Storage *storage, bool encrypt) { - static CONFIDENTIAL char scratch[512]; - _Static_assert(sizeof(scratch) == sizeof(storage->encrypted_sec), - "Be extermely careful when changing the size of scratch."); - memzero(scratch, sizeof(scratch)); - - if (encrypt) { - if (!storage->has_sec) - return; - - memzero(storage->encrypted_sec, sizeof(storage->encrypted_sec)); - - // Serialize to scratch. - storage_writeHDNode(&scratch[0], 129, &storage->sec.node); - memcpy(&scratch[0] + 129, storage->sec.mnemonic, 241); - storage_writeCacheV1(&scratch[0] + 370, 75, &storage->sec.cache); - - // 63 reserved bytes - - // Take a fingerprint of the secrets so we can tell whether they've - // been correctly decrypted later. - storage->has_sec_fingerprint = true; - sha256_Raw((const uint8_t *)scratch, sizeof(scratch), storage->sec_fingerprint); - - // Encrypt with the storage key. - uint8_t iv[64]; - memcpy(iv, ss->storageKey, sizeof(iv)); - aes_encrypt_ctx ctx; - aes_encrypt_key256(ss->storageKey, &ctx); - aes_cbc_encrypt((const uint8_t*)scratch, storage->encrypted_sec, - sizeof(scratch), iv + 32, &ctx); - memzero(&ctx, sizeof(ctx)); - storage->encrypted_sec_version = STORAGE_VERSION; - } else { - memzero(&storage->sec, sizeof(storage->sec)); - storage->has_sec = false; - - // Decrypt with the storage key. - uint8_t iv[64]; - memcpy(iv, ss->storageKey, sizeof(iv)); - aes_decrypt_ctx ctx; - aes_decrypt_key256(ss->storageKey, &ctx); - aes_cbc_decrypt((const uint8_t*)storage->encrypted_sec, - (uint8_t*)&scratch[0], sizeof(scratch), - iv + 32, &ctx); - memzero(iv, sizeof(iv)); - - // De-serialize from scratch. - storage_readHDNode(&storage->sec.node, &scratch[0], 129); - memcpy(storage->sec.mnemonic, &scratch[0] + 129, 241); - storage_readCacheV1(&storage->sec.cache, &scratch[0] + 370, 75); - - // 63 reserved bytes - - // Check whether the secrets were correctly decrypted - uint8_t sec_fingerprint[32]; - sha256_Raw((const uint8_t *)scratch, sizeof(scratch), sec_fingerprint); - if (storage->has_sec_fingerprint) { - if (memcmp_s(storage->sec_fingerprint, sec_fingerprint, - sizeof(sec_fingerprint)) != 0) { - assert(false && "storage decrypt failure"); - memzero(scratch, sizeof(scratch)); - storage_wipe(); - layout_warning_static("Storage decrypt failure. Reboot device!"); - shutdown(); - } - } + static CONFIDENTIAL char scratch[512]; + _Static_assert(sizeof(scratch) == sizeof(storage->encrypted_sec), + "Be extermely careful when changing the size of scratch."); + memzero(scratch, sizeof(scratch)); - storage->has_sec_fingerprint = true; - memcpy(storage->sec_fingerprint, sec_fingerprint, - sizeof(sec_fingerprint)); + if (encrypt) { + if (!storage->has_sec) return; - // Derive the u2froot, if we haven't already. - if (storage->pub.has_mnemonic && !storage->pub.has_u2froot) { - storage_compute_u2froot(ss, storage->sec.mnemonic, &storage->pub.u2froot); - storage->pub.has_u2froot = true; - } + memzero(storage->encrypted_sec, sizeof(storage->encrypted_sec)); -#if DEBUG_LINK - memcpy(debuglink_mnemonic, storage->sec.mnemonic, sizeof(debuglink_mnemonic)); - storage_loadNode(&debuglink_node, &storage->sec.node); -#endif + // Serialize to scratch. + storage_writeHDNode(&scratch[0], 129, &storage->sec.node); + memcpy(&scratch[0] + 129, storage->sec.mnemonic, 241); + storage_writeCacheV1(&scratch[0] + 370, 75, &storage->sec.cache); - storage->has_sec = true; - } + // 63 reserved bytes - memzero(scratch, sizeof(scratch)); -} - -void storage_readStorageV1(SessionState *ss, Storage *storage, const char *ptr, size_t len) { - if (len < 464 + 17) - return; - storage->version = read_u32_le(ptr); - storage->pub.has_node = read_bool(ptr + 4); - storage_readHDNode(&storage->sec.node, ptr + 8, 140); - storage->pub.has_mnemonic = read_bool(ptr + 140); - memcpy(storage->sec.mnemonic, ptr + 141, 241); - storage->pub.passphrase_protection = read_bool(ptr + 383); - storage->pub.pin_failed_attempts = read_u32_le(ptr + 388); - storage->pub.has_pin = read_bool(ptr + 392); - memset(storage->sec.pin, 0, sizeof(storage->sec.pin)); - memcpy(storage->sec.pin, ptr + 393, 10); - storage->pub.has_language = read_bool(ptr + 403); - memset(storage->pub.language, 0, sizeof(storage->pub.language)); - memcpy(storage->pub.language, ptr + 404, 17); - storage->pub.has_label = read_bool(ptr + 421); - memset(storage->pub.label, 0, sizeof(storage->pub.label)); - memcpy(storage->pub.label, ptr + 422, 33); - storage->pub.no_backup = false; - storage->pub.imported = read_bool(ptr + 456); - if (storage->version == 1) { - storage->pub.policies_count = 0; - } else { - storage->pub.policies_count = 1; - storage_readPolicyV1(&storage->pub.policies[0], ptr + 464, 17); - } - storage->pub.has_auto_lock_delay_ms = true; - storage->pub.auto_lock_delay_ms = STORAGE_DEFAULT_SCREENSAVER_TIMEOUT; + // Take a fingerprint of the secrets so we can tell whether they've + // been correctly decrypted later. + storage->has_sec_fingerprint = true; + sha256_Raw((const uint8_t *)scratch, sizeof(scratch), + storage->sec_fingerprint); - // Can't do derivation here, since the pin hasn't been entered. - storage->pub.has_u2froot = false; - memzero(&storage->pub.u2froot, sizeof(storage->pub.u2froot)); - storage->pub.u2f_counter = 0; + // Encrypt with the storage key. + uint8_t iv[64]; + memcpy(iv, ss->storageKey, sizeof(iv)); + aes_encrypt_ctx ctx; + aes_encrypt_key256(ss->storageKey, &ctx); + aes_cbc_encrypt((const uint8_t *)scratch, storage->encrypted_sec, + sizeof(scratch), iv + 32, &ctx); + memzero(&ctx, sizeof(ctx)); + storage->encrypted_sec_version = STORAGE_VERSION; + } else { + memzero(&storage->sec, sizeof(storage->sec)); + storage->has_sec = false; - if (storage->version == 1) { - storage_resetPolicies(storage); - storage_resetCache(&storage->sec.cache); - } else { - storage_readCacheV1(&storage->sec.cache, ptr + 484, 75); + // Decrypt with the storage key. + uint8_t iv[64]; + memcpy(iv, ss->storageKey, sizeof(iv)); + aes_decrypt_ctx ctx; + aes_decrypt_key256(ss->storageKey, &ctx); + aes_cbc_decrypt((const uint8_t *)storage->encrypted_sec, + (uint8_t *)&scratch[0], sizeof(scratch), iv + 32, &ctx); + memzero(iv, sizeof(iv)); + + // De-serialize from scratch. + storage_readHDNode(&storage->sec.node, &scratch[0], 129); + memcpy(storage->sec.mnemonic, &scratch[0] + 129, 241); + storage_readCacheV1(&storage->sec.cache, &scratch[0] + 370, 75); + + // 63 reserved bytes + + // Check whether the secrets were correctly decrypted + uint8_t sec_fingerprint[32]; + sha256_Raw((const uint8_t *)scratch, sizeof(scratch), sec_fingerprint); + if (storage->has_sec_fingerprint) { + if (memcmp_s(storage->sec_fingerprint, sec_fingerprint, + sizeof(sec_fingerprint)) != 0) { + assert(false && "storage decrypt failure"); + memzero(scratch, sizeof(scratch)); + storage_wipe(); + layout_warning_static("Storage decrypt failure. Reboot device!"); + shutdown(); + } } - _Static_assert(sizeof(storage->pub.wrapped_storage_key) == 64, - "(un)wrapped key must be 64 bytes"); + storage->has_sec_fingerprint = true; + memcpy(storage->sec_fingerprint, sec_fingerprint, sizeof(sec_fingerprint)); - _Static_assert(sizeof(storage->pub.storage_key_fingerprint) == 32, - "key fingerprint must be 32 bytes"); + // Derive the u2froot, if we haven't already. + if (storage->pub.has_mnemonic && !storage->pub.has_u2froot) { + storage_compute_u2froot(ss, storage->sec.mnemonic, &storage->pub.u2froot); + storage->pub.has_u2froot = true; + } - random_buffer(storage->pub.random_salt, 32); +#if DEBUG_LINK + memcpy(debuglink_mnemonic, storage->sec.mnemonic, + sizeof(debuglink_mnemonic)); + storage_loadNode(&debuglink_node, &storage->sec.node); +#endif storage->has_sec = true; + } + + memzero(scratch, sizeof(scratch)); +} + +void storage_readStorageV1(SessionState *ss, Storage *storage, const char *ptr, + size_t len) { + if (len < 464 + 17) return; + storage->version = read_u32_le(ptr); + storage->pub.has_node = read_bool(ptr + 4); + storage_readHDNode(&storage->sec.node, ptr + 8, 140); + storage->pub.has_mnemonic = read_bool(ptr + 140); + memcpy(storage->sec.mnemonic, ptr + 141, 241); + storage->pub.passphrase_protection = read_bool(ptr + 383); + storage->pub.pin_failed_attempts = read_u32_le(ptr + 388); + storage->pub.has_pin = read_bool(ptr + 392); + memset(storage->sec.pin, 0, sizeof(storage->sec.pin)); + memcpy(storage->sec.pin, ptr + 393, 10); + storage->pub.has_language = read_bool(ptr + 403); + memset(storage->pub.language, 0, sizeof(storage->pub.language)); + memcpy(storage->pub.language, ptr + 404, 17); + storage->pub.has_label = read_bool(ptr + 421); + memset(storage->pub.label, 0, sizeof(storage->pub.label)); + memcpy(storage->pub.label, ptr + 422, 33); + storage->pub.no_backup = false; + storage->pub.imported = read_bool(ptr + 456); + if (storage->version == 1) { + storage->pub.policies_count = 0; + } else { + storage->pub.policies_count = 1; + storage_readPolicyV1(&storage->pub.policies[0], ptr + 464, 17); + } + storage->pub.has_auto_lock_delay_ms = true; + storage->pub.auto_lock_delay_ms = STORAGE_DEFAULT_SCREENSAVER_TIMEOUT; + + // Can't do derivation here, since the pin hasn't been entered. + storage->pub.has_u2froot = false; + memzero(&storage->pub.u2froot, sizeof(storage->pub.u2froot)); + storage->pub.u2f_counter = 0; + + if (storage->version == 1) { + storage_resetPolicies(storage); + storage_resetCache(&storage->sec.cache); + } else { + storage_readCacheV1(&storage->sec.cache, ptr + 484, 75); + } + + _Static_assert(sizeof(storage->pub.wrapped_storage_key) == 64, + "(un)wrapped key must be 64 bytes"); + + _Static_assert(sizeof(storage->pub.storage_key_fingerprint) == 32, + "key fingerprint must be 32 bytes"); - storage_setPin_impl(ss, storage, storage->pub.has_pin ? storage->sec.pin : ""); + random_buffer(storage->pub.random_salt, 32); - storage->has_sec_fingerprint = false; + storage->has_sec = true; + + storage_setPin_impl(ss, storage, + storage->pub.has_pin ? storage->sec.pin : ""); + + storage->has_sec_fingerprint = false; #if DEBUG_LINK - strncpy(debuglink_pin, storage->sec.pin, sizeof(debuglink_pin)); - memcpy(debuglink_mnemonic, storage->sec.mnemonic, sizeof(debuglink_mnemonic)); - storage_loadNode(&debuglink_node, &storage->sec.node); + strncpy(debuglink_pin, storage->sec.pin, sizeof(debuglink_pin)); + memcpy(debuglink_mnemonic, storage->sec.mnemonic, sizeof(debuglink_mnemonic)); + storage_loadNode(&debuglink_node, &storage->sec.node); #endif - if (storage->pub.has_pin) { - session_clear_impl(ss, storage, /*clear_pin=*/true); - // No need to storage_commit() here, it will get done - } + if (storage->pub.has_pin) { + session_clear_impl(ss, storage, /*clear_pin=*/true); + // No need to storage_commit() here, it will get done + } } void storage_writeStorageV11(char *ptr, size_t len, const Storage *storage) { - if (len < 852) - return; - write_u32_le(ptr, storage->version); - - uint32_t flags = - (storage->pub.has_pin ? (1u << 0) : 0) | - (storage->pub.has_language ? (1u << 1) : 0) | - (storage->pub.has_label ? (1u << 2) : 0) | - (storage->pub.has_auto_lock_delay_ms ? (1u << 3) : 0) | - (storage->pub.imported ? (1u << 4) : 0) | - (storage->pub.passphrase_protection ? (1u << 5) : 0) | - (/* ShapeShift policy, enabled always */ (1u << 6) ) | - (/* Pin Caching policy, enabled always */ (1u << 7) ) | - (storage->pub.has_node ? (1u << 8) : 0) | - (storage->pub.has_mnemonic ? (1u << 9) : 0) | - (storage->pub.has_u2froot ? (1u << 10) : 0) | - (storage_isPolicyEnabled("Experimental") ? (1u << 11) : 0) | - (storage_isPolicyEnabled("AdvancedMode") ? (1u << 12) : 0) | - (storage->pub.no_backup ? (1u << 13) : 0) | - (storage->has_sec_fingerprint ? (1u << 14) : 0) | - (storage->pub.sca_hardened ? (1u << 15) : 0) | - /* reserved 31:16 */ 0; - write_u32_le(ptr + 4, flags); - - write_u32_le(ptr + 8, storage->pub.pin_failed_attempts); - write_u32_le(ptr + 12, storage->pub.auto_lock_delay_ms); - - memcpy(ptr + 16, storage->pub.language, 16); - memcpy(ptr + 32, storage->pub.label, 48); - - memcpy(ptr + 80, storage->pub.wrapped_storage_key, 64); - memcpy(ptr + 144, storage->pub.storage_key_fingerprint, 32); - - storage_writeHDNode(ptr + 176, 129, &storage->pub.u2froot); - write_u32_le(ptr + 305, storage->pub.u2f_counter); + if (len < 852) return; + write_u32_le(ptr, storage->version); - if (storage->has_sec_fingerprint) { - memcpy(ptr + 309, storage->sec_fingerprint, 32); - } + uint32_t flags = (storage->pub.has_pin ? (1u << 0) : 0) | + (storage->pub.has_language ? (1u << 1) : 0) | + (storage->pub.has_label ? (1u << 2) : 0) | + (storage->pub.has_auto_lock_delay_ms ? (1u << 3) : 0) | + (storage->pub.imported ? (1u << 4) : 0) | + (storage->pub.passphrase_protection ? (1u << 5) : 0) | + (/* ShapeShift policy, enabled always */ (1u << 6)) | + (/* Pin Caching policy, enabled always */ (1u << 7)) | + (storage->pub.has_node ? (1u << 8) : 0) | + (storage->pub.has_mnemonic ? (1u << 9) : 0) | + (storage->pub.has_u2froot ? (1u << 10) : 0) | + (storage_isPolicyEnabled("Experimental") ? (1u << 11) : 0) | + (storage_isPolicyEnabled("AdvancedMode") ? (1u << 12) : 0) | + (storage->pub.no_backup ? (1u << 13) : 0) | + (storage->has_sec_fingerprint ? (1u << 14) : 0) | + (storage->pub.sca_hardened ? (1u << 15) : 0) | + /* reserved 31:16 */ 0; + write_u32_le(ptr + 4, flags); - memcpy(ptr + 341, storage->pub.random_salt, 32); + write_u32_le(ptr + 8, storage->pub.pin_failed_attempts); + write_u32_le(ptr + 12, storage->pub.auto_lock_delay_ms); - // 91 reserved bytes + memcpy(ptr + 16, storage->pub.language, 16); + memcpy(ptr + 32, storage->pub.label, 48); - // Ignore whatever was in storage->sec. Only encrypted_sec can be committed. - // Yes, this is a potential footgun. No, there's nothing we can do about it here. + memcpy(ptr + 80, storage->pub.wrapped_storage_key, 64); + memcpy(ptr + 144, storage->pub.storage_key_fingerprint, 32); - // Note: the encrypted_sec_version is not necessarily STORAGE_VERSION. If - // storage is committed without pin entry on storage upgrade, the plaintext - // and ciphertext storage sections will have different versions. - write_u32_le(ptr + 464, storage->encrypted_sec_version); + storage_writeHDNode(ptr + 176, 129, &storage->pub.u2froot); + write_u32_le(ptr + 305, storage->pub.u2f_counter); - memcpy(ptr + 468, storage->encrypted_sec, sizeof(storage->encrypted_sec)); -} + if (storage->has_sec_fingerprint) { + memcpy(ptr + 309, storage->sec_fingerprint, 32); + } -void storage_readStorageV11(Storage *storage, const char *ptr, size_t len) { - if (len < 852) - return; - - storage->version = read_u32_le(ptr); - - uint32_t flags = read_u32_le(ptr + 4); - storage->pub.has_pin = flags & (1u << 0); - storage->pub.has_language = flags & (1u << 1); - storage->pub.has_label = flags & (1u << 2); - storage->pub.has_auto_lock_delay_ms = flags & (1u << 3); - storage->pub.imported = flags & (1u << 4); - storage->pub.passphrase_protection = flags & (1u << 5); - storage_readPolicyV2(&storage->pub.policies[0], "ShapeShift", true); - storage_readPolicyV2(&storage->pub.policies[1], "Pin Caching", true); - storage->pub.has_node = flags & (1u << 8); - storage->pub.has_mnemonic = flags & (1u << 9); - storage->pub.has_u2froot = flags & (1u << 10); - storage_readPolicyV2(&storage->pub.policies[2], "Experimental", flags & (1u << 11)); - storage_readPolicyV2(&storage->pub.policies[3], "AdvancedMode", flags & (1u << 12)); - storage->pub.no_backup = flags & (1u << 13); - storage->has_sec_fingerprint = flags & (1u << 14); - storage->pub.sca_hardened = flags & (1u << 15); - - storage->pub.policies_count = POLICY_COUNT; - - storage->pub.pin_failed_attempts = read_u32_le(ptr + 8); - storage->pub.auto_lock_delay_ms = MAX(read_u32_le(ptr + 12), - STORAGE_MIN_SCREENSAVER_TIMEOUT); - - memset(storage->pub.language, 0, sizeof(storage->pub.language)); - memcpy(storage->pub.language, ptr + 16, 16); - - memset(storage->pub.label, 0, sizeof(storage->pub.label)); - memcpy(storage->pub.label, ptr + 32, 48); - - memcpy(storage->pub.wrapped_storage_key, ptr + 80, 64); - memcpy(storage->pub.storage_key_fingerprint, ptr + 144, 32); - - storage_readHDNode(&storage->pub.u2froot, ptr + 176, 129); - storage->pub.u2f_counter = read_u32_le(ptr + 305); + memcpy(ptr + 341, storage->pub.random_salt, 32); - if (storage->has_sec_fingerprint) { - memcpy(storage->sec_fingerprint, ptr + 309, 32); - } else { - memset(storage->sec_fingerprint, 0, sizeof(storage->sec_fingerprint)); - } + // 91 reserved bytes - memcpy(storage->pub.random_salt, ptr + 341, 32); + // Ignore whatever was in storage->sec. Only encrypted_sec can be committed. + // Yes, this is a potential footgun. No, there's nothing we can do about it + // here. - // 91 reserved bytes + // Note: the encrypted_sec_version is not necessarily STORAGE_VERSION. If + // storage is committed without pin entry on storage upgrade, the plaintext + // and ciphertext storage sections will have different versions. + write_u32_le(ptr + 464, storage->encrypted_sec_version); - storage->has_sec = false; - memzero(&storage->sec, sizeof(storage->sec)); - storage->encrypted_sec_version = read_u32_le(ptr + 464); - memcpy(storage->encrypted_sec, ptr + 468, sizeof(storage->encrypted_sec)); + memcpy(ptr + 468, storage->encrypted_sec, sizeof(storage->encrypted_sec)); +} + +void storage_readStorageV11(Storage *storage, const char *ptr, size_t len) { + if (len < 852) return; + + storage->version = read_u32_le(ptr); + + uint32_t flags = read_u32_le(ptr + 4); + storage->pub.has_pin = flags & (1u << 0); + storage->pub.has_language = flags & (1u << 1); + storage->pub.has_label = flags & (1u << 2); + storage->pub.has_auto_lock_delay_ms = flags & (1u << 3); + storage->pub.imported = flags & (1u << 4); + storage->pub.passphrase_protection = flags & (1u << 5); + storage_readPolicyV2(&storage->pub.policies[0], "ShapeShift", true); + storage_readPolicyV2(&storage->pub.policies[1], "Pin Caching", true); + storage->pub.has_node = flags & (1u << 8); + storage->pub.has_mnemonic = flags & (1u << 9); + storage->pub.has_u2froot = flags & (1u << 10); + storage_readPolicyV2(&storage->pub.policies[2], "Experimental", + flags & (1u << 11)); + storage_readPolicyV2(&storage->pub.policies[3], "AdvancedMode", + flags & (1u << 12)); + storage->pub.no_backup = flags & (1u << 13); + storage->has_sec_fingerprint = flags & (1u << 14); + storage->pub.sca_hardened = flags & (1u << 15); + storage->pub.v15_16_trans = false; + + storage->pub.policies_count = POLICY_COUNT; + + storage->pub.pin_failed_attempts = read_u32_le(ptr + 8); + storage->pub.auto_lock_delay_ms = + MAX(read_u32_le(ptr + 12), STORAGE_MIN_SCREENSAVER_TIMEOUT); + + memset(storage->pub.language, 0, sizeof(storage->pub.language)); + memcpy(storage->pub.language, ptr + 16, 16); + + memset(storage->pub.label, 0, sizeof(storage->pub.label)); + memcpy(storage->pub.label, ptr + 32, 48); + + memcpy(storage->pub.wrapped_storage_key, ptr + 80, 64); + memcpy(storage->pub.storage_key_fingerprint, ptr + 144, 32); + + storage_readHDNode(&storage->pub.u2froot, ptr + 176, 129); + storage->pub.u2f_counter = read_u32_le(ptr + 305); + + if (storage->has_sec_fingerprint) { + memcpy(storage->sec_fingerprint, ptr + 309, 32); + } else { + memset(storage->sec_fingerprint, 0, sizeof(storage->sec_fingerprint)); + } + + memcpy(storage->pub.random_salt, ptr + 341, 32); + + // 91 reserved bytes + + storage->has_sec = false; + memzero(&storage->sec, sizeof(storage->sec)); + storage->encrypted_sec_version = read_u32_le(ptr + 464); + memcpy(storage->encrypted_sec, ptr + 468, sizeof(storage->encrypted_sec)); +} + +void storage_writeStorageV16(char *ptr, size_t len, const Storage *storage) { + if (len < 852) return; + write_u32_le(ptr, storage->version); + + uint32_t flags = (storage->pub.has_pin ? (1u << 0) : 0) | + (storage->pub.has_language ? (1u << 1) : 0) | + (storage->pub.has_label ? (1u << 2) : 0) | + (storage->pub.has_auto_lock_delay_ms ? (1u << 3) : 0) | + (storage->pub.imported ? (1u << 4) : 0) | + (storage->pub.passphrase_protection ? (1u << 5) : 0) | + (/* ShapeShift policy, enabled always */ (1u << 6)) | + (/* Pin Caching policy, enabled always */ (1u << 7)) | + (storage->pub.has_node ? (1u << 8) : 0) | + (storage->pub.has_mnemonic ? (1u << 9) : 0) | + (storage->pub.has_u2froot ? (1u << 10) : 0) | + (storage_isPolicyEnabled("Experimental") ? (1u << 11) : 0) | + (storage_isPolicyEnabled("AdvancedMode") ? (1u << 12) : 0) | + (storage->pub.no_backup ? (1u << 13) : 0) | + (storage->has_sec_fingerprint ? (1u << 14) : 0) | + (storage->pub.sca_hardened ? (1u << 15) : 0) | + (storage->pub.has_wipe_code ? (1u << 16) : 0) | + (storage->pub.v15_16_trans ? (1u << 17) : 0) | + /* reserved 31:18 */ 0; + write_u32_le(ptr + 4, flags); + + write_u32_le(ptr + 8, storage->pub.pin_failed_attempts); + write_u32_le(ptr + 12, storage->pub.auto_lock_delay_ms); + + memcpy(ptr + 16, storage->pub.language, 16); + memcpy(ptr + 32, storage->pub.label, 48); + + memcpy(ptr + 80, storage->pub.wrapped_storage_key, 64); + memcpy(ptr + 144, storage->pub.storage_key_fingerprint, 32); + memcpy(ptr + 176, storage->pub.wrapped_wipe_code_key, 64); + memcpy(ptr + 240, storage->pub.wipe_code_key_fingerprint, 32); + + storage_writeHDNode(ptr + 272, 129, &storage->pub.u2froot); + write_u32_le(ptr + 401, storage->pub.u2f_counter); + + if (storage->has_sec_fingerprint) { + memcpy(ptr + 405, storage->sec_fingerprint, 32); + } + + memcpy(ptr + 437, storage->pub.random_salt, 32); + // 1028 reserved bytes + + // Ignore whatever was in storage->sec. Only encrypted_sec can be committed. + // Yes, this is a potential footgun. No, there's nothing we can do about it + // here. + + // Note: the encrypted_sec_version is not necessarily STORAGE_VERSION. If + // storage is committed without pin entry on storage upgrade, the plaintext + // and ciphertext storage sections will have different versions. + write_u32_le(ptr + 1497, storage->encrypted_sec_version); + + memcpy(ptr + 1501, storage->encrypted_sec, sizeof(storage->encrypted_sec)); +} + +void storage_readStorageV16(Storage *storage, const char *ptr, size_t len) { + if (len < 852) return; + + storage->version = read_u32_le(ptr); + + uint32_t flags = read_u32_le(ptr + 4); + storage->pub.has_pin = flags & (1u << 0); + storage->pub.has_language = flags & (1u << 1); + storage->pub.has_label = flags & (1u << 2); + storage->pub.has_auto_lock_delay_ms = flags & (1u << 3); + storage->pub.imported = flags & (1u << 4); + storage->pub.passphrase_protection = flags & (1u << 5); + storage_readPolicyV2(&storage->pub.policies[0], "ShapeShift", true); + storage_readPolicyV2(&storage->pub.policies[1], "Pin Caching", true); + storage->pub.has_node = flags & (1u << 8); + storage->pub.has_mnemonic = flags & (1u << 9); + storage->pub.has_u2froot = flags & (1u << 10); + storage_readPolicyV2(&storage->pub.policies[2], "Experimental", + flags & (1u << 11)); + storage_readPolicyV2(&storage->pub.policies[3], "AdvancedMode", + flags & (1u << 12)); + storage->pub.no_backup = flags & (1u << 13); + storage->has_sec_fingerprint = flags & (1u << 14); + storage->pub.sca_hardened = flags & (1u << 15); + storage->pub.has_wipe_code = flags & (1u << 16); + storage->pub.v15_16_trans = flags & (1u << 17); + + storage->pub.policies_count = POLICY_COUNT; + + storage->pub.pin_failed_attempts = read_u32_le(ptr + 8); + storage->pub.auto_lock_delay_ms = + MAX(read_u32_le(ptr + 12), STORAGE_MIN_SCREENSAVER_TIMEOUT); + + memset(storage->pub.language, 0, sizeof(storage->pub.language)); + memcpy(storage->pub.language, ptr + 16, 16); + + memset(storage->pub.label, 0, sizeof(storage->pub.label)); + memcpy(storage->pub.label, ptr + 32, 48); + + memcpy(storage->pub.wrapped_storage_key, ptr + 80, 64); + memcpy(storage->pub.storage_key_fingerprint, ptr + 144, 32); + + memcpy(storage->pub.wrapped_wipe_code_key, ptr + 176, 64); + memcpy(storage->pub.wipe_code_key_fingerprint, ptr + 240, 32); + + storage_readHDNode(&storage->pub.u2froot, ptr + 272, 129); + storage->pub.u2f_counter = read_u32_le(ptr + 401); + + if (storage->has_sec_fingerprint) { + memcpy(storage->sec_fingerprint, ptr + 405, 32); + } else { + memset(storage->sec_fingerprint, 0, sizeof(storage->sec_fingerprint)); + } + + memcpy(storage->pub.random_salt, ptr + 437, 32); + // 1028 reserved bytes + + storage->has_sec = false; + memzero(&storage->sec, sizeof(storage->sec)); + storage->encrypted_sec_version = read_u32_le(ptr + 1497); + memcpy(storage->encrypted_sec, ptr + 1501, sizeof(storage->encrypted_sec)); } void storage_readCacheV1(Cache *cache, const char *ptr, size_t len) { - if (len < 65 + 10) - return; - cache->root_seed_cache_status = read_u8(ptr); - memcpy(cache->root_seed_cache, ptr + 1, 64); - memcpy(cache->root_ecdsa_curve_type, ptr + 65, 10); + if (len < 65 + 10) return; + cache->root_seed_cache_status = read_u8(ptr); + memcpy(cache->root_seed_cache, ptr + 1, 64); + memcpy(cache->root_ecdsa_curve_type, ptr + 65, 10); } void storage_writeCacheV1(char *ptr, size_t len, const Cache *cache) { - if (len < 65 + 10) - return; - write_u8(ptr, cache->root_seed_cache_status); - memcpy(ptr + 1, cache->root_seed_cache, 64); - memcpy(ptr + 65, cache->root_ecdsa_curve_type, 10); + if (len < 65 + 10) return; + write_u8(ptr, cache->root_seed_cache_status); + memcpy(ptr + 1, cache->root_seed_cache, 64); + memcpy(ptr + 65, cache->root_ecdsa_curve_type, 10); } _Static_assert(offsetof(Cache, root_seed_cache) == 1, "rsc"); _Static_assert(offsetof(Cache, root_ecdsa_curve_type) == 65, "rect"); -_Static_assert(sizeof(((Cache*)0)->root_ecdsa_curve_type) == 10, "rect"); +_Static_assert(sizeof(((Cache *)0)->root_ecdsa_curve_type) == 10, "rect"); -void storage_readV1(SessionState *ss, ConfigFlash *dst, const char *flash, size_t len) { - if (len < 44 + 528) - return; - storage_readMeta(&dst->meta, flash, 44); - storage_readStorageV1(ss, &dst->storage, flash + 44, 481); +void storage_readV1(SessionState *ss, ConfigFlash *dst, const char *flash, + size_t len) { + if (len < 44 + 528) return; + storage_readMeta(&dst->meta, flash, 44); + storage_readStorageV1(ss, &dst->storage, flash + 44, 481); } -void storage_readV2(SessionState *ss, ConfigFlash *dst, const char *flash, size_t len) { - if (len < 528 + 75) - return; - storage_readMeta(&dst->meta, flash, 44); - storage_readStorageV1(ss, &dst->storage, flash + 44, 481); +void storage_readV2(SessionState *ss, ConfigFlash *dst, const char *flash, + size_t len) { + if (len < 528 + 75) return; + storage_readMeta(&dst->meta, flash, 44); + storage_readStorageV1(ss, &dst->storage, flash + 44, 481); } void storage_readV11(ConfigFlash *dst, const char *flash, size_t len) { - if (len < 1024) - return; - storage_readMeta(&dst->meta, flash, 44); - storage_readStorageV11(&dst->storage, flash + 44, 852); + if (len < 1024) return; + storage_readMeta(&dst->meta, flash, 44); + storage_readStorageV11(&dst->storage, flash + 44, 852); } void storage_writeV11(char *flash, size_t len, const ConfigFlash *src) { - if (len < 1024) - return; - storage_writeMeta(flash, 44, &src->meta); - storage_writeStorageV11(flash + 44, 852, &src->storage); -} - -StorageUpdateStatus storage_fromFlash(SessionState *ss, ConfigFlash *dst, const char *flash) -{ - memzero(dst, sizeof(*dst)); - - // Load config values from active config node. - enum StorageVersion version = - version_from_int(read_u32_le(flash + 44)); - - switch (version) - { - case StorageVersion_1: - storage_readV1(ss, dst, flash, STORAGE_SECTOR_LEN); - dst->storage.version = STORAGE_VERSION; - return SUS_Updated; - - case StorageVersion_2: - case StorageVersion_3: - case StorageVersion_4: - case StorageVersion_5: - case StorageVersion_6: - case StorageVersion_7: - case StorageVersion_8: - case StorageVersion_9: - case StorageVersion_10: - storage_readV2(ss, dst, flash, STORAGE_SECTOR_LEN); - dst->storage.version = STORAGE_VERSION; - - /* We have to do this for users with bootloaders <= v1.0.2. This - scenario would only happen after a firmware install from the same - storage version */ - if (dst->storage.pub.policies_count == 0xFFFFFFFF) - { - storage_resetPolicies(&dst->storage); - storage_resetCache(&dst->storage.sec.cache); - return SUS_Updated; - } - - storage_upgradePolicies(&dst->storage); - - return dst->storage.version == version - ? SUS_Valid - : SUS_Updated; - - case StorageVersion_11: - case StorageVersion_12: - case StorageVersion_13: - case StorageVersion_14: - case StorageVersion_15: - storage_readV11(dst, flash, STORAGE_SECTOR_LEN); - dst->storage.version = STORAGE_VERSION; - return dst->storage.version == version - ? SUS_Valid - : SUS_Updated; - - case StorageVersion_NONE: - return SUS_Invalid; - - // DO *NOT* add a default case - } + if (len < 1024) return; + storage_writeMeta(flash, 44, &src->meta); + storage_writeStorageV11(flash + 44, 852, &src->storage); +} + +void storage_readV16(ConfigFlash *dst, const char *flash, size_t len) { + if (len < 1024) return; + storage_readMeta(&dst->meta, flash, 44); + storage_readStorageV16(&dst->storage, flash + 44, 852); +} + +void storage_writeV16(char *flash, size_t len, const ConfigFlash *src) { + if (len < 1024) return; + storage_writeMeta(flash, 44, &src->meta); + storage_writeStorageV16(flash + 44, 852, &src->storage); +} + +StorageUpdateStatus storage_fromFlash(SessionState *ss, ConfigFlash *dst, + const char *flash) { + memzero(dst, sizeof(*dst)); + + // Load config values from active config node. + enum StorageVersion version = version_from_int(read_u32_le(flash + 44)); + + switch (version) { + case StorageVersion_1: + storage_readV1(ss, dst, flash, STORAGE_SECTOR_LEN); + dst->storage.version = STORAGE_VERSION; + return SUS_Updated; + + case StorageVersion_2: + case StorageVersion_3: + case StorageVersion_4: + case StorageVersion_5: + case StorageVersion_6: + case StorageVersion_7: + case StorageVersion_8: + case StorageVersion_9: + case StorageVersion_10: + storage_readV2(ss, dst, flash, STORAGE_SECTOR_LEN); + dst->storage.version = STORAGE_VERSION; + + /* We have to do this for users with bootloaders <= v1.0.2. This + scenario would only happen after a firmware install from the same + storage version */ + if (dst->storage.pub.policies_count == 0xFFFFFFFF) { + storage_resetPolicies(&dst->storage); + storage_resetCache(&dst->storage.sec.cache); + return SUS_Updated; + } + + storage_upgradePolicies(&dst->storage); + + return dst->storage.version == version ? SUS_Valid : SUS_Updated; + + case StorageVersion_11: + case StorageVersion_12: + case StorageVersion_13: + case StorageVersion_14: + case StorageVersion_15: + storage_readV11(dst, flash, STORAGE_SECTOR_LEN); + dst->storage.version = STORAGE_VERSION; + return dst->storage.version == version ? SUS_Valid : SUS_Updated; + case StorageVersion_16: + storage_readV16(dst, flash, STORAGE_SECTOR_LEN); + dst->storage.version = STORAGE_VERSION; + return dst->storage.version == version ? SUS_Valid : SUS_Updated; + + case StorageVersion_NONE: + return SUS_Invalid; + + // DO *NOT* add a default case + } #ifdef DEBUG_ON - // Should be unreachable, but we don't want to tell the compiler that in a - // release build. The benefit to doing it this way is that with the - // unreachable and lack of default case in the switch, the compiler will - // tell us if we have not covered every case in the switch. - __builtin_unreachable(); + // Should be unreachable, but we don't want to tell the compiler that in a + // release build. The benefit to doing it this way is that with the + // unreachable and lack of default case in the switch, the compiler will + // tell us if we have not covered every case in the switch. + __builtin_unreachable(); #endif - return SUS_Invalid; + return SUS_Invalid; } /// \brief Shifts sector for config storage -static void wear_leveling_shift(void) -{ - switch(storage_location) - { - case FLASH_STORAGE1: - { - storage_location = FLASH_STORAGE2; - break; - } +static void wear_leveling_shift(void) { + switch (storage_location) { + case FLASH_STORAGE1: { + storage_location = FLASH_STORAGE2; + break; + } - case FLASH_STORAGE2: - { - storage_location = FLASH_STORAGE3; - break; - } + case FLASH_STORAGE2: { + storage_location = FLASH_STORAGE3; + break; + } - /* wraps around */ - case FLASH_STORAGE3: - { - storage_location = FLASH_STORAGE1; - break; - } + /* wraps around */ + case FLASH_STORAGE3: { + storage_location = FLASH_STORAGE1; + break; + } - default: - { - storage_location = STORAGE_SECT_DEFAULT; - break; - } + default: { + storage_location = STORAGE_SECT_DEFAULT; + break; } + } } /// \brief Set root session seed in storage. @@ -827,25 +991,22 @@ static void wear_leveling_shift(void) /// \param cfg[in] The active storage sector. /// \param seed[in] Root seed to write into storage. /// \param curve[in] ECDSA curve name being used. -static void storage_setRootSeedCache(const SessionState *ss, - ConfigFlash *cfg, const uint8_t *seed, - const char* curve) -{ - // Don't cache when passphrase protection is enabled. - if (cfg->storage.pub.passphrase_protection && strlen(ss->passphrase)) - return; +static void storage_setRootSeedCache(const SessionState *ss, ConfigFlash *cfg, + const uint8_t *seed, const char *curve) { + // Don't cache when passphrase protection is enabled. + if (cfg->storage.pub.passphrase_protection && strlen(ss->passphrase)) return; - memset(&cfg->storage.sec.cache, 0, sizeof(cfg->storage.sec.cache)); + memset(&cfg->storage.sec.cache, 0, sizeof(cfg->storage.sec.cache)); - memcpy(&cfg->storage.sec.cache.root_seed_cache, seed, - sizeof(cfg->storage.sec.cache.root_seed_cache)); + memcpy(&cfg->storage.sec.cache.root_seed_cache, seed, + sizeof(cfg->storage.sec.cache.root_seed_cache)); - strlcpy(cfg->storage.sec.cache.root_ecdsa_curve_type, curve, - sizeof(cfg->storage.sec.cache.root_ecdsa_curve_type)); + strlcpy(cfg->storage.sec.cache.root_ecdsa_curve_type, curve, + sizeof(cfg->storage.sec.cache.root_ecdsa_curve_type)); - cfg->storage.sec.cache.root_seed_cache_status = CACHE_EXISTS; - cfg->storage.has_sec = true; - storage_commit(); + cfg->storage.sec.cache.root_seed_cache_status = CACHE_EXISTS; + cfg->storage.has_sec = true; + storage_commit(); } /// \brief Get root session seed cache from storage. @@ -856,845 +1017,855 @@ static void storage_setRootSeedCache(const SessionState *ss, /// \returns true on success. static bool storage_getRootSeedCache(const SessionState *ss, ConfigFlash *cfg, const char *curve, bool usePassphrase, - uint8_t *seed) -{ - if (!cfg->storage.has_sec) - return false; - - if (cfg->storage.sec.cache.root_seed_cache_status != CACHE_EXISTS) - return false; + uint8_t *seed) { + if (!cfg->storage.has_sec) return false; - if (usePassphrase && cfg->storage.pub.passphrase_protection && - strlen(ss->passphrase)) { - return false; - } - - if (strcmp(cfg->storage.sec.cache.root_ecdsa_curve_type, curve) != 0) { - return false; - } + if (cfg->storage.sec.cache.root_seed_cache_status != CACHE_EXISTS) + return false; - memset(seed, 0, sizeof(ss->seed)); - memcpy(seed, &cfg->storage.sec.cache.root_seed_cache, - sizeof(cfg->storage.sec.cache.root_seed_cache)); - _Static_assert(sizeof(ss->seed) == sizeof(cfg->storage.sec.cache.root_seed_cache), - "size mismatch"); - return true; -} + if (usePassphrase && cfg->storage.pub.passphrase_protection && + strlen(ss->passphrase)) { + return false; + } -void storage_init(void) -{ - // Find storage sector with valid data and set storage_location variable. - if (!find_active_storage(&storage_location)) { - // Otherwise initialize it to the default sector. - storage_location = STORAGE_SECT_DEFAULT; - } - const char *flash = (const char *)flash_write_helper(storage_location); - - // Reset shadow configuration in RAM - storage_reset_impl(&session, &shadow_config); - - // If the storage partition is not already active - if (!storage_isActiveSector(flash)) { - // ... activate it by pupoulating new Metadata section, - // and writing it to flash. - storage_resetUuid(); - storage_commit(); - return; - } + if (strcmp(cfg->storage.sec.cache.root_ecdsa_curve_type, curve) != 0) { + return false; + } + + memset(seed, 0, sizeof(ss->seed)); + memcpy(seed, &cfg->storage.sec.cache.root_seed_cache, + sizeof(cfg->storage.sec.cache.root_seed_cache)); + _Static_assert( + sizeof(ss->seed) == sizeof(cfg->storage.sec.cache.root_seed_cache), + "size mismatch"); + return true; +} + +void storage_init(void) { + // Find storage sector with valid data and set storage_location variable. + if (!find_active_storage(&storage_location)) { + // Otherwise initialize it to the default sector. + storage_location = STORAGE_SECT_DEFAULT; + } + const char *flash = (const char *)flash_write_helper(storage_location); + + // Reset shadow configuration in RAM + storage_reset_impl(&session, &shadow_config); + + // If the storage partition is not already active + if (!storage_isActiveSector(flash)) { + // ... activate it by pupoulating new Metadata section, + // and writing it to flash. + storage_resetUuid(); + storage_commit(); + return; + } - // Otherwise clear out flash before looking for end config node. - memcpy(shadow_config.meta.uuid, ((const Metadata *)flash)->uuid, - sizeof(shadow_config.meta.uuid)); - data2hex(shadow_config.meta.uuid, sizeof(shadow_config.meta.uuid), - shadow_config.meta.uuid_str); + // Otherwise clear out flash before looking for end config node. + memcpy(shadow_config.meta.uuid, ((const Metadata *)flash)->uuid, + sizeof(shadow_config.meta.uuid)); + data2hex(shadow_config.meta.uuid, sizeof(shadow_config.meta.uuid), + shadow_config.meta.uuid_str); - // Load storage from flash, and update it if necessary. - switch (storage_fromFlash(&session, &shadow_config, flash)) { + // Load storage from flash, and update it if necessary. + switch (storage_fromFlash(&session, &shadow_config, flash)) { case SUS_Invalid: - storage_reset(); - storage_commit(); - break; + storage_reset(); + storage_commit(); + break; case SUS_Valid: - break; + break; case SUS_Updated: - // If the version changed, write the new storage to flash so - // that it's available on next boot without conversion. - storage_commit(); - break; - } - - if (!storage_hasPin()) { - // Cache the PIN + // If the version changed, write the new storage to flash so + // that it's available on next boot without conversion. + storage_commit(); + break; + } + + if (!storage_hasPin()) { + // Cache the PIN #ifndef NDEBUG - bool ret = + bool ret = #endif storage_isPinCorrect(""); - assert(ret && "Empty PIN not cached?"); - } + assert(ret && "Empty PIN not cached?"); + } } -void storage_resetUuid(void) -{ - storage_resetUuid_impl(&shadow_config); -} +void storage_resetUuid(void) { storage_resetUuid_impl(&shadow_config); } -void storage_resetUuid_impl(ConfigFlash *cfg) -{ +void storage_resetUuid_impl(ConfigFlash *cfg) { #ifdef EMULATOR - random_buffer(cfg->meta.uuid, sizeof(cfg->meta.uuid)); + random_buffer(cfg->meta.uuid, sizeof(cfg->meta.uuid)); #else - _Static_assert(sizeof(cfg->meta.uuid) == 3 * sizeof(uint32_t), - "uuid not large enough"); - desig_get_unique_id((uint32_t*)cfg->meta.uuid); + _Static_assert(sizeof(cfg->meta.uuid) == 3 * sizeof(uint32_t), + "uuid not large enough"); + desig_get_unique_id((uint32_t *)cfg->meta.uuid); #endif - data2hex(cfg->meta.uuid, sizeof(cfg->meta.uuid), cfg->meta.uuid_str); + data2hex(cfg->meta.uuid, sizeof(cfg->meta.uuid), cfg->meta.uuid_str); } -void storage_reset(void) -{ - storage_reset_impl(&session, &shadow_config); -} +void storage_reset(void) { storage_reset_impl(&session, &shadow_config); } -void storage_reset_impl(SessionState *ss, ConfigFlash *cfg) -{ - memset(&cfg->storage, 0, sizeof(cfg->storage)); +void storage_reset_impl(SessionState *ss, ConfigFlash *cfg) { + memset(&cfg->storage, 0, sizeof(cfg->storage)); - storage_resetPolicies(&cfg->storage); + storage_resetPolicies(&cfg->storage); - storage_setPin_impl(ss, &cfg->storage, ""); + storage_setPin_impl(ss, &cfg->storage, ""); - cfg->storage.version = STORAGE_VERSION; + cfg->storage.version = STORAGE_VERSION; - memzero(ss, sizeof(*ss)); + memzero(ss, sizeof(*ss)); - cfg->storage.has_sec = false; - memzero(&cfg->storage.sec, sizeof(cfg->storage.sec)); + cfg->storage.has_sec = false; + memzero(&cfg->storage.sec, sizeof(cfg->storage.sec)); } -void storage_wipe(void) -{ - flash_erase_word(FLASH_STORAGE1); - flash_erase_word(FLASH_STORAGE2); - flash_erase_word(FLASH_STORAGE3); +void storage_wipe(void) { + flash_erase_word(FLASH_STORAGE1); + flash_erase_word(FLASH_STORAGE2); + flash_erase_word(FLASH_STORAGE3); } -void session_clear(bool clear_pin) { - if (PIN_REWRAP == session_clear_impl(&session, &shadow_config.storage, clear_pin)) { - storage_commit(); - } +void storage_clearKeys(void) { + session_clear_impl(&session, &shadow_config.storage, false); + memzero(&session.storageKey, sizeof(session.storageKey)); + memzero(&shadow_config.storage.pub.wrapped_storage_key, + sizeof(shadow_config.storage.pub.wrapped_storage_key)); + memzero(&shadow_config.storage.pub.storage_key_fingerprint, + sizeof(shadow_config.storage.pub.storage_key_fingerprint)); + + session.pinCached = false; + storage_commit(); } -pintest_t session_clear_impl(SessionState *ss, Storage *storage, bool clear_pin) -{ -/* - This is a *_impl() function that is assumed to not modify the flash storage config state. Because this function - calls storage_isPinCorrect_impl(), the storage config may need updating: - This function will return - PIN_WRONG - PIN is incorrect - PIN_GOOD - PIN is correct - PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING FUNCTION SHOULD storage_commit() - - If the pin is correct, the shadow config may be out of sync with the storage config in flash. - Thus, if the return is PIN_REWRAP, then the calling function is required to update the flash with a - storage_commit(). -*/ - pintest_t ret = PIN_WRONG; - - ss->seedCached = false; - memset(&ss->seed, 0, sizeof(ss->seed)); - - ss->passphraseCached = false; - memset(&ss->passphrase, 0, sizeof(ss->passphrase)); - - if (!storage_hasPin_impl(storage)) { - ret = storage_isPinCorrect_impl("", - storage->pub.wrapped_storage_key, - storage->pub.storage_key_fingerprint, - &storage->pub.sca_hardened, - ss->storageKey, - shadow_config.storage.pub.random_salt); - - if (ret == PIN_WRONG) { - ss->pinCached = false; - } else { - ss->pinCached = true; - } +void session_clear(bool clear_pin) { + if (PIN_REWRAP == + session_clear_impl(&session, &shadow_config.storage, clear_pin)) { + storage_commit(); + } +} + +pintest_t session_clear_impl(SessionState *ss, Storage *storage, + bool clear_pin) { + /* + This is a *_impl() function that is assumed to not modify the flash + storage config state. Because this function calls + storage_isPinCorrect_impl(), the storage config may need updating: This + function will return PIN_WRONG - PIN is incorrect PIN_GOOD - PIN is + correct PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING + FUNCTION SHOULD storage_commit() + + If the pin is correct, the shadow config may be out of sync with the + storage config in flash. Thus, if the return is PIN_REWRAP, then the + calling function is required to update the flash with a storage_commit(). + */ + pintest_t ret = PIN_WRONG; + + ss->seedCached = false; + memset(&ss->seed, 0, sizeof(ss->seed)); + + ss->passphraseCached = false; + memset(&ss->passphrase, 0, sizeof(ss->passphrase)); + + if (!storage_hasPin_impl(storage)) { + ret = storage_isPinCorrect_impl("", storage->pub.wrapped_storage_key, + storage->pub.storage_key_fingerprint, + &storage->pub.sca_hardened, + &storage->pub.v15_16_trans, + ss->storageKey, + shadow_config.storage.pub.random_salt); + + if (ret == PIN_WRONG) { + ss->pinCached = false; + } else { + ss->pinCached = true; + } - if (!ss->pinCached) - goto clear; + if (!ss->pinCached) goto clear; - storage_secMigrate(ss, storage, /*encrypt=*/false); - return(ret); - } + storage_secMigrate(ss, storage, /*encrypt=*/false); + return (ret); + } - if (!clear_pin) { - return(ret); - } + if (!clear_pin) { + return (ret); + } clear: - memzero(ss->storageKey, sizeof(ss->storageKey)); - ss->pinCached = false; - storage->has_sec = false; - memzero(&storage->sec, sizeof(storage->sec)); - return(ret); + memzero(ss->storageKey, sizeof(ss->storageKey)); + ss->pinCached = false; + storage->has_sec = false; + memzero(&storage->sec, sizeof(storage->sec)); + return (ret); } -void storage_commit(void) -{ - // Temporary storage for marshalling secrets in & out of flash. - static char flash_temp[1024]; +void storage_commit(void) { + // Temporary storage for marshalling secrets in & out of flash. + // Size of v16 storage layout (2013 bytes) + size of meta (44 bytes) + 1 + static char flash_temp[2058]; - memzero(flash_temp, sizeof(flash_temp)); + memzero(flash_temp, sizeof(flash_temp)); - if (session.pinCached || !shadow_config.storage.pub.has_pin) { - storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/true); - } else { - // commit what was in storage->encrypted_sec - } + if (session.pinCached || !shadow_config.storage.pub.has_pin) { + storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/true); + } else { + // commit what was in storage->encrypted_sec + } - storage_writeV11(flash_temp, sizeof(flash_temp), &shadow_config); + storage_writeV16(flash_temp, sizeof(flash_temp), &shadow_config); - memcpy(&shadow_config, STORAGE_MAGIC_STR, STORAGE_MAGIC_LEN); + memcpy(&shadow_config, STORAGE_MAGIC_STR, STORAGE_MAGIC_LEN); - uint32_t retries = 0; - for (retries = 0; retries < STORAGE_RETRIES; retries++) { - /* Capture CRC for verification at restore */ - uint32_t shadow_ram_crc32 = - calc_crc32(flash_temp, sizeof(flash_temp) / sizeof(uint32_t)); + uint32_t retries = 0; + for (retries = 0; retries < STORAGE_RETRIES; retries++) { + /* Capture CRC for verification at restore */ + uint32_t shadow_ram_crc32 = + calc_crc32(flash_temp, sizeof(flash_temp) / sizeof(uint32_t)); - if (shadow_ram_crc32 == 0) { - continue; /* Retry */ - } + if (shadow_ram_crc32 == 0) { + continue; /* Retry */ + } - /* Make sure storage sector is valid before proceeding */ - if(storage_location < FLASH_STORAGE1 || storage_location > FLASH_STORAGE3) - { - /* Let it exhaust the retries and error out */ - continue; - } + /* Make sure storage sector is valid before proceeding */ + if (storage_location < FLASH_STORAGE1 || + storage_location > FLASH_STORAGE3) { + /* Let it exhaust the retries and error out */ + continue; + } - flash_erase_word(storage_location); - wear_leveling_shift(); - flash_erase_word(storage_location); + flash_erase_word(storage_location); + wear_leveling_shift(); + flash_erase_word(storage_location); - /* Write storage data first before writing storage magic */ - if (!flash_write_word(storage_location, STORAGE_MAGIC_LEN, - sizeof(flash_temp) - STORAGE_MAGIC_LEN, - (uint8_t *)flash_temp + STORAGE_MAGIC_LEN)) { - flash_erase_word(storage_location); - continue; // Retry - } + /* Write storage data first before writing storage magic */ + if (!flash_write_word(storage_location, STORAGE_MAGIC_LEN, + sizeof(flash_temp) - STORAGE_MAGIC_LEN, + (uint8_t *)flash_temp + STORAGE_MAGIC_LEN)) { + flash_erase_word(storage_location); + continue; // Retry + } - if (!flash_write_word(storage_location, 0, STORAGE_MAGIC_LEN, - (uint8_t *)flash_temp)) { - flash_erase_word(storage_location); - continue; // Retry - } + if (!flash_write_word(storage_location, 0, STORAGE_MAGIC_LEN, + (uint8_t *)flash_temp)) { + flash_erase_word(storage_location); + continue; // Retry + } - /* Flash write completed successfully. Verify CRC */ - uint32_t shadow_flash_crc32 = - calc_crc32((const void*)flash_write_helper(storage_location), - sizeof(flash_temp) / sizeof(uint32_t)); + /* Flash write completed successfully. Verify CRC */ + uint32_t shadow_flash_crc32 = + calc_crc32((const void *)flash_write_helper(storage_location), + sizeof(flash_temp) / sizeof(uint32_t)); - if (shadow_flash_crc32 == shadow_ram_crc32) { - storage_protect_off(); - /* Commit successful, break to exit */ - break; - } + if (shadow_flash_crc32 == shadow_ram_crc32) { + storage_protect_off(); + /* Commit successful, break to exit */ + break; } + } - memzero(flash_temp, sizeof(flash_temp)); + memzero(flash_temp, sizeof(flash_temp)); - if(retries >= STORAGE_RETRIES) { - storage_wipe(); - layout_warning_static("Error Detected. Reboot Device!"); - shutdown(); - } + if (retries >= STORAGE_RETRIES) { + storage_wipe(); + layout_warning_static("Error Detected. Reboot Device!"); + shutdown(); + } } // Great candidate for C++ templates... sigh. void storage_dumpNode(HDNodeType *dst, const HDNode *src) { #if DEBUG_LINK - dst->depth = src->depth; - dst->fingerprint = 0; - dst->child_num = src->child_num; - - dst->chain_code.size = sizeof(src->chain_code); - memcpy(dst->chain_code.bytes, src->chain_code, - sizeof(src->chain_code)); - _Static_assert(sizeof(dst->chain_code.bytes) == - sizeof(src->chain_code), "chain_code type mismatch"); - - dst->has_private_key = true; - dst->private_key.size = sizeof(src->private_key); - memcpy(dst->private_key.bytes, src->private_key, - sizeof(src->private_key)); - _Static_assert(sizeof(dst->private_key.bytes) == - sizeof(src->private_key), "private_key type mismatch"); - - dst->has_public_key = true; - dst->public_key.size = sizeof(src->public_key); - memcpy(dst->public_key.bytes, src->public_key, - sizeof(src->public_key)); - _Static_assert(sizeof(dst->public_key.bytes) == - sizeof(src->public_key), "public_key type mismatch"); + dst->depth = src->depth; + dst->fingerprint = 0; + dst->child_num = src->child_num; + + dst->chain_code.size = sizeof(src->chain_code); + memcpy(dst->chain_code.bytes, src->chain_code, sizeof(src->chain_code)); + _Static_assert(sizeof(dst->chain_code.bytes) == sizeof(src->chain_code), + "chain_code type mismatch"); + + dst->has_private_key = true; + dst->private_key.size = sizeof(src->private_key); + memcpy(dst->private_key.bytes, src->private_key, sizeof(src->private_key)); + _Static_assert(sizeof(dst->private_key.bytes) == sizeof(src->private_key), + "private_key type mismatch"); + + dst->has_public_key = true; + dst->public_key.size = sizeof(src->public_key); + memcpy(dst->public_key.bytes, src->public_key, sizeof(src->public_key)); + _Static_assert(sizeof(dst->public_key.bytes) == sizeof(src->public_key), + "public_key type mismatch"); #else - (void)dst; - (void)src; + (void)dst; + (void)src; #endif } void storage_loadNode(HDNode *dst, const HDNodeType *src) { - dst->depth = src->depth; - dst->child_num = src->child_num; - - memcpy(dst->chain_code, src->chain_code.bytes, - sizeof(src->chain_code.bytes)); - _Static_assert(sizeof(dst->chain_code) == - sizeof(src->chain_code.bytes), "chain_code type mismatch"); - - if (src->has_private_key) { - memcpy(dst->private_key, src->private_key.bytes, - sizeof(src->private_key.bytes)); - _Static_assert(sizeof(dst->private_key) == - sizeof(src->private_key.bytes), "private_key type mismatch"); - } else { - memzero(dst->private_key, sizeof(dst->private_key)); - } + dst->depth = src->depth; + dst->child_num = src->child_num; - if (src->has_public_key) { - memcpy(dst->public_key, src->public_key.bytes, - sizeof(src->public_key)); - _Static_assert(sizeof(dst->public_key) == - sizeof(src->public_key.bytes), "public_key type mismatch"); - } else { - memzero(dst->public_key, sizeof(dst->public_key)); - } + memcpy(dst->chain_code, src->chain_code.bytes, sizeof(src->chain_code.bytes)); + _Static_assert(sizeof(dst->chain_code) == sizeof(src->chain_code.bytes), + "chain_code type mismatch"); + + if (src->has_private_key) { + memcpy(dst->private_key, src->private_key.bytes, + sizeof(src->private_key.bytes)); + _Static_assert(sizeof(dst->private_key) == sizeof(src->private_key.bytes), + "private_key type mismatch"); + } else { + memzero(dst->private_key, sizeof(dst->private_key)); + } + + if (src->has_public_key) { + memcpy(dst->public_key, src->public_key.bytes, sizeof(src->public_key)); + _Static_assert(sizeof(dst->public_key) == sizeof(src->public_key.bytes), + "public_key type mismatch"); + } else { + memzero(dst->public_key, sizeof(dst->public_key)); + } } -void storage_loadDevice(LoadDevice *msg) -{ - storage_reset_impl(&session, &shadow_config); +void storage_loadDevice(LoadDevice *msg) { + storage_reset_impl(&session, &shadow_config); - shadow_config.storage.pub.imported = true; + shadow_config.storage.pub.imported = true; - storage_setPin(msg->has_pin ? msg->pin : ""); + storage_setPin(msg->has_pin ? msg->pin : ""); - shadow_config.storage.pub.no_backup = false; - shadow_config.storage.pub.passphrase_protection = - msg->has_passphrase_protection && msg->passphrase_protection; + shadow_config.storage.pub.no_backup = false; + shadow_config.storage.pub.passphrase_protection = + msg->has_passphrase_protection && msg->passphrase_protection; - if (msg->has_node) { - shadow_config.storage.pub.has_node = true; - shadow_config.storage.pub.has_mnemonic = false; - shadow_config.storage.has_sec = true; - memcpy(&shadow_config.storage.sec.node, &msg->node, sizeof(msg->node)); + if (msg->has_node) { + shadow_config.storage.pub.has_node = true; + shadow_config.storage.pub.has_mnemonic = false; + shadow_config.storage.has_sec = true; + memcpy(&shadow_config.storage.sec.node, &msg->node, sizeof(msg->node)); #if DEBUG_LINK - storage_loadNode(&debuglink_node, &msg->node); + storage_loadNode(&debuglink_node, &msg->node); #endif - session.seedCached = false; - memset(&session.seed, 0, sizeof(session.seed)); - } else if(msg->has_mnemonic) { - shadow_config.storage.pub.has_mnemonic = true; - shadow_config.storage.pub.has_node = false; - shadow_config.storage.has_sec = true; - strlcpy(shadow_config.storage.sec.mnemonic, msg->mnemonic, - sizeof(shadow_config.storage.sec.mnemonic)); + session.seedCached = false; + memset(&session.seed, 0, sizeof(session.seed)); + } else if (msg->has_mnemonic) { + shadow_config.storage.pub.has_mnemonic = true; + shadow_config.storage.pub.has_node = false; + shadow_config.storage.has_sec = true; + strlcpy(shadow_config.storage.sec.mnemonic, msg->mnemonic, + sizeof(shadow_config.storage.sec.mnemonic)); #if DEBUG_LINK - memcpy(debuglink_mnemonic, msg->mnemonic, sizeof(debuglink_mnemonic)); + memcpy(debuglink_mnemonic, msg->mnemonic, sizeof(debuglink_mnemonic)); #endif - storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, - &shadow_config.storage.pub.u2froot); - shadow_config.storage.pub.has_u2froot = true; - session.seedCached = false; - memset(&session.seed, 0, sizeof(session.seed)); - } + storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, + &shadow_config.storage.pub.u2froot); + shadow_config.storage.pub.has_u2froot = true; + session.seedCached = false; + memset(&session.seed, 0, sizeof(session.seed)); + } - if (msg->has_language) { - storage_setLanguage(msg->language); - } + if (msg->has_language) { + storage_setLanguage(msg->language); + } - if (msg->has_label) { - storage_setLabel(msg->label); - } + if (msg->has_label) { + storage_setLabel(msg->label); + } - if (msg->has_u2f_counter) { - storage_setU2FCounter(msg->u2f_counter); - } + if (msg->has_u2f_counter) { + storage_setU2FCounter(msg->u2f_counter); + } } -void storage_setLabel(const char *label) -{ - if(!label) { return; } +void storage_setLabel(const char *label) { + if (!label) { + return; + } - shadow_config.storage.pub.has_label = true; - memset(shadow_config.storage.pub.label, 0, sizeof(shadow_config.storage.pub.label)); - strlcpy(shadow_config.storage.pub.label, label, - sizeof(shadow_config.storage.pub.label)); + shadow_config.storage.pub.has_label = true; + memset(shadow_config.storage.pub.label, 0, + sizeof(shadow_config.storage.pub.label)); + strlcpy(shadow_config.storage.pub.label, label, + sizeof(shadow_config.storage.pub.label)); } -const char *storage_getLabel(void) -{ - if (!shadow_config.storage.pub.has_label) { - return NULL; - } +const char *storage_getLabel(void) { + if (!shadow_config.storage.pub.has_label) { + return NULL; + } - return shadow_config.storage.pub.label; + return shadow_config.storage.pub.label; } -void storage_setLanguage(const char *lang) -{ - if(!lang) { return; } +void storage_setLanguage(const char *lang) { + if (!lang) { + return; + } - // sanity check - if(strcmp(lang, "english") == 0) - { - shadow_config.storage.pub.has_language = true; - memset(shadow_config.storage.pub.language, 0, - sizeof(shadow_config.storage.pub.language)); - strlcpy(shadow_config.storage.pub.language, lang, - sizeof(shadow_config.storage.pub.language)); - } + // sanity check + if (strcmp(lang, "english") == 0) { + shadow_config.storage.pub.has_language = true; + memset(shadow_config.storage.pub.language, 0, + sizeof(shadow_config.storage.pub.language)); + strlcpy(shadow_config.storage.pub.language, lang, + sizeof(shadow_config.storage.pub.language)); + } } -const char *storage_getLanguage(void) -{ - if (!shadow_config.storage.pub.has_language) { - return NULL; - } +const char *storage_getLanguage(void) { + if (!shadow_config.storage.pub.has_language) { + return NULL; + } - return shadow_config.storage.pub.language; + return shadow_config.storage.pub.language; } bool storage_isPinCorrect(const char *pin) { - pintest_t ret = storage_isPinCorrect_impl(pin, - shadow_config.storage.pub.wrapped_storage_key, - shadow_config.storage.pub.storage_key_fingerprint, - &shadow_config.storage.pub.sca_hardened, - session.storageKey, - shadow_config.storage.pub.random_salt); - - switch (ret) { + pintest_t ret = storage_isPinCorrect_impl( + pin, shadow_config.storage.pub.wrapped_storage_key, + shadow_config.storage.pub.storage_key_fingerprint, + &shadow_config.storage.pub.sca_hardened, + &shadow_config.storage.pub.v15_16_trans, + session.storageKey, + shadow_config.storage.pub.random_salt); + + switch (ret) { case PIN_REWRAP: - session.pinCached = true; - storage_commit(); - storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/false); - break; + session.pinCached = true; + storage_commit(); + storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/false); + break; case PIN_GOOD: - session.pinCached = true; - storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/false); - break; + session.pinCached = true; + storage_secMigrate(&session, &shadow_config.storage, /*encrypt=*/false); + break; case PIN_WRONG: default: - session.pinCached = false; - session_clear_impl(&session, &shadow_config.storage, /*clear_pin=*/true); - memzero(session.storageKey, sizeof(session.storageKey)); - break; - } + session.pinCached = false; + session_clear_impl(&session, &shadow_config.storage, /*clear_pin=*/true); + memzero(session.storageKey, sizeof(session.storageKey)); + break; + } - return ret; + return ret; } -bool storage_hasPin(void) -{ - return storage_hasPin_impl(&shadow_config.storage); +bool storage_hasPin(void) { + return storage_hasPin_impl(&shadow_config.storage); } -bool storage_hasPin_impl(const Storage *storage) -{ - return storage->pub.has_pin; +bool storage_hasPin_impl(const Storage *storage) { + return storage->pub.has_pin; } -void storage_setPin(const char *pin) -{ - storage_setPin_impl(&session, &shadow_config.storage, pin); +void storage_setPin(const char *pin) { + storage_setPin_impl(&session, &shadow_config.storage, pin); - session.pinCached = true; + session.pinCached = true; #if DEBUG_LINK - strncpy(debuglink_pin, pin, sizeof(debuglink_pin)); + strncpy(debuglink_pin, pin, sizeof(debuglink_pin)); #endif } -void storage_setPin_impl(SessionState *ss, Storage *storage, const char *pin) -{ - // Derive the wrapping key for the new pin - uint8_t wrapping_key[64]; - storage_deriveWrappingKey(pin, wrapping_key, /*sca_hardened=*/true, - storage->pub.random_salt, _("Encrypting Secrets")); +void storage_setPin_impl(SessionState *ss, Storage *storage, const char *pin) { + // Derive the wrapping key for the new pin + uint8_t wrapping_key[64]; + storage_deriveWrappingKey(pin, wrapping_key, /*sca_hardened=*/true, + /*v15_16_trans=*/true, + storage->pub.random_salt, _("Encrypting Secrets")); - // Derive a new storageKey. - random_buffer(ss->storageKey, 64); + // Derive a new storageKey. + random_buffer(ss->storageKey, 64); - // Wrap the new storageKey. - storage_wrapStorageKey(wrapping_key, ss->storageKey, - storage->pub.wrapped_storage_key); - storage->pub.sca_hardened = true; + // Wrap the new storageKey. + storage_wrapStorageKey(wrapping_key, ss->storageKey, + storage->pub.wrapped_storage_key); + storage->pub.sca_hardened = true; + storage->pub.v15_16_trans = true; - // Fingerprint the storageKey. - storage_keyFingerprint(ss->storageKey, - storage->pub.storage_key_fingerprint); + // Fingerprint the storageKey. + storage_keyFingerprint(ss->storageKey, storage->pub.storage_key_fingerprint); - // Clean up secrets to get them off the stack. - memzero(wrapping_key, sizeof(wrapping_key)); + // Clean up secrets to get them off the stack. + memzero(wrapping_key, sizeof(wrapping_key)); - storage->pub.has_pin = !!strlen(pin); + storage->pub.has_pin = !!strlen(pin); - storage_secMigrate(ss, storage, /*encrypt=*/true); + storage_secMigrate(ss, storage, /*encrypt=*/true); } -bool session_isPinCached(void) -{ - return session.pinCached; +bool storage_isWipeCodeCorrect(const char *wipe_code) { + uint8_t scratch_key[64]; + pintest_t ret = storage_isWipeCodeCorrect_impl( + wipe_code, shadow_config.storage.pub.wrapped_wipe_code_key, + shadow_config.storage.pub.wipe_code_key_fingerprint, scratch_key, + shadow_config.storage.pub.random_salt); + + if (ret == PIN_WRONG) { + session_clear_impl(&session, &shadow_config.storage, /*clear_pin=*/true); + memzero(session.storageKey, sizeof(session.storageKey)); + } + + memset(scratch_key, 0, sizeof(scratch_key)); + return ret; } -void storage_resetPinFails(void) -{ - shadow_config.storage.pub.pin_failed_attempts = 0; +bool storage_hasWipeCode(void) { + return storage_hasWipeCode_impl(&shadow_config.storage); +} - storage_commit(); +bool storage_hasWipeCode_impl(const Storage *storage) { + return storage->pub.has_wipe_code; } -void storage_increasePinFails(void) -{ - shadow_config.storage.pub.pin_failed_attempts++; +void storage_setWipeCode(const char *wipe_code) { + storage_setWipeCode_impl(&session, &shadow_config.storage, wipe_code); - storage_commit(); +#if DEBUG_LINK + strncpy(debuglink_wipe_code, wipe_code, sizeof(debuglink_wipe_code)); +#endif } -uint32_t storage_getPinFails(void) -{ - return shadow_config.storage.pub.pin_failed_attempts; +void storage_setWipeCode_impl(SessionState *ss, Storage *storage, + const char *wipe_code) { + uint8_t scratch_key[64]; + // Derive the wrapping key for the new wipe code + uint8_t wrapping_key[64]; + storage_deriveWrappingKey(wipe_code, wrapping_key, /*sca_hardened=*/true, + /*v15_16_trans=*/true, + storage->pub.random_salt, _("Updating Wipe Code")); + + // Derive a new wipe code key . + random_buffer(scratch_key, 64); + + // Wrap the new wipe code key. + storage_wrapStorageKey(wrapping_key, scratch_key, + storage->pub.wrapped_wipe_code_key); + storage->pub.sca_hardened = true; + + // Fingerprint the wipe code key. + storage_keyFingerprint(scratch_key, storage->pub.wipe_code_key_fingerprint); + + // Clean up secrets to get them off the stack. + memzero(wrapping_key, sizeof(wrapping_key)); + memzero(scratch_key, sizeof(scratch_key)); + + storage->pub.has_wipe_code = !!strlen(wipe_code); + + storage_secMigrate(ss, storage, /*encrypt=*/true); +} + +bool session_isPinCached(void) { return session.pinCached; } + +void storage_resetPinFails(void) { + shadow_config.storage.pub.pin_failed_attempts = 0; + + storage_commit(); +} + +void storage_increasePinFails(void) { + shadow_config.storage.pub.pin_failed_attempts++; + + storage_commit(); +} + +uint32_t storage_getPinFails(void) { + return shadow_config.storage.pub.pin_failed_attempts; } /// \brief Calls animation callback. /// \param iter Current iteration. /// \param total Total iterations. -static void get_root_node_callback(uint32_t iter, uint32_t total) -{ - animating_progress_handler(_("Waking up"), 1000 * iter / total); +static void get_root_node_callback(uint32_t iter, uint32_t total) { + animating_progress_handler(_("Waking up"), 1000 * iter / total); } -const uint8_t *storage_getSeed(const ConfigFlash *cfg, bool usePassphrase) -{ - // root node is properly cached - if (usePassphrase == session.seedUsesPassphrase - && session.seedCached) { - return session.seed; - } - - // if storage has mnemonic, convert it to node and use it - if (cfg->storage.pub.has_mnemonic) { - if (!cfg->storage.has_sec) { - return NULL; - } +const uint8_t *storage_getSeed(const ConfigFlash *cfg, bool usePassphrase) { + // root node is properly cached + if (usePassphrase == session.seedUsesPassphrase && session.seedCached) { + return session.seed; + } - if (usePassphrase && !passphrase_protect()) { - return NULL; - } + // if storage has mnemonic, convert it to node and use it + if (cfg->storage.pub.has_mnemonic) { + if (!cfg->storage.has_sec) { + return NULL; + } - mnemonic_to_seed(cfg->storage.sec.mnemonic, - usePassphrase ? session.passphrase : "", - session.seed, get_root_node_callback); // BIP-0039 - session.seedCached = true; - session.seedUsesPassphrase = usePassphrase; - return session.seed; + if (usePassphrase && !passphrase_protect()) { + return NULL; } - return NULL; + mnemonic_to_seed(cfg->storage.sec.mnemonic, + usePassphrase ? session.passphrase : "", session.seed, + get_root_node_callback); // BIP-0039 + session.seedCached = true; + session.seedUsesPassphrase = usePassphrase; + return session.seed; + } + + return NULL; } bool storage_getRootNode(const char *curve, bool usePassphrase, HDNode *node) { - // if storage has node, decrypt and use it - if (shadow_config.storage.pub.has_node && strcmp(curve, SECP256K1_NAME) == 0) { - if (!shadow_config.storage.has_sec) { - return false; - } - - if (!passphrase_protect()) { - /* passphrased failed. Bailing */ - return false; - } + // if storage has node, decrypt and use it + if (shadow_config.storage.pub.has_node && + strcmp(curve, SECP256K1_NAME) == 0) { + if (!shadow_config.storage.has_sec) { + return false; + } - if (hdnode_from_xprv(shadow_config.storage.sec.node.depth, - shadow_config.storage.sec.node.child_num, - shadow_config.storage.sec.node.chain_code.bytes, - shadow_config.storage.sec.node.private_key.bytes, - curve, node) == 0) { - return false; - } + if (!passphrase_protect()) { + /* passphrased failed. Bailing */ + return false; + } - if (shadow_config.storage.pub.passphrase_protection && - session.passphraseCached && - strlen(session.passphrase) > 0) { - // decrypt hd node - static uint8_t CONFIDENTIAL secret[64]; - PBKDF2_HMAC_SHA512_CTX pctx; - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)session.passphrase, strlen(session.passphrase), (const uint8_t *)"TREZORHD", 8, 1); - for (int i = 0; i < 8; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); - get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); - } - pbkdf2_hmac_sha512_Final(&pctx, secret); - aes_decrypt_ctx ctx; - aes_decrypt_key256(secret, &ctx); - aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); - aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); - memzero(&ctx, sizeof(ctx)); - memzero(secret, sizeof(secret)); - } + if (hdnode_from_xprv(shadow_config.storage.sec.node.depth, + shadow_config.storage.sec.node.child_num, + shadow_config.storage.sec.node.chain_code.bytes, + shadow_config.storage.sec.node.private_key.bytes, + curve, node) == 0) { + return false; + } - return true; + if (shadow_config.storage.pub.passphrase_protection && + session.passphraseCached && strlen(session.passphrase) > 0) { + // decrypt hd node + static uint8_t CONFIDENTIAL secret[64]; + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)session.passphrase, + strlen(session.passphrase), + (const uint8_t *)"TREZORHD", 8, 1); + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, + BIP39_PBKDF2_ROUNDS); + } + pbkdf2_hmac_sha512_Final(&pctx, secret); + aes_decrypt_ctx ctx; + aes_decrypt_key256(secret, &ctx); + aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, + &ctx); + aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, + &ctx); + memzero(&ctx, sizeof(ctx)); + memzero(secret, sizeof(secret)); } - /* get node from mnemonic */ - if (shadow_config.storage.pub.has_mnemonic) { - if (!shadow_config.storage.has_sec) { - return false; - } + return true; + } - if (!passphrase_protect()) { - /* passphrased failed. Bailing */ - return false; - } + /* get node from mnemonic */ + if (shadow_config.storage.pub.has_mnemonic) { + if (!shadow_config.storage.has_sec) { + return false; + } - if(!session.seedCached) { - session.seedCached = storage_getRootSeedCache(&session, &shadow_config, curve, usePassphrase, session.seed); + if (!passphrase_protect()) { + /* passphrased failed. Bailing */ + return false; + } - if(!session.seedCached) { - /* calculate session seed and update the global sessionSeed/sessionSeedCached variables */ - storage_getSeed(&shadow_config, usePassphrase); + if (!session.seedCached) { + session.seedCached = storage_getRootSeedCache( + &session, &shadow_config, curve, usePassphrase, session.seed); - if (!session.seedCached) { - return false; - } + if (!session.seedCached) { + /* calculate session seed and update the global + * sessionSeed/sessionSeedCached variables */ + storage_getSeed(&shadow_config, usePassphrase); - storage_setRootSeedCache(&session, &shadow_config, session.seed, curve); - } + if (!session.seedCached) { + return false; } - if (hdnode_from_seed(session.seed, 64, curve, node) == 1) { - return true; - } + storage_setRootSeedCache(&session, &shadow_config, session.seed, curve); + } } - return false; -} + if (hdnode_from_seed(session.seed, 64, curve, node) == 1) { + return true; + } + } -bool storage_isInitialized(void) -{ - return shadow_config.storage.pub.has_node || shadow_config.storage.pub.has_mnemonic; + return false; } -const char *storage_getUuidStr(void) -{ - return shadow_config.meta.uuid_str; +bool storage_isInitialized(void) { + return shadow_config.storage.pub.has_node || + shadow_config.storage.pub.has_mnemonic; } -bool storage_getPassphraseProtected(void) -{ - return shadow_config.storage.pub.passphrase_protection; -} +const char *storage_getUuidStr(void) { return shadow_config.meta.uuid_str; } -void storage_setPassphraseProtected(bool passphrase) -{ - shadow_config.storage.pub.passphrase_protection = passphrase; +bool storage_getPassphraseProtected(void) { + return shadow_config.storage.pub.passphrase_protection; } -void session_cachePassphrase(const char *passphrase) -{ - strlcpy(session.passphrase, passphrase, sizeof(session.passphrase)); - session.passphraseCached = true; +void storage_setPassphraseProtected(bool passphrase) { + shadow_config.storage.pub.passphrase_protection = passphrase; } -bool session_isPassphraseCached(void) -{ - return session.passphraseCached; +void session_cachePassphrase(const char *passphrase) { + strlcpy(session.passphrase, passphrase, sizeof(session.passphrase)); + session.passphraseCached = true; } +bool session_isPassphraseCached(void) { return session.passphraseCached; } + void storage_setMnemonicFromWords(const char (*words)[12], - unsigned int word_count) -{ - strlcpy(shadow_config.storage.sec.mnemonic, words[0], - sizeof(shadow_config.storage.sec.mnemonic)); + unsigned int word_count) { + strlcpy(shadow_config.storage.sec.mnemonic, words[0], + sizeof(shadow_config.storage.sec.mnemonic)); #if DEBUG_LINK - strlcpy(debuglink_mnemonic, words[0], sizeof(debuglink_mnemonic)); + strlcpy(debuglink_mnemonic, words[0], sizeof(debuglink_mnemonic)); #endif - for(uint32_t i = 1; i < word_count; i++) - { - strlcat(shadow_config.storage.sec.mnemonic, " ", - sizeof(shadow_config.storage.sec.mnemonic)); - strlcat(shadow_config.storage.sec.mnemonic, words[i], - sizeof(shadow_config.storage.sec.mnemonic)); + for (uint32_t i = 1; i < word_count; i++) { + strlcat(shadow_config.storage.sec.mnemonic, " ", + sizeof(shadow_config.storage.sec.mnemonic)); + strlcat(shadow_config.storage.sec.mnemonic, words[i], + sizeof(shadow_config.storage.sec.mnemonic)); #if DEBUG_LINK - strlcat(debuglink_mnemonic, " ", sizeof(debuglink_mnemonic)); - strlcat(debuglink_mnemonic, words[i], sizeof(debuglink_mnemonic)); + strlcat(debuglink_mnemonic, " ", sizeof(debuglink_mnemonic)); + strlcat(debuglink_mnemonic, words[i], sizeof(debuglink_mnemonic)); #endif - } + } - shadow_config.storage.pub.has_mnemonic = true; - shadow_config.storage.has_sec = true; + shadow_config.storage.pub.has_mnemonic = true; + shadow_config.storage.has_sec = true; - storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, - &shadow_config.storage.pub.u2froot); - shadow_config.storage.pub.has_u2froot = true; + storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, + &shadow_config.storage.pub.u2froot); + shadow_config.storage.pub.has_u2froot = true; } -void storage_setMnemonic(const char *m) -{ - memset(shadow_config.storage.sec.mnemonic, 0, - sizeof(shadow_config.storage.sec.mnemonic)); - strlcpy(shadow_config.storage.sec.mnemonic, m, - sizeof(shadow_config.storage.sec.mnemonic)); +void storage_setMnemonic(const char *m) { + memset(shadow_config.storage.sec.mnemonic, 0, + sizeof(shadow_config.storage.sec.mnemonic)); + strlcpy(shadow_config.storage.sec.mnemonic, m, + sizeof(shadow_config.storage.sec.mnemonic)); #if DEBUG_LINK - memset(debuglink_mnemonic, 0, sizeof(debuglink_mnemonic)); - strlcpy(debuglink_mnemonic, m, sizeof(debuglink_mnemonic)); + memset(debuglink_mnemonic, 0, sizeof(debuglink_mnemonic)); + strlcpy(debuglink_mnemonic, m, sizeof(debuglink_mnemonic)); #endif - shadow_config.storage.pub.has_mnemonic = true; - shadow_config.storage.has_sec = true; + shadow_config.storage.pub.has_mnemonic = true; + shadow_config.storage.has_sec = true; - storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, - &shadow_config.storage.pub.u2froot); - shadow_config.storage.pub.has_u2froot = true; + storage_compute_u2froot(&session, shadow_config.storage.sec.mnemonic, + &shadow_config.storage.pub.u2froot); + shadow_config.storage.pub.has_u2froot = true; } -bool storage_hasMnemonic(void) -{ - return shadow_config.storage.pub.has_mnemonic; +bool storage_hasMnemonic(void) { + return shadow_config.storage.pub.has_mnemonic; } /* Check whether mnemonic matches storage. The mnemonic must be * a null-terminated string. */ bool storage_containsMnemonic(const char *mnemonic) { - if (!storage_hasMnemonic()) - return false; - if (!shadow_config.storage.has_sec) - return false; - - // Compare the digests to mitigate side-channel attacks. - uint8_t digest_stored[SHA256_DIGEST_LENGTH]; - sha256_Raw((const uint8_t*)shadow_config.storage.sec.mnemonic, - strnlen(shadow_config.storage.sec.mnemonic, MAX_MNEMONIC_LEN), - digest_stored); - - uint8_t digest_input[SHA256_DIGEST_LENGTH]; - sha256_Raw((const uint8_t*)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), - digest_input); - - uint8_t diff = 0; - for (size_t i = 0; i < sizeof(digest_input); i++) { - diff |= (digest_stored[i] - digest_input[i]); - } - memzero(digest_stored, sizeof(digest_stored)); - memzero(digest_input, sizeof(digest_input)); - return diff == 0; -} + if (!storage_hasMnemonic()) return false; + if (!shadow_config.storage.has_sec) return false; -const char *storage_getShadowMnemonic(void) -{ - if (!shadow_config.storage.has_sec) - return NULL; - return shadow_config.storage.sec.mnemonic; -} + // Compare the digests to mitigate side-channel attacks. + uint8_t digest_stored[SHA256_DIGEST_LENGTH]; + sha256_Raw((const uint8_t *)shadow_config.storage.sec.mnemonic, + strnlen(shadow_config.storage.sec.mnemonic, MAX_MNEMONIC_LEN), + digest_stored); -bool storage_getImported(void) -{ - return shadow_config.storage.pub.imported; -} + uint8_t digest_input[SHA256_DIGEST_LENGTH]; + sha256_Raw((const uint8_t *)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), + digest_input); -void storage_setImported(bool val) -{ - shadow_config.storage.pub.imported = val; + uint8_t diff = 0; + for (size_t i = 0; i < sizeof(digest_input); i++) { + diff |= (digest_stored[i] - digest_input[i]); + } + memzero(digest_stored, sizeof(digest_stored)); + memzero(digest_input, sizeof(digest_input)); + return diff == 0; } -bool storage_hasNode(void) -{ - return shadow_config.storage.pub.has_node; +const char *storage_getShadowMnemonic(void) { + if (!shadow_config.storage.has_sec) return NULL; + return shadow_config.storage.sec.mnemonic; } -Allocation storage_getLocation(void) -{ - return storage_location; -} +bool storage_getImported(void) { return shadow_config.storage.pub.imported; } + +void storage_setImported(bool val) { shadow_config.storage.pub.imported = val; } -bool storage_setPolicy(const char *policy_name, bool enabled) -{ - return storage_setPolicy_impl(shadow_config.storage.pub.policies, policy_name, enabled); +bool storage_hasNode(void) { return shadow_config.storage.pub.has_node; } + +Allocation storage_getLocation(void) { return storage_location; } + +bool storage_setPolicy(const char *policy_name, bool enabled) { + return storage_setPolicy_impl(shadow_config.storage.pub.policies, policy_name, + enabled); } -bool storage_setPolicy_impl(PolicyType ps[POLICY_COUNT], const char *policy_name, bool enabled) -{ - for (unsigned i = 0; i < POLICY_COUNT; ++i) { - if (strcmp(policy_name, ps[i].policy_name) == 0) { - ps[i].has_enabled = true; - ps[i].enabled = enabled; - return true; - } +bool storage_setPolicy_impl(PolicyType ps[POLICY_COUNT], + const char *policy_name, bool enabled) { + for (unsigned i = 0; i < POLICY_COUNT; ++i) { + if (strcmp(policy_name, ps[i].policy_name) == 0) { + ps[i].has_enabled = true; + ps[i].enabled = enabled; + return true; } + } - return false; + return false; } -void storage_getPolicies(PolicyType *policy_data) -{ - for (size_t i = 0; i < POLICY_COUNT; ++i) { - memcpy(&policy_data[i], &shadow_config.storage.pub.policies[i], sizeof(policy_data[i])); - } +void storage_getPolicies(PolicyType *policy_data) { + for (size_t i = 0; i < POLICY_COUNT; ++i) { + memcpy(&policy_data[i], &shadow_config.storage.pub.policies[i], + sizeof(policy_data[i])); + } } -bool storage_isPolicyEnabled(const char *policy_name) -{ - return storage_isPolicyEnabled_impl(shadow_config.storage.pub.policies, policy_name); +bool storage_isPolicyEnabled(const char *policy_name) { + return storage_isPolicyEnabled_impl(shadow_config.storage.pub.policies, + policy_name); } -bool storage_isPolicyEnabled_impl(const PolicyType ps[POLICY_COUNT], const char *policy_name) -{ - for (unsigned i = 0; i < POLICY_COUNT; ++i) { - if (strcmp(policy_name, ps[i].policy_name) == 0) { - return ps[i].enabled; - } +bool storage_isPolicyEnabled_impl(const PolicyType ps[POLICY_COUNT], + const char *policy_name) { + for (unsigned i = 0; i < POLICY_COUNT; ++i) { + if (strcmp(policy_name, ps[i].policy_name) == 0) { + return ps[i].enabled; } - return false; + } + return false; } -bool storage_noBackup(void) { - return shadow_config.storage.pub.no_backup; -} +bool storage_noBackup(void) { return shadow_config.storage.pub.no_backup; } -void storage_setNoBackup(void) { - shadow_config.storage.pub.no_backup = true; -} +void storage_setNoBackup(void) { shadow_config.storage.pub.no_backup = true; } -uint32_t storage_getAutoLockDelayMs() -{ - return shadow_config.storage.pub.has_auto_lock_delay_ms - ? MAX(shadow_config.storage.pub.auto_lock_delay_ms, - STORAGE_MIN_SCREENSAVER_TIMEOUT) - : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT; +uint32_t storage_getAutoLockDelayMs() { + return shadow_config.storage.pub.has_auto_lock_delay_ms + ? MAX(shadow_config.storage.pub.auto_lock_delay_ms, + STORAGE_MIN_SCREENSAVER_TIMEOUT) + : STORAGE_DEFAULT_SCREENSAVER_TIMEOUT; } -void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) -{ - shadow_config.storage.pub.has_auto_lock_delay_ms = true; - shadow_config.storage.pub.auto_lock_delay_ms = - MAX(auto_lock_delay_ms, STORAGE_MIN_SCREENSAVER_TIMEOUT); +void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { + shadow_config.storage.pub.has_auto_lock_delay_ms = true; + shadow_config.storage.pub.auto_lock_delay_ms = + MAX(auto_lock_delay_ms, STORAGE_MIN_SCREENSAVER_TIMEOUT); } #if DEBUG_LINK -const char *storage_getPin(void) -{ - return shadow_config.storage.pub.has_pin ? debuglink_pin : NULL; +const char *storage_getPin(void) { + return shadow_config.storage.pub.has_pin ? debuglink_pin : NULL; } -const char *storage_getMnemonic(void) -{ - return debuglink_mnemonic; -} +const char *storage_getMnemonic(void) { return debuglink_mnemonic; } -HDNode *storage_getNode(void) -{ - return &debuglink_node; -} +HDNode *storage_getNode(void) { return &debuglink_node; } #endif diff --git a/lib/firmware/storage.h b/lib/firmware/storage.h index 584d30b51..a15bddae9 100644 --- a/lib/firmware/storage.h +++ b/lib/firmware/storage.h @@ -17,7 +17,6 @@ * along with this library. If not, see . */ - #ifndef STORAGEPB_H #define STORAGEPB_H @@ -25,70 +24,77 @@ #include "keepkey/firmware/storage.h" #include "keepkey/firmware/policy.h" +// The length of the external salt in bytes. +#define EXTERNAL_SALT_SIZE 32 + typedef struct _Storage { - uint32_t version; - struct Public { - uint8_t wrapped_storage_key[64]; - uint8_t storage_key_fingerprint[32]; - bool has_pin; - uint32_t pin_failed_attempts; - bool has_language; - char language[16]; - bool has_label; - char label[48]; - bool imported; - uint32_t policies_count; - PolicyType policies[POLICY_COUNT]; - bool has_auto_lock_delay_ms; - uint32_t auto_lock_delay_ms; - bool passphrase_protection; - bool initialized; - bool has_node; - bool has_mnemonic; - bool has_u2froot; - HDNodeType u2froot; - uint32_t u2f_counter; - bool no_backup; - bool sca_hardened; - uint8_t random_salt[32]; - } pub; - - bool has_sec; - struct Secret { - HDNodeType node; - char mnemonic[241]; - char pin[10]; - Cache cache; - } sec; - - bool has_sec_fingerprint; - uint8_t sec_fingerprint[32]; - - uint32_t encrypted_sec_version; - uint8_t encrypted_sec[512]; + uint32_t version; + struct Public { + uint8_t wrapped_storage_key[64]; + uint8_t storage_key_fingerprint[32]; + uint8_t wrapped_wipe_code_key[64]; + uint8_t wipe_code_key_fingerprint[32]; + bool has_pin; + bool has_wipe_code; + uint32_t pin_failed_attempts; + bool has_language; + char language[16]; + bool has_label; + char label[48]; + bool imported; + uint32_t policies_count; + PolicyType policies[POLICY_COUNT]; + bool has_auto_lock_delay_ms; + uint32_t auto_lock_delay_ms; + bool passphrase_protection; + bool initialized; + bool has_node; + bool has_mnemonic; + bool has_u2froot; + HDNodeType u2froot; + uint32_t u2f_counter; + bool no_backup; + bool sca_hardened; + bool v15_16_trans; + uint8_t random_salt[32]; + } pub; + + bool has_sec; + struct Secret { + HDNodeType node; + char mnemonic[241]; + char pin[10]; + Cache cache; + } sec; + + bool has_sec_fingerprint; + uint8_t sec_fingerprint[32]; + + uint32_t encrypted_sec_version; + uint8_t encrypted_sec[512]; } Storage; typedef struct _ConfigFlash { - Metadata meta; - Storage storage; + Metadata meta; + Storage storage; } ConfigFlash; typedef struct _SessionState { - bool seedUsesPassphrase; - bool seedCached; - uint8_t seed[64]; + bool seedUsesPassphrase; + bool seedCached; + uint8_t seed[64]; - bool pinCached; - uint8_t storageKey[64]; + bool pinCached; + uint8_t storageKey[64]; - bool passphraseCached; - char passphrase[51]; + bool passphraseCached; + char passphrase[51]; } SessionState; typedef enum { - PIN_WRONG, // PIN incorrect - PIN_GOOD, // PIN correct - PIN_REWRAP // PIN correct but storage key rewrapped, requires storage update + PIN_WRONG, // PIN incorrect + PIN_GOOD, // PIN correct + PIN_REWRAP // PIN correct but storage key rewrapped, requires storage update } pintest_t; #define MAX_MNEMONIC_LEN 240 @@ -97,26 +103,43 @@ void storage_loadNode(HDNode *dst, const HDNodeType *src); /// Derive the wrapping key from the user's pin. void storage_deriveWrappingKey(const char *pin, uint8_t wrapping_key[64], - bool sca_hardened, uint8_t random_salt[RANDOM_SALT_LEN], - const char *message); + bool sca_hardened, + bool v15_16_trans, + uint8_t random_salt[RANDOM_SALT_LEN], + const char *message); /// Wrap the storage key. -void storage_wrapStorageKey(const uint8_t wrapping_key[64], const uint8_t key[64], uint8_t wrapped_key[64]); +void storage_wrapStorageKey(const uint8_t wrapping_key[64], + const uint8_t key[64], uint8_t wrapped_key[64]); /// Attempt to unnwrap the storage key. -void storage_unwrapStorageKey(const uint8_t wrapping_key[64], const uint8_t wrapped_key[64], uint8_t key[64]); +void storage_unwrapStorageKey(const uint8_t wrapping_key[64], + const uint8_t wrapped_key[64], uint8_t key[64]); /// Attempt to unnwrap the storage key using aes256. -void storage_unwrapStorageKey256(const uint8_t wrapping_key[64], const uint8_t wrapped_key[64], uint8_t key[64]); +void storage_unwrapStorageKey256(const uint8_t wrapping_key[64], + const uint8_t wrapped_key[64], + uint8_t key[64]); /// Get the fingerprint for an unwrapped storage key. void storage_keyFingerprint(const uint8_t key[64], uint8_t fingerprint[32]); /// \return: PIN_WRONG - PIN is incorrect /// PIN_GOOD - PIN is correct -/// PIN_REWRAPPED -> PIN is correct, storage key was rewrapped, CALLING FUNCTION SHOULD storage_commit() -pintest_t storage_isPinCorrect_impl(const char *pin, uint8_t wrapped_key[64], const uint8_t fingerprint[32], bool *sca_hardened, uint8_t key[64], - uint8_t random_salt[RANDOM_SALT_LEN]); +/// PIN_REWRAPPED -> PIN is correct, storage key was rewrapped, CALLING +/// FUNCTION SHOULD storage_commit() +pintest_t storage_isPinCorrect_impl(const char *pin, uint8_t wrapped_key[64], + const uint8_t fingerprint[32], + bool *sca_hardened, + bool *v15_16_trans, + uint8_t key[64], + uint8_t random_salt[RANDOM_SALT_LEN]); + +pintest_t storage_isWipeCodeCorrect_impl(const char *wipe_code, + uint8_t wrapped_key[64], + const uint8_t fingerprint[32], + uint8_t key[64], + uint8_t random_salt[RANDOM_SALT_LEN]); /// Migrate data in Storage to/from sec/encrypted_sec. void storage_secMigrate(SessionState *state, Storage *storage, bool encrypt); @@ -125,43 +148,57 @@ void storage_resetUuid_impl(ConfigFlash *cfg); void storage_reset_impl(SessionState *session, ConfigFlash *cfg); -void storage_setPin_impl(SessionState *session, Storage *storage, const char *pin); +void storage_setPin_impl(SessionState *session, Storage *storage, + const char *pin); bool storage_hasPin_impl(const Storage *storage); +void storage_setWipeCode_impl(SessionState *ss, Storage *storage, + const char *wipe_code); + +bool storage_hasWipeCode_impl(const Storage *storage); + /// \return: PIN_WRONG - PIN is incorrect /// PIN_GOOD - PIN is correct -/// PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING FUNCTION SHOULD storage_commit() -pintest_t session_clear_impl(SessionState *session, Storage *storage, bool clear_pin); +/// PIN_REWRAP -> PIN is correct, storage key was rewrapped, CALLING +/// FUNCTION SHOULD storage_commit() +pintest_t session_clear_impl(SessionState *session, Storage *storage, + bool clear_pin); /// \brief Get user private seed. /// \returns NULL on error, otherwise \returns the private seed. const uint8_t *storage_getSeed(const ConfigFlash *cfg, bool usePassphrase); typedef enum { - SUS_Invalid, - SUS_Valid, - SUS_Updated, + SUS_Invalid, + SUS_Valid, + SUS_Updated, } StorageUpdateStatus; /// \brief Copy configuration from storage partition in flash memory to shadow /// memory in RAM /// \returns true iff successful. -StorageUpdateStatus storage_fromFlash(SessionState *ss, ConfigFlash *dst, const char *flash); +StorageUpdateStatus storage_fromFlash(SessionState *ss, ConfigFlash *dst, + const char *flash); void storage_upgradePolicies(Storage *storage); void storage_resetPolicies(Storage *storage); void storage_resetCache(Cache *cache); -void storage_readV1(SessionState *session, ConfigFlash *dst, const char *ptr, size_t len); -void storage_readV2(SessionState *session, ConfigFlash *dst, const char *ptr, size_t len); +void storage_readV1(SessionState *session, ConfigFlash *dst, const char *ptr, + size_t len); +void storage_readV2(SessionState *session, ConfigFlash *dst, const char *ptr, + size_t len); void storage_readV11(ConfigFlash *dst, const char *ptr, size_t len); +void storage_readV16(ConfigFlash *dst, const char *ptr, size_t len); void storage_writeV11(char *ptr, size_t len, const ConfigFlash *src); +void storage_writeV16(char *ptr, size_t len, const ConfigFlash *src); void storage_readMeta(Metadata *meta, const char *ptr, size_t len); void storage_readPolicyV1(PolicyType *policy, const char *ptr, size_t len); void storage_readHDNode(HDNodeType *node, const char *ptr, size_t len); -void storage_readStorageV1(SessionState *session, Storage *storage, const char *ptr, size_t len); +void storage_readStorageV1(SessionState *session, Storage *storage, + const char *ptr, size_t len); void storage_readStorageV11(Storage *storage, const char *ptr, size_t len); void storage_readCacheV1(Cache *cache, const char *ptr, size_t len); @@ -171,7 +208,13 @@ void storage_writeHDNode(char *ptr, size_t len, const HDNodeType *node); void storage_writeStorageV11(char *ptr, size_t len, const Storage *storage); void storage_writeCacheV1(char *ptr, size_t len, const Cache *cache); -bool storage_setPolicy_impl(PolicyType policies[POLICY_COUNT], const char *policy_name, bool enabled); -bool storage_isPolicyEnabled_impl(const PolicyType policies[POLICY_COUNT], const char *policy_name); +bool storage_setPolicy_impl(PolicyType policies[POLICY_COUNT], + const char *policy_name, bool enabled); +bool storage_isPolicyEnabled_impl(const PolicyType policies[POLICY_COUNT], + const char *policy_name); + +bool storageHasWipeCode(void); +bool storageChangeWipeCode(uint32_t pin, const uint8_t *ext_salt, + uint32_t wipe_code); #endif diff --git a/lib/firmware/storage_versions.inc b/lib/firmware/storage_versions.inc index 23963d8aa..443c7e785 100644 --- a/lib/firmware/storage_versions.inc +++ b/lib/firmware/storage_versions.inc @@ -20,7 +20,8 @@ STORAGE_VERSION_ENTRY(11) STORAGE_VERSION_ENTRY(12) STORAGE_VERSION_ENTRY(13) STORAGE_VERSION_ENTRY(14) -STORAGE_VERSION_LAST(15) +STORAGE_VERSION_ENTRY(15) +STORAGE_VERSION_LAST(16) #undef STORAGE_VERSION_ENTRY diff --git a/lib/firmware/tendermint.c b/lib/firmware/tendermint.c index 891fc6fe5..59e8bb8e7 100644 --- a/lib/firmware/tendermint.c +++ b/lib/firmware/tendermint.c @@ -7,19 +7,17 @@ #include #include -bool tendermint_pathMismatched(const CoinType *coin, - const uint32_t *address_n, - const uint32_t address_n_count) -{ - // m / 44' / coin' / account' / 0 / 0 - bool mismatch = false; - mismatch |= address_n_count != 5; - mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); - mismatch |= address_n_count > 1 && (address_n[1] != coin->bip44_account_path); - mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; - mismatch |= address_n_count > 3 && address_n[3] != 0; - mismatch |= address_n_count > 4 && address_n[4] != 0; - return mismatch; +bool tendermint_pathMismatched(const CoinType *coin, const uint32_t *address_n, + const uint32_t address_n_count) { + // m / 44' / coin' / account' / 0 / 0 + bool mismatch = false; + mismatch |= address_n_count != 5; + mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); + mismatch |= address_n_count > 1 && (address_n[1] != coin->bip44_account_path); + mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; + mismatch |= address_n_count > 3 && address_n[3] != 0; + mismatch |= address_n_count > 4 && address_n[4] != 0; + return mismatch; } /** @@ -31,45 +29,44 @@ bool tendermint_pathMismatched(const CoinType *coin, * * \returns true if successful */ -bool tendermint_getAddress(const HDNode *node, const char *prefix, char *address) -{ - uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; - ecdsa_get_pubkeyhash(node->public_key, HASHER_SHA2_RIPEMD, hash160Buf); +bool tendermint_getAddress(const HDNode *node, const char *prefix, + char *address) { + uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; + ecdsa_get_pubkeyhash(node->public_key, HASHER_SHA2_RIPEMD, hash160Buf); - uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; - size_t len = 0; - convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1); - return bech32_encode(address, prefix, fiveBitExpanded, len) == 1; + uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; + size_t len = 0; + convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1); + return bech32_encode(address, prefix, fiveBitExpanded, len) == 1; } -void tendermint_sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) -{ - for (size_t i = 0; i != len; i++) { - if (s[i] == '"') { - sha256_Update(ctx, (const uint8_t *)"\\\"", 2); - } else if (s[i] == '\\') { - sha256_Update(ctx, (const uint8_t *)"\\\\", 2); - } else { - // The copy here is required (as opposed to a cast), since the - // source is a character array, and sha256_Update uses it as if it - // were an array of uint8_t, which would violate the strict aliasing - // rule. - const uint8_t c = s[i]; - sha256_Update(ctx, &c, 1); - } +void tendermint_sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, + size_t len) { + for (size_t i = 0; i != len; i++) { + if (s[i] == '"') { + sha256_Update(ctx, (const uint8_t *)"\\\"", 2); + } else if (s[i] == '\\') { + sha256_Update(ctx, (const uint8_t *)"\\\\", 2); + } else { + // The copy here is required (as opposed to a cast), since the + // source is a character array, and sha256_Update uses it as if it + // were an array of uint8_t, which would violate the strict aliasing + // rule. + const uint8_t c = s[i]; + sha256_Update(ctx, &c, 1); } + } } -bool tendermint_snprintf(SHA256_CTX *ctx, char *temp, size_t len, const char *format, ...) -{ - va_list vl; - va_start(vl, format); - int n = vsnprintf(temp, len, format, vl); - va_end(vl); +bool tendermint_snprintf(SHA256_CTX *ctx, char *temp, size_t len, + const char *format, ...) { + va_list vl; + va_start(vl, format); + int n = vsnprintf(temp, len, format, vl); + va_end(vl); - if (n < 0 || (size_t)n >= len) - return false; + if (n < 0 || (size_t)n >= len) return false; - sha256_Update(ctx, (const uint8_t *)temp, n); - return true; + sha256_Update(ctx, (const uint8_t *)temp, n); + return true; } diff --git a/lib/firmware/transaction.c b/lib/firmware/transaction.c index b929aee9c..8d2453ec2 100644 --- a/lib/firmware/transaction.c +++ b/lib/firmware/transaction.c @@ -25,6 +25,8 @@ #include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/coins.h" #include "keepkey/firmware/crypto.h" +#include "keepkey/firmware/signing.h" +#include "keepkey/firmware/txin_check.h" #include "keepkey/transport/interface.h" #include "trezor/crypto/address.h" #include "trezor/crypto/base58.h" @@ -42,7 +44,7 @@ #define CASHADDR_P2KH (0) #define CASHADDR_P2SH (8) -#define CASHADDR_160 (0) +#define CASHADDR_160 (0) /* transaction input size (without script): 32 prevhash, 4 idx, 4 sequence */ #define TXSIZE_INPUT 40 @@ -62,879 +64,953 @@ #define TXSIZE_P2PKHASH 25 /* size of a p2sh script (hash, push, 20 scripthash, equal) */ #define TXSIZE_P2SCRIPT 23 -/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block index */ +/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block + * index */ #define TXSIZE_DECRED_WITNESS 16 -static const uint8_t segwit_header[2] = {0,1}; +static const uint8_t segwit_header[2] = {0, 1}; static inline uint32_t op_push_size(uint32_t i) { - if (i < 0x4C) { - return 1; - } - if (i < 0x100) { - return 2; - } - if (i < 0x10000) { - return 3; - } - return 5; + if (i < 0x4C) { + return 1; + } + if (i < 0x100) { + return 2; + } + if (i < 0x10000) { + return 3; + } + return 5; } uint32_t op_push(uint32_t i, uint8_t *out) { - if (i < 0x4C) { - out[0] = i & 0xFF; - return 1; - } - if (i < 0x100) { - out[0] = 0x4C; - out[1] = i & 0xFF; - return 2; - } - if (i < 0x10000) { - out[0] = 0x4D; - out[1] = i & 0xFF; - out[2] = (i >> 8) & 0xFF; - return 3; - } - out[0] = 0x4E; - out[1] = i & 0xFF; - out[2] = (i >> 8) & 0xFF; - out[3] = (i >> 16) & 0xFF; - out[4] = (i >> 24) & 0xFF; - return 5; -} - -bool compute_address(const CoinType *coin, - InputScriptType script_type, - const HDNode *node, - bool has_multisig, const MultisigRedeemScriptType *multisig, - char address[MAX_ADDR_SIZE]) { - - uint8_t raw[MAX_ADDR_RAW_SIZE]; - uint8_t digest[32]; - size_t prelen; - - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return 0; - - if (has_multisig) { - if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) { - return 0; - } - if (compile_script_multisig_hash(coin, multisig, digest) == 0) { - return 0; - } - if (script_type == InputScriptType_SPENDWITNESS) { - // segwit p2wsh: script hash is single sha256 - if ((!coin->has_segwit || !coin->segwit) || !coin->has_bech32_prefix) { - return 0; - } - if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 32)) { - return 0; - } - } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { - // segwit p2wsh encapsuled in p2sh address - if (!coin->has_segwit || !coin->segwit) { - return 0; - } - if (!coin->has_address_type_p2sh) { - return 0; - } - raw[0] = 0; // push version - raw[1] = 32; // push 32 bytes - memcpy(raw + 2, digest, 32); // push hash - hasher_Raw(curve->hasher_pubkey, raw, 34, digest); - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - memcpy(raw + prelen, digest, 32); - if (!base58_encode_check(raw, prelen + 20, curve->hasher_base58, address, MAX_ADDR_SIZE)) { - return 0; - } - } else if (coin->has_cashaddr_prefix) { - raw[0] = CASHADDR_P2SH | CASHADDR_160; - ripemd160(digest, 32, raw + 1); - if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { - return 0; - } - } else { - // non-segwit p2sh multisig - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, curve->hasher_base58, address, MAX_ADDR_SIZE)) { - return 0; - } - } - } else if (script_type == InputScriptType_SPENDWITNESS) { - // segwit p2wpkh: pubkey hash is ripemd160 of sha256 - if ((!coin->has_segwit || !coin->segwit) || !coin->has_bech32_prefix) { - return 0; - } - ecdsa_get_pubkeyhash(node->public_key, curve->hasher_pubkey, digest); - if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { - return 0; - } - } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { - // segwit p2wpkh embedded in p2sh - if (!coin->has_segwit || !coin->segwit) { - return 0; - } - if (!coin->has_address_type_p2sh) { - return 0; - } - ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, curve->hasher_pubkey, curve->hasher_base58, address, MAX_ADDR_SIZE); - } else if (coin->has_cashaddr_prefix) { - ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, curve->hasher_pubkey, raw); - if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { - return 0; - } - } else { - ecdsa_get_address(node->public_key, coin->address_type, curve->hasher_pubkey, curve->hasher_base58, address, MAX_ADDR_SIZE); - } - return 1; -} - -int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) -{ - memset(out, 0, sizeof(TxOutputBinType)); - out->amount = in->amount; - out->decred_script_version = in->decred_script_version; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - size_t addr_raw_len; - - if (in->script_type == OutputScriptType_PAYTOOPRETURN) { - // only 0 satoshi allowed for OP_RETURN - if (in->amount != 0) { - return 0; // failed to compile output - } - if (needs_confirm) { - if (in->op_return_data.size >= 8 && memcmp(in->op_return_data.bytes, "omni", 4) == 0) { // OMNI transaction - if (!confirm_omni(ButtonRequestType_ButtonRequest_ConfirmOutput, _("Confirm OMNI"), in->op_return_data.bytes, in->op_return_data.size)) { - return -1; // user aborted - } - } else { - if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmOutput, _("Confirm OP_RETURN"), in->op_return_data.bytes, in->op_return_data.size)) { - return -1; // user aborted - } - } - } - uint32_t r = 0; - out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN - r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); - memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; - out->script_pubkey.size = r; - return r; - } - - if (in->address_n_count > 0) { - static CONFIDENTIAL HDNode node; - InputScriptType input_script_type; - - switch (in->script_type) { - case OutputScriptType_PAYTOADDRESS: - input_script_type = InputScriptType_SPENDADDRESS; - break; - case OutputScriptType_PAYTOMULTISIG: - input_script_type = InputScriptType_SPENDMULTISIG; - break; - case OutputScriptType_PAYTOWITNESS: - input_script_type = InputScriptType_SPENDWITNESS; - break; - case OutputScriptType_PAYTOP2SHWITNESS: - input_script_type = InputScriptType_SPENDP2SHWITNESS; - break; - default: - return 0; // failed to compile output - } - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { - return 0; // failed to compile output - } - hdnode_fill_public_key(&node); - if (!compute_address(coin, input_script_type, &node, - in->has_multisig, &in->multisig, - in->address)) { - return 0; // failed to compile output - } - } else if (!in->has_address) { - return 0; // failed to compile output - } - - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return 0; - - addr_raw_len = base58_decode_check(in->address, curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - size_t prefix_len; - if (coin->has_address_type // p2pkh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) - && address_check_prefix(addr_raw, coin->address_type)) { - out->script_pubkey.bytes[0] = 0x76; // OP_DUP - out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY - out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG - out->script_pubkey.size = 25; - } else if (coin->has_address_type_p2sh // p2sh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh)) - && address_check_prefix(addr_raw, coin->address_type_p2sh)) { - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - - // If the user is sending sending to a 3 address warn them that they could be burning their coins - // I.E. sending bch to a btc segwit address - if (memcmp(coin->coin_name, "BitcoinCash", sizeof("BitcoinCash")) == 0) { - if (!confirm_without_button_request("WARNING", - "Sending to \"3\" addresses is not recommended for BCH. " - "Continue at your own risk!")) { - return TXOUT_CANCEL; - } - } - } else if (coin->has_cashaddr_prefix - && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) { - if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { - out->script_pubkey.bytes[0] = 0x76; // OP_DUP - out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); - out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY - out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG - out->script_pubkey.size = 25; - - } else if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - } else { - return 0; - } - } else if (coin->has_bech32_prefix) { - int witver; - if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { - return 0; - } - // segwit: - // push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i) - // push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40) - out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver; - out->script_pubkey.bytes[1] = addr_raw_len; - memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len); - out->script_pubkey.size = addr_raw_len + 2; - } else { - return 0; - } - - // KeepKey custom: outputs must have sane address type - if (in->has_address_type) { - switch (in->address_type) { - case OutputAddressType_SPEND: { - if (!in->has_address) - return 0; - } break; - - case OutputAddressType_TRANSFER: - case OutputAddressType_CHANGE: { - if (in->address_n_count == 0) - return 0; - // TRANSFERs only allowed to the 'external' chain, not to the - // 'change' chain. - if (in->address_type == OutputAddressType_TRANSFER) - if (in->address_n_count < 5 || - in->address_n[3] != 0) - return 0; - } break; - - case OutputAddressType_EXCHANGE: { - if (!in->has_exchange_type) - return false; - } break; - } - } - - // KeepKey custom: internal transfer screen - if (needs_confirm && in->address_n_count > 0) { - switch (in->script_type) { - case OutputScriptType_PAYTOSCRIPTHASH: - case OutputScriptType_PAYTOMULTISIG: - case OutputScriptType_PAYTOOPRETURN: - break; - case OutputScriptType_PAYTOADDRESS: - case OutputScriptType_PAYTOWITNESS: - case OutputScriptType_PAYTOP2SHWITNESS: { - char amount_str[32]; - char node_str[NODE_STRING_LENGTH]; - coin_amnt_to_str(coin, in->amount, amount_str, sizeof(amount_str)); - memset(node_str, 0, sizeof(node_str)); - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, in->address_n, - in->address_n_count, /*whole_account=*/false, - /*show_addridx=*/true)) - break; - if (!confirm_transfer_output(ButtonRequestType_ButtonRequest_ConfirmTransferToAccount, amount_str, node_str)) - return TXOUT_CANCEL; - return out->script_pubkey.size; - } - } - } - - if (needs_confirm) { - char amount_str[32]; - coin_amnt_to_str(coin, in->amount, amount_str, sizeof(amount_str)); - if (coin->has_cashaddr_prefix) { - prefix_len = strlen(coin->cashaddr_prefix) + 1; - if (memcmp(coin->cashaddr_prefix, in->address, prefix_len) != 0) - prefix_len = 0; - } else { - prefix_len = 0; - } - if (!confirm_transaction_output(ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, - prefix_len + in->address)) { - return -1; // user aborted - } - } - - return out->script_pubkey.size; -} - -uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out) -{ - if (coinByAddressType(address_type)) { // valid coin type - out[0] = 0x76; // OP_DUP - out[1] = 0xA9; // OP_HASH_160 - out[2] = 0x14; // pushing 20 bytes - memcpy(out + 3, pubkeyhash, 20); - out[23] = 0x88; // OP_EQUALVERIFY - out[24] = 0xAC; // OP_CHECKSIG - return 25; - } else { - return 0; // unsupported - } + if (i < 0x4C) { + out[0] = i & 0xFF; + return 1; + } + if (i < 0x100) { + out[0] = 0x4C; + out[1] = i & 0xFF; + return 2; + } + if (i < 0x10000) { + out[0] = 0x4D; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + return 3; + } + out[0] = 0x4E; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + out[3] = (i >> 16) & 0xFF; + out[4] = (i >> 24) & 0xFF; + return 5; +} + +bool compute_address(const CoinType *coin, InputScriptType script_type, + const HDNode *node, bool has_multisig, + const MultisigRedeemScriptType *multisig, + char address[MAX_ADDR_SIZE]) { + uint8_t raw[MAX_ADDR_RAW_SIZE]; + uint8_t digest[32]; + size_t prelen; + + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return 0; + + if (has_multisig) { + if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) { + return 0; + } + if (compile_script_multisig_hash(coin, multisig, digest) == 0) { + return 0; + } + if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wsh: script hash is single sha256 + if ((!coin->has_segwit || !coin->segwit) || !coin->has_bech32_prefix) { + return 0; + } + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, + digest, 32)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wsh encapsuled in p2sh address + if (!coin->has_segwit || !coin->segwit) { + return 0; + } + if (!coin->has_address_type_p2sh) { + return 0; + } + raw[0] = 0; // push version + raw[1] = 32; // push 32 bytes + memcpy(raw + 2, digest, 32); // push hash + hasher_Raw(curve->hasher_pubkey, raw, 34, digest); + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + memcpy(raw + prelen, digest, 32); + if (!base58_encode_check(raw, prelen + 20, curve->hasher_base58, address, + MAX_ADDR_SIZE)) { + return 0; + } + } else if (coin->has_cashaddr_prefix) { + raw[0] = CASHADDR_P2SH | CASHADDR_160; + ripemd160(digest, 32, raw + 1); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } + } else { + // non-segwit p2sh multisig + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, prelen + 20, curve->hasher_base58, address, + MAX_ADDR_SIZE)) { + return 0; + } + } + } else if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wpkh: pubkey hash is ripemd160 of sha256 + if ((!coin->has_segwit || !coin->segwit) || !coin->has_bech32_prefix) { + return 0; + } + ecdsa_get_pubkeyhash(node->public_key, curve->hasher_pubkey, digest); + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, + digest, 20)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wpkh embedded in p2sh + if (!coin->has_segwit || !coin->segwit) { + return 0; + } + if (!coin->has_address_type_p2sh) { + return 0; + } + ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, + curve->hasher_pubkey, curve->hasher_base58, + address, MAX_ADDR_SIZE); + } else if (coin->has_cashaddr_prefix) { + ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, + curve->hasher_pubkey, raw); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } + } else { + ecdsa_get_address(node->public_key, coin->address_type, + curve->hasher_pubkey, curve->hasher_base58, address, + MAX_ADDR_SIZE); + } + return 1; +} + +int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, + TxOutputBinType *out, bool needs_confirm) { + memset(out, 0, sizeof(TxOutputBinType)); + out->amount = in->amount; + out->decred_script_version = in->decred_script_version; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + size_t addr_raw_len; + + if (in->script_type == OutputScriptType_PAYTOOPRETURN) { + // only 0 satoshi allowed for OP_RETURN + if (in->amount != 0) { + return 0; // failed to compile output + } + if (needs_confirm) { + if (in->op_return_data.size >= 8 && + memcmp(in->op_return_data.bytes, "omni", 4) == + 0) { // OMNI transaction + if (!confirm_omni(ButtonRequestType_ButtonRequest_ConfirmOutput, + _("Confirm OMNI"), in->op_return_data.bytes, + in->op_return_data.size)) { + return -1; // user aborted + } + } else { + if (!confirm_data(ButtonRequestType_ButtonRequest_ConfirmOutput, + _("Confirm OP_RETURN"), in->op_return_data.bytes, + in->op_return_data.size)) { + return -1; // user aborted + } + } + } + uint32_t r = 0; + out->script_pubkey.bytes[0] = 0x6A; + r++; // OP_RETURN + r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); + memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, + in->op_return_data.size); + r += in->op_return_data.size; + out->script_pubkey.size = r; + return r; + } + + if (in->address_n_count > 0) { + static CONFIDENTIAL HDNode node; + InputScriptType input_script_type; + + switch (in->script_type) { + case OutputScriptType_PAYTOADDRESS: + input_script_type = InputScriptType_SPENDADDRESS; + break; + case OutputScriptType_PAYTOMULTISIG: + input_script_type = InputScriptType_SPENDMULTISIG; + break; + case OutputScriptType_PAYTOWITNESS: + input_script_type = InputScriptType_SPENDWITNESS; + break; + case OutputScriptType_PAYTOP2SHWITNESS: + input_script_type = InputScriptType_SPENDP2SHWITNESS; + break; + default: + return 0; // failed to compile output + } + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, + NULL) == 0) { + return 0; // failed to compile output + } + hdnode_fill_public_key(&node); + if (!compute_address(coin, input_script_type, &node, in->has_multisig, + &in->multisig, in->address)) { + return 0; // failed to compile output + } + } else if (!in->has_address) { + return 0; // failed to compile output + } + + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return 0; + + addr_raw_len = base58_decode_check(in->address, curve->hasher_base58, + addr_raw, MAX_ADDR_RAW_SIZE); + size_t prefix_len; + if (coin->has_address_type // p2pkh + && addr_raw_len == + 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) && + address_check_prefix(addr_raw, coin->address_type)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + } else if (coin->has_address_type_p2sh // p2sh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len( + coin->address_type_p2sh)) && + address_check_prefix(addr_raw, coin->address_type_p2sh)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + + // If the user is sending sending to a 3 address warn them that they could + // be burning their coins I.E. sending bch to a btc segwit address + if (memcmp(coin->coin_name, "BitcoinCash", sizeof("BitcoinCash")) == 0) { + if (!confirm_without_button_request( + "WARNING", + "Sending to \"3\" addresses is not recommended for BCH. " + "Continue at your own risk!")) { + return TXOUT_CANCEL; + } + } + } else if (coin->has_cashaddr_prefix && + cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, + in->address)) { + if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + + } else if (addr_raw_len == 21 && + addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else { + return 0; + } + } else if (coin->has_bech32_prefix) { + int witver; + if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, + coin->bech32_prefix, in->address)) { + return 0; + } + // segwit: + // push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i) + // push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40) + out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver; + out->script_pubkey.bytes[1] = addr_raw_len; + memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len); + out->script_pubkey.size = addr_raw_len + 2; + } else { + return 0; + } + + // KeepKey custom: outputs must have sane address type + if (in->has_address_type) { + switch (in->address_type) { + case OutputAddressType_SPEND: { + if (!in->has_address) return 0; + } break; + + case OutputAddressType_TRANSFER: + case OutputAddressType_CHANGE: { + if (in->address_n_count == 0) return 0; + // TRANSFERs only allowed to the 'external' chain, not to the + // 'change' chain. + if (in->address_type == OutputAddressType_TRANSFER) + if (in->address_n_count < 5 || in->address_n[3] != 0) return 0; + } break; + + case OutputAddressType_EXCHANGE: { + if (!in->has_exchange_type) return false; + } break; + } + } + + // KeepKey custom: internal transfer screen + if (needs_confirm && in->address_n_count > 0) { + switch (in->script_type) { + case OutputScriptType_PAYTOSCRIPTHASH: + case OutputScriptType_PAYTOMULTISIG: + case OutputScriptType_PAYTOOPRETURN: + break; + case OutputScriptType_PAYTOADDRESS: + case OutputScriptType_PAYTOWITNESS: + case OutputScriptType_PAYTOP2SHWITNESS: { + char amount_str[32]; + char node_str[NODE_STRING_LENGTH]; + coin_amnt_to_str(coin, in->amount, amount_str, sizeof(amount_str)); + memset(node_str, 0, sizeof(node_str)); + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, + in->address_n, in->address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true)) + break; + if (!confirm_transfer_output( + ButtonRequestType_ButtonRequest_ConfirmTransferToAccount, + amount_str, node_str)) + return TXOUT_CANCEL; + return out->script_pubkey.size; + } + } + } + + if (needs_confirm) { + char amount_str[32]; + int retval = 0; + coin_amnt_to_str(coin, in->amount, amount_str, sizeof(amount_str)); + if (coin->has_cashaddr_prefix) { + prefix_len = strlen(coin->cashaddr_prefix) + 1; + if (memcmp(coin->cashaddr_prefix, in->address, prefix_len) != 0) + prefix_len = 0; + } else { + prefix_len = 0; + } + + if (!confirm_transaction_output( + ButtonRequestType_ButtonRequest_ConfirmOutput, amount_str, + prefix_len + in->address)) { + return -1; // user aborted + } + + /* + This vuln fix prevents two identical transactions to be signed sequentially. + Thus it also prevents potential valid multisig transactions that submit the + same tx twice in a row with different signing keys. If a multisig client is + built then this fix will need to be modified. + */ + // Check for tx with the same output as previous but different inputs. Could + // be host malware + if (txin_dgst_compare(amount_str, prefix_len + in->address)) { + char prev[DIGEST_STR_LEN], cur[DIGEST_STR_LEN]; + txin_dgst_getstrs(prev, cur, DIGEST_STR_LEN); + review(ButtonRequestType_ButtonRequest_Other, + "WARNING: Duplicate Transaction!", + "Already signed a tx with the same outputs\n" + "To try again, unplug/replug KeepKey."); + retval = -1; // abort + } + txin_dgst_save_and_reset(amount_str, prefix_len + in->address); + + if (retval == -1) { + return retval; + } + } + + return out->script_pubkey.size; +} + +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, + uint8_t *out) { + if (coinByAddressType(address_type)) { // valid coin type + out[0] = 0x76; // OP_DUP + out[1] = 0xA9; // OP_HASH_160 + out[2] = 0x14; // pushing 20 bytes + memcpy(out + 3, pubkeyhash, 20); + out[23] = 0x88; // OP_EQUALVERIFY + out[24] = 0xAC; // OP_CHECKSIG + return 25; + } else { + return 0; // unsupported + } } // if out == NULL just compute the length -uint32_t compile_script_multisig(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t *out) -{ - if (!multisig->has_m) return 0; - const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; - if (m < 1 || m > 15) return 0; - if (n < 1 || n > 15) return 0; - uint32_t r = 0; - if (out) { - out[r] = 0x50 + m; r++; - for (uint32_t i = 0; i < n; i++) { - out[r] = 33; r++; // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - memcpy(out + r, pubkey, 33); r += 33; - } - out[r] = 0x50 + n; r++; - out[r] = 0xAE; r++; // OP_CHECKMULTISIG - } else { - r = 1 + 34 * n + 2; - } - return r; -} - -uint32_t compile_script_multisig_hash(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash) -{ - if (!multisig->has_m) return 0; - const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; - if (m < 1 || m > 15) return 0; - if (n < 1 || n > 15) return 0; - - const curve_info *curve = get_curve_by_name(coin->curve_name); - if (!curve) return 0; - - Hasher hasher; - hasher_Init(&hasher, curve->hasher_script); - - uint8_t d[2]; - d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); - for (uint32_t i = 0; i < n; i++) { - d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - hasher_Update(&hasher, pubkey, 33); - } - d[0] = 0x50 + n; - d[1] = 0xAE; - hasher_Update(&hasher, d, 2); - - hasher_Final(&hasher, hash); - - return 1; -} - -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out) -{ - uint32_t r = 0; - r += op_push(signature_len + 1, out + r); - memcpy(out + r, signature, signature_len); r += signature_len; - out[r] = sighash; r++; - r += op_push(pubkey_len, out + r); - memcpy(out + r, pubkey, pubkey_len); r += pubkey_len; - return r; -} - -uint32_t serialize_script_multisig(const CoinType *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) -{ - uint32_t r = 0; - if (!coin->decred) { - // Decred fixed the off-by-one bug - out[r] = 0x00; r++; - } - for (uint32_t i = 0; i < multisig->signatures_count; i++) { - if (multisig->signatures[i].size == 0) { - continue; - } - r += op_push(multisig->signatures[i].size + 1, out + r); - memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; - out[r] = sighash; r++; - } - uint32_t script_len = compile_script_multisig(coin, multisig, 0); - if (script_len == 0) { - return 0; - } - r += op_push(script_len, out + r); - r += compile_script_multisig(coin, multisig, out + r); - return r; +uint32_t compile_script_multisig(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *out) { + if (!multisig->has_m) return 0; + const uint32_t m = multisig->m; + const uint32_t n = multisig->pubkeys_count; + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; + uint32_t r = 0; + if (out) { + out[r] = 0x50 + m; + r++; + for (uint32_t i = 0; i < n; i++) { + out[r] = 33; + r++; // OP_PUSH 33 + const uint8_t *pubkey = + cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); + if (!pubkey) return 0; + memcpy(out + r, pubkey, 33); + r += 33; + } + out[r] = 0x50 + n; + r++; + out[r] = 0xAE; + r++; // OP_CHECKMULTISIG + } else { + r = 1 + 34 * n + 2; + } + return r; +} + +uint32_t compile_script_multisig_hash(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *hash) { + if (!multisig->has_m) return 0; + const uint32_t m = multisig->m; + const uint32_t n = multisig->pubkeys_count; + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; + + const curve_info *curve = get_curve_by_name(coin->curve_name); + if (!curve) return 0; + + Hasher hasher; + hasher_Init(&hasher, curve->hasher_script); + + uint8_t d[2]; + d[0] = 0x50 + m; + hasher_Update(&hasher, d, 1); + for (uint32_t i = 0; i < n; i++) { + d[0] = 33; + hasher_Update(&hasher, d, 1); // OP_PUSH 33 + const uint8_t *pubkey = + cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); + if (!pubkey) return 0; + hasher_Update(&hasher, pubkey, 33); + } + d[0] = 0x50 + n; + d[1] = 0xAE; + hasher_Update(&hasher, d, 2); + + hasher_Final(&hasher, hash); + + return 1; +} + +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, + const uint8_t *pubkey, uint32_t pubkey_len, + uint8_t sighash, uint8_t *out) { + uint32_t r = 0; + r += op_push(signature_len + 1, out + r); + memcpy(out + r, signature, signature_len); + r += signature_len; + out[r] = sighash; + r++; + r += op_push(pubkey_len, out + r); + memcpy(out + r, pubkey, pubkey_len); + r += pubkey_len; + return r; +} + +uint32_t serialize_script_multisig(const CoinType *coin, + const MultisigRedeemScriptType *multisig, + uint8_t sighash, uint8_t *out) { + uint32_t r = 0; + if (!coin->decred) { + // Decred fixed the off-by-one bug + out[r] = 0x00; + r++; + } + for (uint32_t i = 0; i < multisig->signatures_count; i++) { + if (multisig->signatures[i].size == 0) { + continue; + } + r += op_push(multisig->signatures[i].size + 1, out + r); + memcpy(out + r, multisig->signatures[i].bytes, + multisig->signatures[i].size); + r += multisig->signatures[i].size; + out[r] = sighash; + r++; + } + uint32_t script_len = compile_script_multisig(coin, multisig, 0); + if (script_len == 0) { + return 0; + } + r += op_push(script_len, out + r); + r += compile_script_multisig(coin, multisig, out + r); + return r; } // tx methods -uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) -{ - for (int i = 0; i < 32; i++) { - hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); - } - hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); - return 36; -} - -uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) -{ - int r = ser_length_hash(hasher, size); - hasher_Update(hasher, data, size); - return r + size; -} - -uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) -{ - hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); - return 4; -} - -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) -{ - uint32_t r = 0; - hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; - if (decred) { - uint16_t script_version = output->decred_script_version & 0xFFFF; - hasher_Update(hasher, (const uint8_t *)&script_version, 2); r += 2; - } - r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); - return r; -} - -uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) -{ - int r = ser_length(size, out); - memcpy(out + r, data, size); - return r + size; -} - -uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) -{ - int r = 4; - if (tx->overwintered) { - uint32_t ver = tx->version | TX_OVERWINTERED; - memcpy(out, &ver, 4); - memcpy(out + 4, &(tx->version_group_id), 4); - r += 4; - } else { - memcpy(out, &(tx->version), 4); - if (tx->is_segwit) { - memcpy(out + r, segwit_header, 2); - r += 2; - } - } - return r + ser_length(tx->inputs_len, out + r); -} - -uint32_t tx_serialize_header_hash(TxStruct *tx) -{ - int r = 4; - if (tx->overwintered) { - uint32_t ver = tx->version | TX_OVERWINTERED; - hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version_group_id), 4); - r += 4; - } else { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); - if (tx->is_segwit) { - hasher_Update(&(tx->hasher), segwit_header, 2); - r += 2; - } - } - return r + ser_length_hash(&(tx->hasher), tx->inputs_len); -} - -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header(tx, out + r); - } - for (int i = 0; i < 32; i++) { - *(out + r + i) = input->prev_hash.bytes[31 - i]; - } - r += 32; - memcpy(out + r, &input->prev_index, 4); r += 4; - if (tx->is_decred) { - uint8_t tree = input->decred_tree & 0xFF; - out[r++] = tree; - } else { - r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); - } - memcpy(out + r, &input->sequence, 4); r += 4; - - tx->have_inputs++; - tx->size += r; - - return r; -} - -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header_hash(tx); - } - r += tx_prevout_hash(&(tx->hasher), input); - if (tx->is_decred) { - uint8_t tree = input->decred_tree & 0xFF; - hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); r++; - } else { - r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); - } - r += tx_sequence_hash(&(tx->hasher), input); - - tx->have_inputs++; - tx->size += r; - - return r; -} - -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) -{ - static const uint64_t amount = 0; - static const uint32_t block_height = 0x00000000; - static const uint32_t block_index = 0xFFFFFFFF; - - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += ser_length(tx->inputs_len, out + r); - } - memcpy(out + r, &amount, 8); r += 8; - memcpy(out + r, &block_height, 4); r += 4; - memcpy(out + r, &block_index, 4); r += 4; - r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); - - tx->have_inputs++; - tx->size += r; - - return r; -} - -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header_hash(tx); - } - if (input == NULL) { - r += ser_length_hash(&(tx->hasher), 0); - } else { - r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); - } - - tx->have_inputs++; - tx->size += r; - - return r; -} - -uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) -{ - return ser_length(tx->outputs_len, out); -} - -uint32_t tx_serialize_middle_hash(TxStruct *tx) -{ - return ser_length_hash(&(tx->hasher), tx->outputs_len); -} - -uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) -{ - memcpy(out, &(tx->lock_time), 4); - if (tx->overwintered) { - if (tx->version == 3) { - memcpy(out + 4, &(tx->expiry), 4); - out[8] = 0x00; // nJoinSplit - return 9; - } else - if (tx->version == 4) { - memcpy(out + 4, &(tx->expiry), 4); - memset(out + 8, 0, 8); // valueBalance - out[16] = 0x00; // nShieldedSpend - out[17] = 0x00; // nShieldedOutput - out[18] = 0x00; // nJoinSplit - return 19; - } - } - if (tx->is_decred) { - memcpy(out + 4, &(tx->expiry), 4); - return 8; - } - return 4; -} - -uint32_t tx_serialize_footer_hash(TxStruct *tx) -{ - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); - if (tx->overwintered) { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); - hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit - return 9; - } - if (tx->is_decred) { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); - return 8; - } - return 4; -} - -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs >= tx->outputs_len) { - // already got all outputs - return 0; - } - uint32_t r = 0; - if (tx->have_outputs == 0) { - r += tx_serialize_middle(tx, out + r); - } - memcpy(out + r, &output->amount, 8); r += 8; - if (tx->is_decred) { - uint16_t script_version = output->decred_script_version & 0xFFFF; - memcpy(out + r, &script_version, 2); r += 2; - } - r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); - tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len - && !tx->is_segwit) { - r += tx_serialize_footer(tx, out + r); - } - tx->size += r; - return r; -} - -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs >= tx->outputs_len) { - // already got all outputs - return 0; - } - uint32_t r = 0; - if (tx->have_outputs == 0) { - r += tx_serialize_middle_hash(tx); - } - r += tx_output_hash(&(tx->hasher), output, tx->is_decred); - tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len - && !tx->is_segwit) { - r += tx_serialize_footer_hash(tx); - } - tx->size += r; - return r; -} - -uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs < tx->outputs_len) { - // not all inputs provided - return 0; - } - if (tx->extra_data_received + datalen > tx->extra_data_len) { - // we are receiving too much data - return 0; - } - hasher_Update(&(tx->hasher), data, datalen); - tx->extra_data_received += datalen; - tx->size += datalen; - return datalen; -} - -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id) -{ - tx->inputs_len = inputs_len; - tx->outputs_len = outputs_len; - tx->version = version; - tx->lock_time = lock_time; - tx->expiry = expiry; - tx->have_inputs = 0; - tx->have_outputs = 0; - tx->extra_data_len = extra_data_len; - tx->extra_data_received = 0; - tx->size = 0; - tx->is_segwit = false; - tx->is_decred = false; - tx->overwintered = overwintered; - tx->version_group_id = version_group_id; - hasher_Init(&(tx->hasher), hasher_sign); -} - -void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) -{ - hasher_Final(&(t->hasher), hash); - if (!reverse) return; - for (uint8_t i = 0; i < 16; i++) { - uint8_t k = hash[31 - i]; - hash[31 - i] = hash[i]; - hash[i] = k; - } +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) { + for (int i = 0; i < 32; i++) { + hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); + } + hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); + return 36; +} + +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) { + int r = ser_length_hash(hasher, size); + hasher_Update(hasher, data, size); + return r + size; +} + +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) { + hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); + return 4; +} + +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, + bool decred) { + uint32_t r = 0; + hasher_Update(hasher, (const uint8_t *)&output->amount, 8); + r += 8; + if (decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + hasher_Update(hasher, (const uint8_t *)&script_version, 2); + r += 2; + } + r += tx_script_hash(hasher, output->script_pubkey.size, + output->script_pubkey.bytes); + return r; +} + +uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) { + int r = ser_length(size, out); + memcpy(out + r, data, size); + return r + size; +} + +uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { + int r = 4; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + memcpy(out, &ver, 4); + memcpy(out + 4, &(tx->version_group_id), 4); + r += 4; + } else { + memcpy(out, &(tx->version), 4); + if (tx->is_segwit) { + memcpy(out + r, segwit_header, 2); + r += 2; + } + } + return r + ser_length(tx->inputs_len, out + r); +} + +uint32_t tx_serialize_header_hash(TxStruct *tx) { + int r = 4; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version_group_id), 4); + r += 4; + } else { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); + if (tx->is_segwit) { + hasher_Update(&(tx->hasher), segwit_header, 2); + r += 2; + } + } + return r + ser_length_hash(&(tx->hasher), tx->inputs_len); +} + +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, + uint8_t *out) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header(tx, out + r); + } + for (int i = 0; i < 32; i++) { + *(out + r + i) = input->prev_hash.bytes[31 - i]; + } + r += 32; + memcpy(out + r, &input->prev_index, 4); + r += 4; + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + out[r++] = tree; + } else { + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, + out + r); + } + memcpy(out + r, &input->sequence, 4); + r += 4; + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + r += tx_prevout_hash(&(tx->hasher), input); + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); + r++; + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, + input->script_sig.bytes); + } + r += tx_sequence_hash(&(tx->hasher), input); + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, + uint8_t *out) { + static const uint64_t amount = 0; + static const uint32_t block_height = 0x00000000; + static const uint32_t block_index = 0xFFFFFFFF; + + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += ser_length(tx->inputs_len, out + r); + } + memcpy(out + r, &amount, 8); + r += 8; + memcpy(out + r, &block_height, 4); + r += 4; + memcpy(out + r, &block_index, 4); + r += 4; + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, + out + r); + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, + const TxInputType *input) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + if (input == NULL) { + r += ser_length_hash(&(tx->hasher), 0); + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, + input->script_sig.bytes); + } + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) { + return ser_length(tx->outputs_len, out); +} + +uint32_t tx_serialize_middle_hash(TxStruct *tx) { + return ser_length_hash(&(tx->hasher), tx->outputs_len); +} + +uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { + memcpy(out, &(tx->lock_time), 4); + if (tx->overwintered) { + if (tx->version == 3) { + memcpy(out + 4, &(tx->expiry), 4); + out[8] = 0x00; // nJoinSplit + return 9; + } else if (tx->version == 4) { + memcpy(out + 4, &(tx->expiry), 4); + memset(out + 8, 0, 8); // valueBalance + out[16] = 0x00; // nShieldedSpend + out[17] = 0x00; // nShieldedOutput + out[18] = 0x00; // nJoinSplit + return 19; + } + } + if (tx->is_decred) { + memcpy(out + 4, &(tx->expiry), 4); + return 8; + } + return 4; +} + +uint32_t tx_serialize_footer_hash(TxStruct *tx) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); + if (tx->overwintered) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit + return 9; + } + if (tx->is_decred) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); + return 8; + } + return 4; +} + +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, + uint8_t *out) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle(tx, out + r); + } + memcpy(out + r, &output->amount, 8); + r += 8; + if (tx->is_decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + memcpy(out + r, &script_version, 2); + r += 2; + } + r += tx_serialize_script(output->script_pubkey.size, + output->script_pubkey.bytes, out + r); + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { + r += tx_serialize_footer(tx, out + r); + } + tx->size += r; + return r; +} + +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle_hash(tx); + } + r += tx_output_hash(&(tx->hasher), output, tx->is_decred); + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { + r += tx_serialize_footer_hash(tx); + } + tx->size += r; + return r; +} + +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, + uint32_t datalen) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs < tx->outputs_len) { + // not all inputs provided + return 0; + } + if (tx->extra_data_received + datalen > tx->extra_data_len) { + // we are receiving too much data + return 0; + } + hasher_Update(&(tx->hasher), data, datalen); + tx->extra_data_received += datalen; + tx->size += datalen; + return datalen; +} + +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, + uint32_t version, uint32_t lock_time, uint32_t expiry, + uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, + uint32_t version_group_id) { + tx->inputs_len = inputs_len; + tx->outputs_len = outputs_len; + tx->version = version; + tx->lock_time = lock_time; + tx->expiry = expiry; + tx->have_inputs = 0; + tx->have_outputs = 0; + tx->extra_data_len = extra_data_len; + tx->extra_data_received = 0; + tx->size = 0; + tx->is_segwit = false; + tx->is_decred = false; + tx->overwintered = overwintered; + tx->version_group_id = version_group_id; + hasher_Init(&(tx->hasher), hasher_sign); +} + +void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { + hasher_Final(&(t->hasher), hash); + if (!reverse) return; + for (uint8_t i = 0; i < 16; i++) { + uint8_t k = hash[31 - i]; + hash[31 - i] = hash[i]; + hash[i] = k; + } } static uint32_t tx_input_script_size(const TxInputType *txinput) { - uint32_t input_script_size; - if (txinput->has_multisig) { - uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT - + txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); - input_script_size = 1 // the OP_FALSE bug in multisig - + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) - + op_push_size(multisig_script_size) + multisig_script_size; - } else { - input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); - } - - return input_script_size; + uint32_t input_script_size; + if (txinput->has_multisig) { + uint32_t multisig_script_size = + TXSIZE_MULTISIGSCRIPT + + txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); + input_script_size = 1 // the OP_FALSE bug in multisig + + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) + + op_push_size(multisig_script_size) + + multisig_script_size; + } else { + input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); + } + + return input_script_size; } uint32_t tx_input_weight(const CoinType *coin, const TxInputType *txinput) { - if (coin->decred) { - return 4 * (TXSIZE_INPUT + 1); // Decred tree - } - - uint32_t input_script_size = tx_input_script_size(txinput); - uint32_t weight = 4 * TXSIZE_INPUT; - if (txinput->script_type == InputScriptType_SPENDADDRESS - || txinput->script_type == InputScriptType_SPENDMULTISIG) { - input_script_size += ser_length_size(input_script_size); - weight += 4 * input_script_size; - } else if (txinput->script_type == InputScriptType_SPENDWITNESS - || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - weight += 4 * (2 + (txinput->has_multisig - ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH)); - } else { - weight += 4; // empty input script - } - weight += input_script_size; // discounted witness - } - return weight; -} - -uint32_t tx_output_weight(const CoinType *coin, const curve_info *curve, const TxOutputType *txoutput) { - uint32_t output_script_size = 0; - if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { - output_script_size = 1 + op_push_size(txoutput->op_return_data.size) - + txoutput->op_return_data.size; - } else if (txoutput->address_n_count > 0) { - if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { - output_script_size = txoutput->has_multisig - ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; - } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { - output_script_size = TXSIZE_P2SCRIPT; - } else { - output_script_size = txoutput->has_multisig - ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; - } - } else { - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int witver; - size_t addr_raw_len; - if (coin->has_cashaddr_prefix - && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) { - if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { - output_script_size = TXSIZE_P2PKHASH; - } else if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { - output_script_size = TXSIZE_P2SCRIPT; - } - } else if (coin->has_bech32_prefix - && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { - output_script_size = 2 + addr_raw_len; - } else { - addr_raw_len = base58_decode_check(txoutput->address, curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - if (coin->has_address_type - && address_check_prefix(addr_raw, coin->address_type)) { - output_script_size = TXSIZE_P2PKHASH; - } else if (coin->has_address_type_p2sh - && address_check_prefix(addr_raw, coin->address_type_p2sh)) { - output_script_size = TXSIZE_P2SCRIPT; - } - } - } - output_script_size += ser_length_size(output_script_size); - - uint32_t size = TXSIZE_OUTPUT; - if (coin->decred) { - size += 2; // Decred script version - } - - return 4 * (size + output_script_size); + if (coin->decred) { + return 4 * (TXSIZE_INPUT + 1); // Decred tree + } + + uint32_t input_script_size = tx_input_script_size(txinput); + uint32_t weight = 4 * TXSIZE_INPUT; + if (txinput->script_type == InputScriptType_SPENDADDRESS || + txinput->script_type == InputScriptType_SPENDMULTISIG) { + input_script_size += ser_length_size(input_script_size); + weight += 4 * input_script_size; + } else if (txinput->script_type == InputScriptType_SPENDWITNESS || + txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + weight += 4 * (2 + (txinput->has_multisig ? TXSIZE_WITNESSSCRIPT + : TXSIZE_WITNESSPKHASH)); + } else { + weight += 4; // empty input script + } + weight += input_script_size; // discounted witness + } + return weight; +} + +uint32_t tx_output_weight(const CoinType *coin, const curve_info *curve, + const TxOutputType *txoutput) { + uint32_t output_script_size = 0; + if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { + output_script_size = 1 + op_push_size(txoutput->op_return_data.size) + + txoutput->op_return_data.size; + } else if (txoutput->address_n_count > 0) { + if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + output_script_size = + txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { + output_script_size = TXSIZE_P2SCRIPT; + } else { + output_script_size = + txoutput->has_multisig ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; + } + } else { + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int witver; + size_t addr_raw_len; + if (coin->has_cashaddr_prefix && + cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, + txoutput->address)) { + if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (addr_raw_len == 21 && + addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } else if (coin->has_bech32_prefix && + segwit_addr_decode(&witver, addr_raw, &addr_raw_len, + coin->bech32_prefix, txoutput->address)) { + output_script_size = 2 + addr_raw_len; + } else { + addr_raw_len = base58_decode_check( + txoutput->address, curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); + if (coin->has_address_type && + address_check_prefix(addr_raw, coin->address_type)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (coin->has_address_type_p2sh && + address_check_prefix(addr_raw, coin->address_type_p2sh)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } + } + output_script_size += ser_length_size(output_script_size); + + uint32_t size = TXSIZE_OUTPUT; + if (coin->decred) { + size += 2; // Decred script version + } + + return 4 * (size + output_script_size); } uint32_t tx_decred_witness_weight(const TxInputType *txinput) { - uint32_t input_script_size = tx_input_script_size(txinput); - uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; + uint32_t input_script_size = tx_input_script_size(txinput); + uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + + input_script_size; - return 4 * size; + return 4 * size; } diff --git a/lib/firmware/txin_check.c b/lib/firmware/txin_check.c new file mode 100644 index 000000000..1a9ac976e --- /dev/null +++ b/lib/firmware/txin_check.c @@ -0,0 +1,95 @@ +/* + * This file is part of the KEEPKEY project. + * + * Copyright (C) 2020 Shapeshift + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include "keepkey/board/layout.h" +#include "keepkey/board/util.h" +#include "keepkey/firmware/txin_check.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/sha2.h" + +static uint8_t + txin_current_digest[SHA256_DIGEST_LENGTH]; /* current tx txins digest */ + +// these values help give a hint if malware is changing segwit txids in an +// attempt to create false txs +static uint8_t txin_last_digest[SHA256_DIGEST_LENGTH]; /* last tx digest */ +static char last_amount_str[AMT_STR_LEN]; /* spend value of last tx */ +static char last_addr_str[ADDR_STR_LEN]; /* last spend-to address */ +static SHA256_CTX txin_hash_ctx; + +// initialize the txin digest machine +void txin_dgst_initialize(void) { + memzero(txin_current_digest, SHA256_DIGEST_LENGTH); + memzero(txin_last_digest, SHA256_DIGEST_LENGTH); + memzero(last_amount_str, AMT_STR_LEN); + memzero(last_addr_str, ADDR_STR_LEN); + sha256_Init(&txin_hash_ctx); + return; +} + +// hash in a txin +void txin_dgst_addto(const uint8_t *data, size_t len) { + sha256_Update(&txin_hash_ctx, data, len); + return; +} + +// finalize txin digest +void txin_dgst_final(void) { + sha256_Final(&txin_hash_ctx, txin_current_digest); + return; +} + +// compare dgst, amt, addr +// returns True if warning condition met +bool txin_dgst_compare(const char *amt_str, const char *addr_str) { + // if amt and addr are same AND digest is different, then warn + if ((strncmp(amt_str, last_amount_str, AMT_STR_LEN) == 0) && + (strncmp(addr_str, last_addr_str, ADDR_STR_LEN) == 0)) { + if ((memcmp(txin_current_digest, txin_last_digest, SHA256_DIGEST_LENGTH) != + 0)) { + return (true); + } + } + return (false); +} + +// return string pointers to digests +void txin_dgst_getstrs(char *prev, char *cur, size_t len) { + if (len != DIGEST_STR_LEN) { + return; + } + data2hex(txin_current_digest, SHA256_DIGEST_LENGTH, cur); + kk_strlwr(cur); + data2hex(txin_last_digest, SHA256_DIGEST_LENGTH, prev); + kk_strlwr(prev); + return; +} + +// save last state and reset for next tx request +void txin_dgst_save_and_reset(char *amt_str, char *addr_str) { + memcpy(txin_last_digest, txin_current_digest, SHA256_DIGEST_LENGTH); + memcpy(last_amount_str, amt_str, AMT_STR_LEN); + memcpy(last_addr_str, addr_str, ADDR_STR_LEN); + memzero(txin_current_digest, SHA256_DIGEST_LENGTH); + sha256_Init(&txin_hash_ctx); + return; +} diff --git a/lib/firmware/u2f.c b/lib/firmware/u2f.c index 9ad9db613..2aa6352a6 100644 --- a/lib/firmware/u2f.c +++ b/lib/firmware/u2f.c @@ -47,16 +47,20 @@ #include #ifdef EMULATOR -# include +#include #endif #include // About 1/2 Second according to values used in protect.c -#define U2F_TIMEOUT (800000/2) +#define U2F_TIMEOUT (800000 / 2) #define U2F_OUT_PKT_BUFFER_LEN 130 -#define debugLog(L, B, T) do{}while(0) -#define debugInt(I) do{}while(0) +#define debugLog(L, B, T) \ + do { \ + } while (0) +#define debugInt(I) \ + do { \ + } while (0) // Initialise without a cid static uint32_t cid = 0; @@ -76,44 +80,44 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; #define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t)) // Defined as UsbSignHandler.BOGUS_APP_ID_HASH -// in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 +// in +// https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 #define BOGUS_APPID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" // Auth/Register request state machine typedef enum { - INIT = 0, - AUTH = 10, - AUTH_PASS = 11, - REG = 20, - REG_PASS = 21 + INIT = 0, + AUTH = 10, + AUTH_PASS = 11, + REG = 20, + REG_PASS = 21 } U2F_STATE; static U2F_STATE last_req_state = INIT; typedef struct { - uint8_t reserved; - uint8_t appId[U2F_APPID_SIZE]; - uint8_t chal[U2F_CHAL_SIZE]; - uint8_t keyHandle[KEY_HANDLE_LEN]; - uint8_t pubKey[U2F_PUBKEY_LEN]; + uint8_t reserved; + uint8_t appId[U2F_APPID_SIZE]; + uint8_t chal[U2F_CHAL_SIZE]; + uint8_t keyHandle[KEY_HANDLE_LEN]; + uint8_t pubKey[U2F_PUBKEY_LEN]; } U2F_REGISTER_SIG_STR; typedef struct { - uint8_t appId[U2F_APPID_SIZE]; - uint8_t flags; - uint8_t ctr[4]; - uint8_t chal[U2F_CHAL_SIZE]; + uint8_t appId[U2F_APPID_SIZE]; + uint8_t flags; + uint8_t ctr[4]; + uint8_t chal[U2F_CHAL_SIZE]; } U2F_AUTHENTICATE_SIG_STR; static uint32_t dialog_timeout = 0; -uint32_t next_cid(void) -{ - // extremely unlikely but hey - do { - cid = random32(); - } while (cid == 0 || cid == CID_BROADCAST); - return cid; +uint32_t next_cid(void) { + // extremely unlikely but hey + do { + cid = random32(); + } while (cid == 0 || cid == CID_BROADCAST); + return cid; } // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html#message--and-packet-structure @@ -122,219 +126,212 @@ uint32_t next_cid(void) // the maximum message payload length is 64 - 7 + 128 * (64 - 5) = 7609 bytes. #define U2F_MAXIMUM_PAYLOAD_LENGTH 7609 typedef struct { - uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH]; - uint8_t *buf_ptr; - uint32_t len; - uint8_t seq; - uint8_t cmd; + uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH]; + uint8_t *buf_ptr; + uint32_t len; + uint8_t seq; + uint8_t cmd; } U2F_ReadBuffer; U2F_ReadBuffer *reader; -void u2fhid_read(char tiny, const U2FHID_FRAME *f) -{ - // Always handle init packets directly - if (f->init.cmd == U2FHID_INIT) { - u2fhid_init(f); - if (tiny && reader && f->cid == cid) { - // abort current channel - reader->cmd = 0; - reader->len = 0; - reader->seq = 255; - } - return; - } - - if (tiny) { - // read continue packet - if (reader == 0 || cid != f->cid) { - send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY); - return; - } - - if ((f->type & TYPE_INIT) && reader->seq == 255) { - u2fhid_init_cmd(f); - return; - } - - if (reader->seq != f->cont.seq) { - send_u2fhid_error(f->cid, ERR_INVALID_SEQ); - reader->cmd = 0; - reader->len = 0; - reader->seq = 255; - return; - } - - // check out of bounds - if ((reader->buf_ptr - reader->buf) >= (signed) reader->len - || (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) - return; - reader->seq++; - memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); - reader->buf_ptr += sizeof(f->cont.data); - return; - } - - u2fhid_read_start(f); +void u2fhid_read(char tiny, const U2FHID_FRAME *f) { + // Always handle init packets directly + if (f->init.cmd == U2FHID_INIT) { + u2fhid_init(f); + if (tiny && reader && f->cid == cid) { + // abort current channel + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + } + return; + } + + if (tiny) { + // read continue packet + if (reader == 0 || cid != f->cid) { + send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY); + return; + } + + if ((f->type & TYPE_INIT) && reader->seq == 255) { + u2fhid_init_cmd(f); + return; + } + + if (reader->seq != f->cont.seq) { + send_u2fhid_error(f->cid, ERR_INVALID_SEQ); + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + return; + } + + // check out of bounds + if ((reader->buf_ptr - reader->buf) >= (signed)reader->len || + (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > + (signed)sizeof(reader->buf)) + return; + reader->seq++; + memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); + reader->buf_ptr += sizeof(f->cont.data); + return; + } + + u2fhid_read_start(f); } void u2fhid_init_cmd(const U2FHID_FRAME *f) { - reader->seq = 0; - reader->buf_ptr = reader->buf; - reader->len = MSG_LEN(*f); - reader->cmd = f->type; - memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); - reader->buf_ptr += sizeof(f->init.data); - cid = f->cid; + reader->seq = 0; + reader->buf_ptr = reader->buf; + reader->len = MSG_LEN(*f); + reader->cmd = f->type; + memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); + reader->buf_ptr += sizeof(f->init.data); + cid = f->cid; } void u2fhid_read_start(const U2FHID_FRAME *f) { - U2F_ReadBuffer readbuffer; - memzero(&readbuffer, sizeof(readbuffer)); - - if (!(f->type & TYPE_INIT)) { - return; - } - - // Broadcast is reserved for init - if (f->cid == CID_BROADCAST || f->cid == 0) { - send_u2fhid_error(f->cid, ERR_INVALID_CID); - return; - } - - if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) { - send_u2fhid_error(f->cid, ERR_INVALID_LEN); - return; - } - - reader = &readbuffer; - u2fhid_init_cmd(f); - - usbTiny(1); - for(;;) { - // Do we need to wait for more data - while ((reader->buf_ptr - reader->buf) < (signed)reader->len) { - uint8_t lastseq = reader->seq; - uint8_t lastcmd = reader->cmd; - int counter = U2F_TIMEOUT; - while (reader->seq == lastseq && reader->cmd == lastcmd) { - if (counter-- == 0) { - // timeout - send_u2fhid_error(cid, ERR_MSG_TIMEOUT); - cid = 0; - reader = 0; - usbTiny(0); - layoutHome(); - return; - } - usbPoll(); - } - } - - // We have all the data - switch (reader->cmd) { - case 0: - // message was aborted by init - break; - case U2FHID_PING: - u2fhid_ping(reader->buf, reader->len); - break; - case U2FHID_MSG: - u2fhid_msg((APDU *)reader->buf, reader->len); - break; - case U2FHID_WINK: - u2fhid_wink(reader->buf, reader->len); - break; - default: - send_u2fhid_error(cid, ERR_INVALID_CMD); - break; - } - - // wait for next commmand/ button press - reader->cmd = 0; - reader->seq = 255; - while (dialog_timeout > 0 && reader->cmd == 0) { - dialog_timeout--; - usbPoll(); // may trigger new request - //buttonUpdate(); - if (keepkey_button_down() && - (last_req_state == AUTH || last_req_state == REG)) { - last_req_state++; - // standard requires to remember button press for 10 seconds. - dialog_timeout = 10 * U2F_TIMEOUT; - } - } - - if (reader->cmd == 0) { - last_req_state = INIT; - cid = 0; - reader = 0; - usbTiny(0); - layoutHome(); - return; - } - } + U2F_ReadBuffer readbuffer; + memzero(&readbuffer, sizeof(readbuffer)); + + if (!(f->type & TYPE_INIT)) { + return; + } + + // Broadcast is reserved for init + if (f->cid == CID_BROADCAST || f->cid == 0) { + send_u2fhid_error(f->cid, ERR_INVALID_CID); + return; + } + + if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) { + send_u2fhid_error(f->cid, ERR_INVALID_LEN); + return; + } + + reader = &readbuffer; + u2fhid_init_cmd(f); + + usbTiny(1); + for (;;) { + // Do we need to wait for more data + while ((reader->buf_ptr - reader->buf) < (signed)reader->len) { + uint8_t lastseq = reader->seq; + uint8_t lastcmd = reader->cmd; + int counter = U2F_TIMEOUT; + while (reader->seq == lastseq && reader->cmd == lastcmd) { + if (counter-- == 0) { + // timeout + send_u2fhid_error(cid, ERR_MSG_TIMEOUT); + cid = 0; + reader = 0; + usbTiny(0); + layoutHome(); + return; + } + usbPoll(); + } + } + + // We have all the data + switch (reader->cmd) { + case 0: + // message was aborted by init + break; + case U2FHID_PING: + u2fhid_ping(reader->buf, reader->len); + break; + case U2FHID_MSG: + u2fhid_msg((APDU *)reader->buf, reader->len); + break; + case U2FHID_WINK: + u2fhid_wink(reader->buf, reader->len); + break; + default: + send_u2fhid_error(cid, ERR_INVALID_CMD); + break; + } + + // wait for next commmand/ button press + reader->cmd = 0; + reader->seq = 255; + while (dialog_timeout > 0 && reader->cmd == 0) { + dialog_timeout--; + usbPoll(); // may trigger new request + // buttonUpdate(); + if (keepkey_button_down() && + (last_req_state == AUTH || last_req_state == REG)) { + last_req_state++; + // standard requires to remember button press for 10 seconds. + dialog_timeout = 10 * U2F_TIMEOUT; + } + } + + if (reader->cmd == 0) { + last_req_state = INIT; + cid = 0; + reader = 0; + usbTiny(0); + layoutHome(); + return; + } + } } -void u2fInit(void) { - usb_set_u2f_rx_callback(u2fhid_read); -} +void u2fInit(void) { usb_set_u2f_rx_callback(u2fhid_read); } -void u2fhid_ping(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_ping"); - send_u2fhid_msg(U2FHID_PING, buf, len); +void u2fhid_ping(const uint8_t *buf, uint32_t len) { + debugLog(0, "", "u2fhid_ping"); + send_u2fhid_msg(U2FHID_PING, buf, len); } -void u2fhid_wink(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_wink"); - (void)buf; +void u2fhid_wink(const uint8_t *buf, uint32_t len) { + debugLog(0, "", "u2fhid_wink"); + (void)buf; - if (len > 0) - return send_u2fhid_error(cid, ERR_INVALID_LEN); + if (len > 0) return send_u2fhid_error(cid, ERR_INVALID_LEN); - if (dialog_timeout > 0) - dialog_timeout = U2F_TIMEOUT; + if (dialog_timeout > 0) dialog_timeout = U2F_TIMEOUT; - U2FHID_FRAME f; - memzero(&f, sizeof(f)); - f.cid = cid; - f.init.cmd = U2FHID_WINK; - f.init.bcntl = 0; - queue_u2f_pkt(&f); + U2FHID_FRAME f; + memzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = U2FHID_WINK; + f.init.bcntl = 0; + queue_u2f_pkt(&f); } -void u2fhid_init(const U2FHID_FRAME *in) -{ - const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; - U2FHID_FRAME f; - U2FHID_INIT_RESP resp; - memzero(&resp, sizeof(resp)); - - debugLog(0, "", "u2fhid_init"); - - if (in->cid == 0) { - send_u2fhid_error(in->cid, ERR_INVALID_CID); - return; - } - - memzero(&f, sizeof(f)); - f.cid = in->cid; - f.init.cmd = U2FHID_INIT; - f.init.bcnth = 0; - f.init.bcntl = sizeof(resp); - - memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); - resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; - resp.versionInterface = U2FHID_IF_VERSION; - resp.versionMajor = MAJOR_VERSION; - resp.versionMinor = MINOR_VERSION; - resp.versionBuild = PATCH_VERSION; - resp.capFlags = CAPFLAG_WINK; - memcpy(&f.init.data, &resp, sizeof(resp)); - - queue_u2f_pkt(&f); +void u2fhid_init(const U2FHID_FRAME *in) { + const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; + U2FHID_FRAME f; + U2FHID_INIT_RESP resp; + memzero(&resp, sizeof(resp)); + + debugLog(0, "", "u2fhid_init"); + + if (in->cid == 0) { + send_u2fhid_error(in->cid, ERR_INVALID_CID); + return; + } + + memzero(&f, sizeof(f)); + f.cid = in->cid; + f.init.cmd = U2FHID_INIT; + f.init.bcnth = 0; + f.init.bcntl = sizeof(resp); + + memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); + resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; + resp.versionInterface = U2FHID_IF_VERSION; + resp.versionMajor = MAJOR_VERSION; + resp.versionMinor = MINOR_VERSION; + resp.versionBuild = PATCH_VERSION; + resp.capFlags = CAPFLAG_WINK; + memcpy(&f.init.data, &resp, sizeof(resp)); + + queue_u2f_pkt(&f); } #if 0 @@ -361,231 +358,223 @@ uint8_t *u2f_out_data(void) } #endif -void u2fhid_msg(const APDU *a, uint32_t len) -{ - if ((APDU_LEN(*a) + sizeof(APDU)) > len) { - debugLog(0, "", "BAD APDU LENGTH"); - debugInt(APDU_LEN(*a)); - debugInt(len); - return; - } - - if (a->cla != 0) { - send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED); - return; - } - - switch (a->ins) { - case U2F_REGISTER: - u2f_register(a); - break; - case U2F_AUTHENTICATE: - u2f_authenticate(a); - break; - case U2F_VERSION: - u2f_version(a); - break; - default: - debugLog(0, "", "u2f unknown cmd"); - send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); - } +void u2fhid_msg(const APDU *a, uint32_t len) { + if ((APDU_LEN(*a) + sizeof(APDU)) > len) { + debugLog(0, "", "BAD APDU LENGTH"); + debugInt(APDU_LEN(*a)); + debugInt(len); + return; + } + + if (a->cla != 0) { + send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED); + return; + } + + switch (a->ins) { + case U2F_REGISTER: + u2f_register(a); + break; + case U2F_AUTHENTICATE: + u2f_authenticate(a); + break; + case U2F_VERSION: + u2f_version(a); + break; + default: + debugLog(0, "", "u2f unknown cmd"); + send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); + } } -void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) -{ - if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { - debugLog(0, "", "send_u2fhid_msg failed"); - return; - } - - U2FHID_FRAME f; - uint8_t *p = (uint8_t *)data; - uint32_t l = len; - uint32_t psz; - uint8_t seq = 0; - - // debugLog(0, "", "send_u2fhid_msg"); - - memzero(&f, sizeof(f)); - f.cid = cid; - f.init.cmd = cmd; - f.init.bcnth = len >> 8; - f.init.bcntl = len & 0xff; - - // Init packet - psz = MIN(sizeof(f.init.data), l); - memcpy(f.init.data, p, psz); - queue_u2f_pkt(&f); - l -= psz; - p += psz; - - // Cont packet(s) - for (; l > 0; l -= psz, p += psz) { - // debugLog(0, "", "send_u2fhid_msg con"); - memzero(&f.cont.data, sizeof(f.cont.data)); - f.cont.seq = seq++; - psz = MIN(sizeof(f.cont.data), l); - memcpy(f.cont.data, p, psz); - queue_u2f_pkt(&f); - } - - if (data + len != p) { - debugLog(0, "", "send_u2fhid_msg is bad"); - debugInt(data + len - p); - } +void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, + const uint32_t len) { + if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { + debugLog(0, "", "send_u2fhid_msg failed"); + return; + } + + U2FHID_FRAME f; + uint8_t *p = (uint8_t *)data; + uint32_t l = len; + uint32_t psz; + uint8_t seq = 0; + + // debugLog(0, "", "send_u2fhid_msg"); + + memzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = cmd; + f.init.bcnth = len >> 8; + f.init.bcntl = len & 0xff; + + // Init packet + psz = MIN(sizeof(f.init.data), l); + memcpy(f.init.data, p, psz); + queue_u2f_pkt(&f); + l -= psz; + p += psz; + + // Cont packet(s) + for (; l > 0; l -= psz, p += psz) { + // debugLog(0, "", "send_u2fhid_msg con"); + memzero(&f.cont.data, sizeof(f.cont.data)); + f.cont.seq = seq++; + psz = MIN(sizeof(f.cont.data), l); + memcpy(f.cont.data, p, psz); + queue_u2f_pkt(&f); + } + + if (data + len != p) { + debugLog(0, "", "send_u2fhid_msg is bad"); + debugInt(data + len - p); + } } -void send_u2fhid_error(uint32_t fcid, uint8_t err) -{ - U2FHID_FRAME f; - - memzero(&f, sizeof(f)); - f.cid = fcid; - f.init.cmd = U2FHID_ERROR; - f.init.bcntl = 1; - f.init.data[0] = err; - queue_u2f_pkt(&f); -} - -void u2f_version(const APDU *a) -{ - if (APDU_LEN(*a) != 0) { - debugLog(0, "", "u2f version - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } +void send_u2fhid_error(uint32_t fcid, uint8_t err) { + U2FHID_FRAME f; - // INCLUDES SW_NO_ERROR - static const uint8_t version_response[] = {'U', '2', 'F', '_', - 'V', '2', 0x90, 0x00}; - debugLog(0, "", "u2f version"); - send_u2f_msg(version_response, sizeof(version_response)); + memzero(&f, sizeof(f)); + f.cid = fcid; + f.init.cmd = U2FHID_ERROR; + f.init.bcntl = 1; + f.init.data[0] = err; + queue_u2f_pkt(&f); } -const char *words_from_data(const uint8_t *data, int len) -{ - if (len > 32) - return NULL; - - int mlen = len * 3 / 4; - static char mnemo[24 * 10]; - - int i, j, idx; - char *p = mnemo; - for (i = 0; i < mlen; i++) { - idx = 0; - for (j = 0; j < 11; j++) { - idx <<= 1; - idx += (data[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; - } - strcpy(p, wordlist[idx]); - p += strlen(wordlist[idx]); - *p = (i < mlen - 1) ? ' ' : 0; - p++; - } - - return mnemo; +void u2f_version(const APDU *a) { + if (APDU_LEN(*a) != 0) { + debugLog(0, "", "u2f version - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } + + // INCLUDES SW_NO_ERROR + static const uint8_t version_response[] = {'U', '2', 'F', '_', + 'V', '2', 0x90, 0x00}; + debugLog(0, "", "u2f version"); + send_u2f_msg(version_response, sizeof(version_response)); } -static bool getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname) { - for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { - if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { - *appname = u2f_well_known[i].appname; - return true; - } - } - - // Otherwise use the mnemonic wordlist to invent some human-readable - // identifier of the first 48 bits. - *appname = words_from_data(appid, 6); - return false; +const char *words_from_data(const uint8_t *data, int len) { + if (len > 32) return NULL; + + int mlen = len * 3 / 4; + static char mnemo[24 * 10]; + + int i, j, idx; + char *p = mnemo; + for (i = 0; i < mlen; i++) { + idx = 0; + for (j = 0; j < 11; j++) { + idx <<= 1; + idx += (data[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + strcpy(p, wordlist[idx]); + p += strlen(wordlist[idx]); + *p = (i < mlen - 1) ? ' ' : 0; + p++; + } + + return mnemo; } -static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) -{ - static CONFIDENTIAL HDNode node; - if (!storage_getU2FRoot(&node)) { - layoutHome(); - debugLog(0, "", "ERR: Device not init"); - return 0; - } - if (!address_n || address_n_count == 0) { - return &node; - } - for (size_t i = 0; i < address_n_count; i++) { - if (hdnode_private_ckd(&node, address_n[i]) == 0) { - layoutHome(); - debugLog(0, "", "ERR: Derive private failed"); - return 0; - } - } - return &node; +static bool getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], + const char **appname) { + for (unsigned int i = 0; i < sizeof(u2f_well_known) / sizeof(U2FWellKnown); + i++) { + if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { + *appname = u2f_well_known[i].appname; + return true; + } + } + + // Otherwise use the mnemonic wordlist to invent some human-readable + // identifier of the first 48 bits. + *appname = words_from_data(appid, 6); + return false; } -static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) -{ - uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - - // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' - uint32_t key_path[KEY_PATH_ENTRIES]; - for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) { - // high bit for hardened keys - key_path[i]= 0x80000000 | random32(); - } - - // First half of keyhandle is key_path - memcpy(key_handle, key_path, KEY_PATH_LEN); - - // prepare keypair from /random data - const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - if (!node) - return NULL; - - // For second half of keyhandle - // Signature of app_id and random data - memcpy(&keybase[0], app_id, U2F_APPID_SIZE); - memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - hmac_sha256(node->private_key, sizeof(node->private_key), - keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]); - - // Done! - return node; +static const HDNode *getDerivedNode(uint32_t *address_n, + size_t address_n_count) { + static CONFIDENTIAL HDNode node; + if (!storage_getU2FRoot(&node)) { + layoutHome(); + debugLog(0, "", "ERR: Device not init"); + return 0; + } + if (!address_n || address_n_count == 0) { + return &node; + } + for (size_t i = 0; i < address_n_count; i++) { + if (hdnode_private_ckd(&node, address_n[i]) == 0) { + layoutHome(); + debugLog(0, "", "ERR: Derive private failed"); + return 0; + } + } + return &node; } +static const HDNode *generateKeyHandle(const uint8_t app_id[], + uint8_t key_handle[]) { + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; + + // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' + uint32_t key_path[KEY_PATH_ENTRIES]; + for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) { + // high bit for hardened keys + key_path[i] = 0x80000000 | random32(); + } + + // First half of keyhandle is key_path + memcpy(key_handle, key_path, KEY_PATH_LEN); + + // prepare keypair from /random data + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) return NULL; + + // For second half of keyhandle + // Signature of app_id and random data + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); + hmac_sha256(node->private_key, sizeof(node->private_key), keybase, + sizeof(keybase), &key_handle[KEY_PATH_LEN]); + + // Done! + return node; +} -static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) -{ - uint32_t key_path[KEY_PATH_ENTRIES]; - memcpy(key_path, key_handle, KEY_PATH_LEN); - for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { - // check high bit for hardened keys - if (! (key_path[i] & 0x80000000)) { - return NULL; - } - } - - const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - if (!node) - return NULL; - - uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - memcpy(&keybase[0], app_id, U2F_APPID_SIZE); - memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - - - uint8_t hmac[SHA256_DIGEST_LENGTH]; - hmac_sha256(node->private_key, sizeof(node->private_key), - keybase, sizeof(keybase), hmac); - - if (memcmp_s(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) - return NULL; - - // Done! - return node; +static const HDNode *validateKeyHandle(const uint8_t app_id[], + const uint8_t key_handle[]) { + uint32_t key_path[KEY_PATH_ENTRIES]; + memcpy(key_path, key_handle, KEY_PATH_LEN); + for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { + // check high bit for hardened keys + if (!(key_path[i] & 0x80000000)) { + return NULL; + } + } + + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) return NULL; + + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); + + uint8_t hmac[SHA256_DIGEST_LENGTH]; + hmac_sha256(node->private_key, sizeof(node->private_key), keybase, + sizeof(keybase), hmac); + + if (memcmp_s(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) + return NULL; + + // Done! + return node; } -static void promptRegister(bool request, const U2F_REGISTER_REQ *req) -{ +static void promptRegister(bool request, const U2F_REGISTER_REQ *req) { #if 0 // Users find it confusing when a Ledger and a KeepKey are plugged in // at the same time. To avoid that, we elect not to show a message in @@ -595,258 +584,248 @@ static void promptRegister(bool request, const U2F_REGISTER_REQ *req) "Another U2F device was used to register in this application."); } else { #else - { + { #endif - const char *appname = ""; - bool readable = getReadableAppId(req->appId, &appname); - layoutU2FDialog(request, "U2F Register", - readable - ? "Do you want to register with %s?" - : "Do you want to register with this U2F application?\n\n%s", - appname); - } + const char *appname = ""; + bool readable = getReadableAppId(req->appId, &appname); + layoutU2FDialog( + request, "U2F Register", + readable ? "Do you want to register with %s?" + : "Do you want to register with this U2F application?\n\n%s", + appname); } - -void u2f_register(const APDU *a) -{ - static U2F_REGISTER_REQ last_req; - const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; - - if (!storage_isInitialized()) { - layout_warning_static("Cannot register u2f: not initialized"); - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - delay_ms(3000); - return; - } - - // Validate basic request parameters - debugLog(0, "", "u2f register"); - if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { - debugLog(0, "", "u2f register - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } - - // If this request is different from last request, reset state machine - if (memcmp(&last_req, req, sizeof(last_req)) != 0) { - memcpy(&last_req, req, sizeof(last_req)); - last_req_state = INIT; - } - - // First Time request, return not present and display request dialog - if (last_req_state == INIT) { - // error: testof-user-presence is required - //buttonUpdate(); - promptRegister(true, req); - last_req_state = REG; - } - - // Still awaiting Keypress - if (last_req_state == REG) { - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; - return; - } - - // Buttons said yes - if (last_req_state == REG_PASS) { - uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; - U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; - memzero(data, sizeof(data)); - - resp->registerId = U2F_REGISTER_ID; - resp->keyHandleLen = KEY_HANDLE_LEN; - // Generate keypair for this appId - const HDNode *node = - generateKeyHandle(req->appId, (uint8_t*)&resp->keyHandleCertSig); - - if (!node) { - debugLog(0, "", "getDerivedNode Fail"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } - - ecdsa_get_public_key65(node->curve->params, node->private_key, - (uint8_t *)&resp->pubKey); - - memcpy(resp->keyHandleCertSig + resp->keyHandleLen, - U2F_ATT_CERT, sizeof(U2F_ATT_CERT)); - - uint8_t sig[64]; - U2F_REGISTER_SIG_STR sig_base; - sig_base.reserved = 0; - memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); - memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); - memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); - if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } - - // Where to write the signature in the response - uint8_t *resp_sig = resp->keyHandleCertSig + - resp->keyHandleLen + sizeof(U2F_ATT_CERT); - // Convert to der for the response - const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); - - // Append success bytes - memcpy(resp->keyHandleCertSig + resp->keyHandleLen + - sizeof(U2F_ATT_CERT) + sig_len, - "\x90\x00", 2); - - int l = 1 /* registerId */ + U2F_PUBKEY_LEN + - 1 /* keyhandleLen */ + resp->keyHandleLen + - sizeof(U2F_ATT_CERT) + sig_len + 2; - - last_req_state = INIT; - dialog_timeout = 0; - send_u2f_msg(data, l); - - promptRegister(false, req); - return; - } - - // Didnt expect to get here - dialog_timeout = 0; } -static void promptAuthenticate(bool request, const U2F_AUTHENTICATE_REQ *req) -{ - const char *appname = ""; - bool readable = getReadableAppId(req->appId, &appname); - layoutU2FDialog(request, - "U2F Authenticate", - readable - ? "Log in to %s?" - : "Do you want to log in?\n\n%s", - appname); +void u2f_register(const APDU *a) { + static U2F_REGISTER_REQ last_req; + const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; + + if (!storage_isInitialized()) { + layout_warning_static("Cannot register u2f: not initialized"); + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + delay_ms(3000); + return; + } + + // Validate basic request parameters + debugLog(0, "", "u2f register"); + if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { + debugLog(0, "", "u2f register - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } + + // If this request is different from last request, reset state machine + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } + + // First Time request, return not present and display request dialog + if (last_req_state == INIT) { + // error: testof-user-presence is required + // buttonUpdate(); + promptRegister(true, req); + last_req_state = REG; + } + + // Still awaiting Keypress + if (last_req_state == REG) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } + + // Buttons said yes + if (last_req_state == REG_PASS) { + uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; + U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; + memzero(data, sizeof(data)); + + resp->registerId = U2F_REGISTER_ID; + resp->keyHandleLen = KEY_HANDLE_LEN; + // Generate keypair for this appId + const HDNode *node = + generateKeyHandle(req->appId, (uint8_t *)&resp->keyHandleCertSig); + + if (!node) { + debugLog(0, "", "getDerivedNode Fail"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + ecdsa_get_public_key65(node->curve->params, node->private_key, + (uint8_t *)&resp->pubKey); + + memcpy(resp->keyHandleCertSig + resp->keyHandleLen, U2F_ATT_CERT, + sizeof(U2F_ATT_CERT)); + + uint8_t sig[64]; + U2F_REGISTER_SIG_STR sig_base; + sig_base.reserved = 0; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); + memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); + if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, + (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, + NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + // Where to write the signature in the response + uint8_t *resp_sig = + resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT); + // Convert to der for the response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); + + // Append success bytes + memcpy(resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + + sig_len, + "\x90\x00", 2); + + int l = 1 /* registerId */ + U2F_PUBKEY_LEN + 1 /* keyhandleLen */ + + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2; + + last_req_state = INIT; + dialog_timeout = 0; + send_u2f_msg(data, l); + + promptRegister(false, req); + return; + } + + // Didnt expect to get here + dialog_timeout = 0; } +static void promptAuthenticate(bool request, const U2F_AUTHENTICATE_REQ *req) { + const char *appname = ""; + bool readable = getReadableAppId(req->appId, &appname); + layoutU2FDialog(request, "U2F Authenticate", + readable ? "Log in to %s?" : "Do you want to log in?\n\n%s", + appname); +} -void u2f_authenticate(const APDU *a) -{ - const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; - static U2F_AUTHENTICATE_REQ last_req; - - if (!storage_isInitialized()) { - layout_warning_static("Cannot authenticate u2f: not initialized"); - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - delay_ms(3000); - return; - } - - if (APDU_LEN(*a) < 64) { /// FIXME: decent value - debugLog(0, "", "u2f authenticate - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } - - if (req->keyHandleLen != KEY_HANDLE_LEN) { - debugLog(0, "", "u2f auth - bad keyhandle len"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } - - const HDNode *node = - validateKeyHandle(req->appId, req->keyHandle); - - if (!node) { - debugLog(0, "", "u2f auth - bad keyhandle len"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } - - if (a->p1 == U2F_AUTH_CHECK_ONLY) { - debugLog(0, "", "u2f authenticate check"); - // This is a success for a good keyhandle - // A failed check would have happened earlier - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - return; - } - - if (a->p1 != U2F_AUTH_ENFORCE) { - debugLog(0, "", "u2f authenticate unknown"); - // error:bad key handle - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } - - debugLog(0, "", "u2f authenticate enforce"); - - if (memcmp(&last_req, req, sizeof(last_req)) != 0) { - memcpy(&last_req, req, sizeof(last_req)); - last_req_state = INIT; - } - - if (last_req_state == INIT) { - // error: testof-user-presence is required - //buttonUpdate(); // Clear button state - promptAuthenticate(true, req); - last_req_state = AUTH; - } - - // Awaiting Keypress - if (last_req_state == AUTH) { - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; - return; - } - - // Buttons said yes - if (last_req_state == AUTH_PASS) { - uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; - U2F_AUTHENTICATE_RESP *resp = - (U2F_AUTHENTICATE_RESP *)&buf; - - const uint32_t ctr = storage_nextU2FCounter(); - resp->flags = U2F_AUTH_FLAG_TUP; - resp->ctr[0] = ctr >> 24 & 0xff; - resp->ctr[1] = ctr >> 16 & 0xff; - resp->ctr[2] = ctr >> 8 & 0xff; - resp->ctr[3] = ctr & 0xff; - - // Build and sign response - U2F_AUTHENTICATE_SIG_STR sig_base; - uint8_t sig[64]; - memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); - sig_base.flags = resp->flags; - memcpy(sig_base.ctr, resp->ctr, 4); - memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } - - // Copy DER encoded signature into response - const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); - - // Append OK - memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - - U2F_MAX_EC_SIG_SIZE + sig_len, - "\x90\x00", 2); - last_req_state = INIT; - dialog_timeout = 0; - send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - - U2F_MAX_EC_SIG_SIZE + sig_len + - 2); - - promptAuthenticate(false, req); - } +void u2f_authenticate(const APDU *a) { + const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; + static U2F_AUTHENTICATE_REQ last_req; + + if (!storage_isInitialized()) { + layout_warning_static("Cannot authenticate u2f: not initialized"); + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + delay_ms(3000); + return; + } + + if (APDU_LEN(*a) < 64) { /// FIXME: decent value + debugLog(0, "", "u2f authenticate - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } + + if (req->keyHandleLen != KEY_HANDLE_LEN) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + const HDNode *node = validateKeyHandle(req->appId, req->keyHandle); + + if (!node) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + if (a->p1 == U2F_AUTH_CHECK_ONLY) { + debugLog(0, "", "u2f authenticate check"); + // This is a success for a good keyhandle + // A failed check would have happened earlier + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } + + if (a->p1 != U2F_AUTH_ENFORCE) { + debugLog(0, "", "u2f authenticate unknown"); + // error:bad key handle + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + debugLog(0, "", "u2f authenticate enforce"); + + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } + + if (last_req_state == INIT) { + // error: testof-user-presence is required + // buttonUpdate(); // Clear button state + promptAuthenticate(true, req); + last_req_state = AUTH; + } + + // Awaiting Keypress + if (last_req_state == AUTH) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } + + // Buttons said yes + if (last_req_state == AUTH_PASS) { + uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; + U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf; + + const uint32_t ctr = storage_nextU2FCounter(); + resp->flags = U2F_AUTH_FLAG_TUP; + resp->ctr[0] = ctr >> 24 & 0xff; + resp->ctr[1] = ctr >> 16 & 0xff; + resp->ctr[2] = ctr >> 8 & 0xff; + resp->ctr[3] = ctr & 0xff; + + // Build and sign response + U2F_AUTHENTICATE_SIG_STR sig_base; + uint8_t sig[64]; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + sig_base.flags = resp->flags; + memcpy(sig_base.ctr, resp->ctr, 4); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, + (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, + NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + // Copy DER encoded signature into response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); + + // Append OK + memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len, + "\x90\x00", 2); + last_req_state = INIT; + dialog_timeout = 0; + send_u2f_msg( + buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); + + promptAuthenticate(false, req); + } } -void send_u2f_error(const uint16_t err) -{ - uint8_t data[2]; - data[0] = err >> 8 & 0xFF; - data[1] = err & 0xFF; - send_u2f_msg(data, 2); +void send_u2f_error(const uint16_t err) { + uint8_t data[2]; + data[0] = err >> 8 & 0xFF; + data[1] = err & 0xFF; + send_u2f_msg(data, 2); } -void send_u2f_msg(const uint8_t *data, const uint32_t len) -{ - send_u2fhid_msg(U2FHID_MSG, data, len); +void send_u2f_msg(const uint8_t *data, const uint32_t len) { + send_u2fhid_msg(U2FHID_MSG, data, len); } diff --git a/lib/firmware/u2f_knownapps.h b/lib/firmware/u2f_knownapps.h index dc026581a..1186c21c6 100644 --- a/lib/firmware/u2f_knownapps.h +++ b/lib/firmware/u2f_knownapps.h @@ -25,157 +25,168 @@ #include typedef struct { - const uint8_t appid[U2F_APPID_SIZE]; - const char *appname; + const uint8_t appid[U2F_APPID_SIZE]; + const char *appname; } U2FWellKnown; static const U2FWellKnown u2f_well_known[] = { - { - // shapeshift.com - { 0x9F, 0x8A, 0xC5, 0xD5, 0x07, 0xD2, 0x0E, 0x96, 0xDF, 0xF1, 0x3C, 0xFB, 0x20, 0xC2, 0x42, 0xB8, 0xD4, 0xA4, 0xCC, 0x61, 0x5E, 0x37, 0x0F, 0xF6, 0x8E, 0xC7, 0x2E, 0x54, 0x61, 0x6D, 0xFB, 0x51 }, - "ShapeShift", - #define U2F_SHAPESHIFT_COM (&u2f_well_known[0]) - }, - { - // shapeshift.io - { 0x6D, 0x89, 0xD6, 0x67, 0x6A, 0xC1, 0xE1, 0xEF, 0x90, 0x8F, 0xCA, 0x25, 0xEB, 0x68, 0xBF, 0x5C, 0x3F, 0x18, 0x8B, 0xFF, 0x46, 0x0C, 0x86, 0xAC, 0x7D, 0xDA, 0x5E, 0x91, 0xCB, 0x3A, 0xB5, 0x52 }, - "ShapeShift", - #define U2F_SHAPESHIFT_IO (&u2f_well_known[1]) - }, - { - // shapeshift.com staging - { 0x7D, 0x0C, 0xBA, 0x5C, 0x58, 0xE1, 0x4A, 0x6B, 0x41, 0xFA, 0xFB, 0x85, 0xD1, 0x4A, 0x52, 0x21, 0xF2, 0xE6, 0x4D, 0x64, 0x19, 0x15, 0x7F, 0xD0, 0xBF, 0xC0, 0xFB, 0x57, 0x7A, 0x98, 0xD5, 0x4E }, - "ShapeShift (staging)", - #define U2F_SHAPESHIFT_COM_STG (&u2f_well_known[2]) - }, - { - // shapeshift.io staging - { 0xC7, 0x6E, 0xBA, 0x1A, 0xF1, 0x0A, 0x48, 0xA4, 0xFD, 0xA9, 0x63, 0xBB, 0x5B, 0x9F, 0x17, 0x42, 0xE5, 0x78, 0x4F, 0x75, 0xDF, 0x3E, 0xDC, 0xED, 0x23, 0x73, 0xF0, 0x16, 0x20, 0x0F, 0xF8, 0x24 }, - "ShapeShift (staging)", - #define U2F_SHAPESHIFT_IO_STG (&u2f_well_known[3]) - }, - { - // shapeshift.com dev - { 0x19, 0xB8, 0xF9, 0x8C, 0xAD, 0x0C, 0xED, 0x18, 0x9F, 0x2F, 0x0F, 0x37, 0xC7, 0x14, 0xAD, 0xF8, 0x61, 0xDE, 0xA1, 0x94, 0xB5, 0xF9, 0x4D, 0x5A, 0xA6, 0xFF, 0xA7, 0xDC, 0xC3, 0x82, 0xA3, 0x0F }, - "ShapeShift (dev)", - #define U2F_SHAPESHIFT_COM_DEV (&u2f_well_known[4]) - }, - { - // shapeshift.io dev - { 0xC7, 0x44, 0xFD, 0x93, 0x8B, 0xDE, 0x8E, 0x5B, 0xFD, 0x26, 0xFF, 0x22, 0xE3, 0xB3, 0xF0, 0x40, 0xE2, 0xC3, 0x33, 0x45, 0xD9, 0x3E, 0xC2, 0x7A, 0xD8, 0x7E, 0x5B, 0x3C, 0x33, 0x25, 0xA9, 0x97 }, - "ShapeShift (dev)" - #define U2F_SHAPESHIFT_IO_DEV (&u2f_well_known[5]) - }, - { - // U2F: https://bitbucket.org - { 0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, 0x11, 0x35, 0xe4, 0x1f, 0xde, 0xdd, 0x4a, 0x84, 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, 0x32, 0xa9, 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e }, - "Bitbucket" - }, - { - // U2F: https://www.bitfinex.com - { 0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, 0xfe, 0xbb, 0x30, 0xe7, 0x32, 0x69, 0xec, 0xa5, 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, 0x0b, 0xf7, 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63 }, - "Bitfinex" - }, - { - // U2F: https://vault.bitwarden.com/app-id.json - { 0xa3, 0x4d, 0x30, 0x9f, 0xfa, 0x28, 0xc1, 0x24, 0x14, 0xb8, 0xba, 0x6c, 0x07, 0xee, 0x1e, 0xfa, 0xe1, 0xa8, 0x5e, 0x8a, 0x04, 0x61, 0x48, 0x59, 0xa6, 0x7c, 0x04, 0x93, 0xb6, 0x95, 0x61, 0x90 }, - "Bitwarden" - }, - { - // U2F: https://www.dashlane.com - { 0x68, 0x20, 0x19, 0x15, 0xd7, 0x4c, 0xb4, 0x2a, 0xf5, 0xb3, 0xcc, 0x5c, 0x95, 0xb9, 0x55, 0x3e, 0x3e, 0x3a, 0x83, 0xb4, 0xd2, 0xa9, 0x3b, 0x45, 0xfb, 0xad, 0xaa, 0x84, 0x69, 0xff, 0x8e, 0x6e }, - "Dashlane" - }, - { - // U2F: https://www.dropbox.com/u2f-app-id.json - { 0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, 0x2e, 0x7a, 0x50, 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, 0xc0, 0xcd, 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81 }, - "Dropbox" - }, - { - // WebAuthn: www.dropbox.com - { 0x82, 0xf4, 0xa8, 0xc9, 0x5f, 0xec, 0x94, 0xb2, 0x6b, 0xaf, 0x9e, 0x37, 0x25, 0x0e, 0x95, 0x63, 0xd9, 0xa3, 0x66, 0xc7, 0xbe, 0x26, 0x1c, 0xa4, 0xdd, 0x01, 0x01, 0xf4, 0xd5, 0xef, 0xcb, 0x83 }, - "Dropbox" - }, - { - // U2F: https://api-9dcf9b83.duosecurity.com - { 0xf3, 0xe2, 0x04, 0x2f, 0x94, 0x60, 0x7d, 0xa0, 0xa9, 0xc1, 0xf3, 0xb9, 0x5e, 0x0d, 0x2f, 0x2b, 0xb2, 0xe0, 0x69, 0xc5, 0xbb, 0x4f, 0xa7, 0x64, 0xaf, 0xfa, 0x64, 0x7d, 0x84, 0x7b, 0x7e, 0xd6 }, - "Duo" - }, - { - // U2F: https://www.fastmail.com - { 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, - "FastMail" - }, - { - // U2F: https://id.fedoraproject.org/u2f-origins.json - { 0x9d, 0x61, 0x44, 0x2f, 0x5c, 0xe1, 0x33, 0xbd, 0x46, 0x54, 0x4f, 0xc4, 0x2f, 0x0a, 0x6d, 0x54, 0xc0, 0xde, 0xb8, 0x88, 0x40, 0xca, 0xc2, 0xb6, 0xae, 0xfa, 0x65, 0x14, 0xf8, 0x93, 0x49, 0xe9 }, - "Fedora" - }, - { - // U2F: https://account.gandi.net/api/u2f/trusted_facets.json - { 0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, 0x12, 0x89, 0x50, 0x11, 0x39, 0x89, 0xfc, 0x45, 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, 0x75, 0x60, 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96 }, - "Gandi" - }, - { - // U2F: https://github.com/u2f/trusted_facets - { 0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 }, - "GitHub" - }, - { - // U2F: https://gitlab.com - { 0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, - "GitLab" - }, - { - // U2F: https://www.gstatic.com/securitykey/origins.json - { 0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, 0xe1, 0x51, 0xed, 0x8d, 0x4d, 0x3c, 0x76, 0x7a, 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, 0x79, 0x4e, 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd }, - "Google" - }, - { - // U2F: https://keepersecurity.com - { 0x53, 0xa1, 0x5b, 0xa4, 0x2a, 0x7c, 0x03, 0x25, 0xb8, 0xdb, 0xee, 0x28, 0x96, 0x34, 0xa4, 0x8f, 0x58, 0xae, 0xa3, 0x24, 0x66, 0x45, 0xd5, 0xff, 0x41, 0x8f, 0x9b, 0xb8, 0x81, 0x98, 0x85, 0xa9 }, - "Keeper" - }, - { - // U2F: https://lastpass.com - { 0xd7, 0x55, 0xc5, 0x27, 0xa8, 0x6b, 0xf7, 0x84, 0x45, 0xc2, 0x82, 0xe7, 0x13, 0xdc, 0xb8, 0x6d, 0x46, 0xff, 0x8b, 0x3c, 0xaf, 0xcf, 0xb7, 0x3b, 0x2e, 0x8c, 0xbe, 0x6c, 0x08, 0x84, 0xcb, 0x24 }, - "LastPass" - }, - { - // U2F: https://slushpool.com/static/security/u2f.json - { 0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, 0x66, 0x84, 0x93, 0xcb, 0x36, 0xcd, 0xcc, 0x4f, 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, 0x8b, 0x73, 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97 }, - "Slush Pool" - }, - { - // U2F: https://dashboard.stripe.com - { 0x2a, 0xc6, 0xad, 0x09, 0xa6, 0xd0, 0x77, 0x2c, 0x44, 0xda, 0x73, 0xa6, 0x07, 0x2f, 0x9d, 0x24, 0x0f, 0xc6, 0x85, 0x4a, 0x70, 0xd7, 0x9c, 0x10, 0x24, 0xff, 0x7c, 0x75, 0x59, 0x59, 0x32, 0x92 }, - "Stripe" - }, - { - // U2F: https://u2f.bin.coffee - { 0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, 0xb4, 0xc2, 0x89, 0xdc, 0x16, 0x74, 0x6b, 0xcc, 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, 0xe1, 0x32, 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68 }, - "u2f.bin.coffee" - }, - { - // WebAuthn: webauthn.bin.coffee - { 0xa6, 0x42, 0xd2, 0x1b, 0x7c, 0x6d, 0x55, 0xe1, 0xce, 0x23, 0xc5, 0x39, 0x98, 0x28, 0xd2, 0xc7, 0x49, 0xbf, 0x6a, 0x6e, 0xf2, 0xfe, 0x03, 0xcc, 0x9e, 0x10, 0xcd, 0xf4, 0xed, 0x53, 0x08, 0x8b }, - "webauthn.bin.coffee" - }, - { - // WebAuthn: webauthn.io - { 0x74, 0xa6, 0xea, 0x92, 0x13, 0xc9, 0x9c, 0x2f, 0x74, 0xb2, 0x24, 0x92, 0xb3, 0x20, 0xcf, 0x40, 0x26, 0x2a, 0x94, 0xc1, 0xa9, 0x50, 0xa0, 0x39, 0x7f, 0x29, 0x25, 0x0b, 0x60, 0x84, 0x1e, 0xf0 }, - "WebAuthn.io" - }, - { - // WebAuthn: webauthn.me - { 0xf9, 0x5b, 0xc7, 0x38, 0x28, 0xee, 0x21, 0x0f, 0x9f, 0xd3, 0xbb, 0xe7, 0x2d, 0x97, 0x90, 0x80, 0x13, 0xb0, 0xa3, 0x75, 0x9e, 0x9a, 0xea, 0x3d, 0x0a, 0xe3, 0x18, 0x76, 0x6c, 0xd2, 0xe1, 0xad }, - "WebAuthn.me" - }, - { - // WebAuthn: demo.yubico.com - { 0xc4, 0x6c, 0xef, 0x82, 0xad, 0x1b, 0x54, 0x64, 0x77, 0x59, 0x1d, 0x00, 0x8b, 0x08, 0x75, 0x9e, 0xc3, 0xe6, 0xd2, 0xec, 0xb4, 0xf3, 0x94, 0x74, 0xbf, 0xea, 0x69, 0x69, 0x92, 0x5d, 0x03, 0xb7 }, - "demo.yubico.com" - }, + { + // shapeshift.com + {0x9F, 0x8A, 0xC5, 0xD5, 0x07, 0xD2, 0x0E, 0x96, 0xDF, 0xF1, 0x3C, + 0xFB, 0x20, 0xC2, 0x42, 0xB8, 0xD4, 0xA4, 0xCC, 0x61, 0x5E, 0x37, + 0x0F, 0xF6, 0x8E, 0xC7, 0x2E, 0x54, 0x61, 0x6D, 0xFB, 0x51}, + "ShapeShift", +#define U2F_SHAPESHIFT_COM (&u2f_well_known[0]) + }, + { + // shapeshift.io + {0x6D, 0x89, 0xD6, 0x67, 0x6A, 0xC1, 0xE1, 0xEF, 0x90, 0x8F, 0xCA, + 0x25, 0xEB, 0x68, 0xBF, 0x5C, 0x3F, 0x18, 0x8B, 0xFF, 0x46, 0x0C, + 0x86, 0xAC, 0x7D, 0xDA, 0x5E, 0x91, 0xCB, 0x3A, 0xB5, 0x52}, + "ShapeShift", +#define U2F_SHAPESHIFT_IO (&u2f_well_known[1]) + }, + { + // shapeshift.com staging + {0x7D, 0x0C, 0xBA, 0x5C, 0x58, 0xE1, 0x4A, 0x6B, 0x41, 0xFA, 0xFB, + 0x85, 0xD1, 0x4A, 0x52, 0x21, 0xF2, 0xE6, 0x4D, 0x64, 0x19, 0x15, + 0x7F, 0xD0, 0xBF, 0xC0, 0xFB, 0x57, 0x7A, 0x98, 0xD5, 0x4E}, + "ShapeShift (staging)", +#define U2F_SHAPESHIFT_COM_STG (&u2f_well_known[2]) + }, + { + // shapeshift.io staging + {0xC7, 0x6E, 0xBA, 0x1A, 0xF1, 0x0A, 0x48, 0xA4, 0xFD, 0xA9, 0x63, + 0xBB, 0x5B, 0x9F, 0x17, 0x42, 0xE5, 0x78, 0x4F, 0x75, 0xDF, 0x3E, + 0xDC, 0xED, 0x23, 0x73, 0xF0, 0x16, 0x20, 0x0F, 0xF8, 0x24}, + "ShapeShift (staging)", +#define U2F_SHAPESHIFT_IO_STG (&u2f_well_known[3]) + }, + { + // shapeshift.com dev + {0x19, 0xB8, 0xF9, 0x8C, 0xAD, 0x0C, 0xED, 0x18, 0x9F, 0x2F, 0x0F, + 0x37, 0xC7, 0x14, 0xAD, 0xF8, 0x61, 0xDE, 0xA1, 0x94, 0xB5, 0xF9, + 0x4D, 0x5A, 0xA6, 0xFF, 0xA7, 0xDC, 0xC3, 0x82, 0xA3, 0x0F}, + "ShapeShift (dev)", +#define U2F_SHAPESHIFT_COM_DEV (&u2f_well_known[4]) + }, + {// shapeshift.io dev + {0xC7, 0x44, 0xFD, 0x93, 0x8B, 0xDE, 0x8E, 0x5B, 0xFD, 0x26, 0xFF, + 0x22, 0xE3, 0xB3, 0xF0, 0x40, 0xE2, 0xC3, 0x33, 0x45, 0xD9, 0x3E, + 0xC2, 0x7A, 0xD8, 0x7E, 0x5B, 0x3C, 0x33, 0x25, 0xA9, 0x97}, + "ShapeShift (dev)" +#define U2F_SHAPESHIFT_IO_DEV (&u2f_well_known[5]) + }, + {// U2F: https://bitbucket.org + {0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, 0x11, 0x35, 0xe4, + 0x1f, 0xde, 0xdd, 0x4a, 0x84, 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, + 0x32, 0xa9, 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e}, + "Bitbucket"}, + {// U2F: https://www.bitfinex.com + {0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, 0xfe, 0xbb, 0x30, + 0xe7, 0x32, 0x69, 0xec, 0xa5, 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, + 0x0b, 0xf7, 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63}, + "Bitfinex"}, + {// U2F: https://vault.bitwarden.com/app-id.json + {0xa3, 0x4d, 0x30, 0x9f, 0xfa, 0x28, 0xc1, 0x24, 0x14, 0xb8, 0xba, + 0x6c, 0x07, 0xee, 0x1e, 0xfa, 0xe1, 0xa8, 0x5e, 0x8a, 0x04, 0x61, + 0x48, 0x59, 0xa6, 0x7c, 0x04, 0x93, 0xb6, 0x95, 0x61, 0x90}, + "Bitwarden"}, + {// U2F: https://www.dashlane.com + {0x68, 0x20, 0x19, 0x15, 0xd7, 0x4c, 0xb4, 0x2a, 0xf5, 0xb3, 0xcc, + 0x5c, 0x95, 0xb9, 0x55, 0x3e, 0x3e, 0x3a, 0x83, 0xb4, 0xd2, 0xa9, + 0x3b, 0x45, 0xfb, 0xad, 0xaa, 0x84, 0x69, 0xff, 0x8e, 0x6e}, + "Dashlane"}, + {// U2F: https://www.dropbox.com/u2f-app-id.json + {0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, 0x2e, 0x7a, 0x50, + 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, + 0xc0, 0xcd, 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81}, + "Dropbox"}, + {// WebAuthn: www.dropbox.com + {0x82, 0xf4, 0xa8, 0xc9, 0x5f, 0xec, 0x94, 0xb2, 0x6b, 0xaf, 0x9e, + 0x37, 0x25, 0x0e, 0x95, 0x63, 0xd9, 0xa3, 0x66, 0xc7, 0xbe, 0x26, + 0x1c, 0xa4, 0xdd, 0x01, 0x01, 0xf4, 0xd5, 0xef, 0xcb, 0x83}, + "Dropbox"}, + {// U2F: https://api-9dcf9b83.duosecurity.com + {0xf3, 0xe2, 0x04, 0x2f, 0x94, 0x60, 0x7d, 0xa0, 0xa9, 0xc1, 0xf3, + 0xb9, 0x5e, 0x0d, 0x2f, 0x2b, 0xb2, 0xe0, 0x69, 0xc5, 0xbb, 0x4f, + 0xa7, 0x64, 0xaf, 0xfa, 0x64, 0x7d, 0x84, 0x7b, 0x7e, 0xd6}, + "Duo"}, + {// U2F: https://www.fastmail.com + {0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, 0x30, 0x79, 0xeb, + 0x71, 0x01, 0x97, 0x84, 0x8c, 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, + 0xd0, 0x29, 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84}, + "FastMail"}, + {// U2F: https://id.fedoraproject.org/u2f-origins.json + {0x9d, 0x61, 0x44, 0x2f, 0x5c, 0xe1, 0x33, 0xbd, 0x46, 0x54, 0x4f, + 0xc4, 0x2f, 0x0a, 0x6d, 0x54, 0xc0, 0xde, 0xb8, 0x88, 0x40, 0xca, + 0xc2, 0xb6, 0xae, 0xfa, 0x65, 0x14, 0xf8, 0x93, 0x49, 0xe9}, + "Fedora"}, + {// U2F: https://account.gandi.net/api/u2f/trusted_facets.json + {0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, 0x12, 0x89, 0x50, + 0x11, 0x39, 0x89, 0xfc, 0x45, 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, + 0x75, 0x60, 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96}, + "Gandi"}, + {// U2F: https://github.com/u2f/trusted_facets + {0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, 0xf4, 0x7c, 0x15, + 0x55, 0x6c, 0x91, 0x79, 0x88, 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, + 0xf7, 0x0a, 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75}, + "GitHub"}, + {// U2F: https://gitlab.com + {0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, 0x72, 0x84, 0x0d, + 0x2e, 0x59, 0x09, 0xf7, 0x2b, 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, + 0x62, 0x4f, 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04}, + "GitLab"}, + {// U2F: https://www.gstatic.com/securitykey/origins.json + {0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, 0xe1, 0x51, 0xed, + 0x8d, 0x4d, 0x3c, 0x76, 0x7a, 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, + 0x79, 0x4e, 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd}, + "Google"}, + {// U2F: https://keepersecurity.com + {0x53, 0xa1, 0x5b, 0xa4, 0x2a, 0x7c, 0x03, 0x25, 0xb8, 0xdb, 0xee, + 0x28, 0x96, 0x34, 0xa4, 0x8f, 0x58, 0xae, 0xa3, 0x24, 0x66, 0x45, + 0xd5, 0xff, 0x41, 0x8f, 0x9b, 0xb8, 0x81, 0x98, 0x85, 0xa9}, + "Keeper"}, + {// U2F: https://lastpass.com + {0xd7, 0x55, 0xc5, 0x27, 0xa8, 0x6b, 0xf7, 0x84, 0x45, 0xc2, 0x82, + 0xe7, 0x13, 0xdc, 0xb8, 0x6d, 0x46, 0xff, 0x8b, 0x3c, 0xaf, 0xcf, + 0xb7, 0x3b, 0x2e, 0x8c, 0xbe, 0x6c, 0x08, 0x84, 0xcb, 0x24}, + "LastPass"}, + {// U2F: https://slushpool.com/static/security/u2f.json + {0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, 0x66, 0x84, 0x93, + 0xcb, 0x36, 0xcd, 0xcc, 0x4f, 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, + 0x8b, 0x73, 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97}, + "Slush Pool"}, + {// U2F: https://dashboard.stripe.com + {0x2a, 0xc6, 0xad, 0x09, 0xa6, 0xd0, 0x77, 0x2c, 0x44, 0xda, 0x73, + 0xa6, 0x07, 0x2f, 0x9d, 0x24, 0x0f, 0xc6, 0x85, 0x4a, 0x70, 0xd7, + 0x9c, 0x10, 0x24, 0xff, 0x7c, 0x75, 0x59, 0x59, 0x32, 0x92}, + "Stripe"}, + {// U2F: https://u2f.bin.coffee + {0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, 0xb4, 0xc2, 0x89, + 0xdc, 0x16, 0x74, 0x6b, 0xcc, 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, + 0xe1, 0x32, 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68}, + "u2f.bin.coffee"}, + {// WebAuthn: webauthn.bin.coffee + {0xa6, 0x42, 0xd2, 0x1b, 0x7c, 0x6d, 0x55, 0xe1, 0xce, 0x23, 0xc5, + 0x39, 0x98, 0x28, 0xd2, 0xc7, 0x49, 0xbf, 0x6a, 0x6e, 0xf2, 0xfe, + 0x03, 0xcc, 0x9e, 0x10, 0xcd, 0xf4, 0xed, 0x53, 0x08, 0x8b}, + "webauthn.bin.coffee"}, + {// WebAuthn: webauthn.io + {0x74, 0xa6, 0xea, 0x92, 0x13, 0xc9, 0x9c, 0x2f, 0x74, 0xb2, 0x24, + 0x92, 0xb3, 0x20, 0xcf, 0x40, 0x26, 0x2a, 0x94, 0xc1, 0xa9, 0x50, + 0xa0, 0x39, 0x7f, 0x29, 0x25, 0x0b, 0x60, 0x84, 0x1e, 0xf0}, + "WebAuthn.io"}, + {// WebAuthn: webauthn.me + {0xf9, 0x5b, 0xc7, 0x38, 0x28, 0xee, 0x21, 0x0f, 0x9f, 0xd3, 0xbb, + 0xe7, 0x2d, 0x97, 0x90, 0x80, 0x13, 0xb0, 0xa3, 0x75, 0x9e, 0x9a, + 0xea, 0x3d, 0x0a, 0xe3, 0x18, 0x76, 0x6c, 0xd2, 0xe1, 0xad}, + "WebAuthn.me"}, + {// WebAuthn: demo.yubico.com + {0xc4, 0x6c, 0xef, 0x82, 0xad, 0x1b, 0x54, 0x64, 0x77, 0x59, 0x1d, + 0x00, 0x8b, 0x08, 0x75, 0x9e, 0xc3, 0xe6, 0xd2, 0xec, 0xb4, 0xf3, + 0x94, 0x74, 0xbf, 0xea, 0x69, 0x69, 0x92, 0x5d, 0x03, 0xb7}, + "demo.yubico.com"}, }; -#endif // U2F_KNOWNAPPS_INCLUDED +#endif // U2F_KNOWNAPPS_INCLUDED diff --git a/lib/firmware/variant/keepkey/resources.c b/lib/firmware/variant/keepkey/resources.c index 5d8d37e31..c8c73c87e 100644 --- a/lib/firmware/variant/keepkey/resources.c +++ b/lib/firmware/variant/keepkey/resources.c @@ -25,4 +25,3 @@ #include #include - diff --git a/lib/rand/rng.c b/lib/rand/rng.c index 9ee7b4672..57c8c75b9 100644 --- a/lib/rand/rng.c +++ b/lib/rand/rng.c @@ -17,96 +17,86 @@ * along with this library. If not, see . */ - #include "keepkey/rand/rng.h" #include "trezor/crypto/rand.h" #ifndef EMULATOR -# include -# include -# include +#include +#include +#include #endif -void reset_rng(void) -{ +void reset_rng(void) { #ifndef EMULATOR - /* disable RNG */ - RNG_CR &= ~(RNG_CR_IE | RNG_CR_RNGEN); - /* reset Seed/Clock/ error status */ - RNG_SR &= ~(RNG_SR_SEIS | RNG_SR_CEIS); - /* reenable RNG */ - RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; - /* this delay is required before rng data can be read */ - { - uint32_t cnt = 5 /* microseconds */ * 20; - while(cnt--) - { - __asm__("nop"); - } + /* disable RNG */ + RNG_CR &= ~(RNG_CR_IE | RNG_CR_RNGEN); + /* reset Seed/Clock/ error status */ + RNG_SR &= ~(RNG_SR_SEIS | RNG_SR_CEIS); + /* reenable RNG */ + RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; + /* this delay is required before rng data can be read */ + { + uint32_t cnt = 5 /* microseconds */ * 20; + while (cnt--) { + __asm__("nop"); } + } - // to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1 - // we don't use the first random number generated after setting the RNGEN bit in setup - random32(); + // to be extra careful and heed the STM32F205xx Reference manual, + // Section 20.3.1 we don't use the first random number generated after setting + // the RNGEN bit in setup + random32(); #endif } -uint32_t random32(void) -{ +uint32_t random32(void) { #ifndef EMULATOR - uint32_t rng_samples = 0, rng_sr_img; - static uint32_t last = 0, new = 0; + uint32_t rng_samples = 0, rng_sr_img; + static uint32_t last = 0, new = 0; - while (new == last) { - /* Capture the RNG status register */ - rng_sr_img = RNG_SR; - if ((rng_sr_img & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) { - if (rng_sr_img & RNG_SR_DRDY) { - new = RNG_DR; - } - } - else if ((rng_sr_img & (RNG_SR_SECS | RNG_SR_CECS)) == 0) { - /* Reset RNG interrupt status bits (SECS, CECS errors no longer exist) */ - RNG_SR &= ~(RNG_SR_SEIS | RNG_SR_CEIS); - } - else { - /* RNG is not ready. Allow few more samples for RNG to come back alive - * before resetting */ - if (++rng_samples >= 100) { - /* RNG in hang state. Reset RNG */ - reset_rng(); - rng_samples = 0; - } - } + while (new == last) { + /* Capture the RNG status register */ + rng_sr_img = RNG_SR; + if ((rng_sr_img & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) { + if (rng_sr_img & RNG_SR_DRDY) { + new = RNG_DR; + } + } else if ((rng_sr_img & (RNG_SR_SECS | RNG_SR_CECS)) == 0) { + /* Reset RNG interrupt status bits (SECS, CECS errors no longer exist) */ + RNG_SR &= ~(RNG_SR_SEIS | RNG_SR_CEIS); + } else { + /* RNG is not ready. Allow few more samples for RNG to come back alive + * before resetting */ + if (++rng_samples >= 100) { + /* RNG in hang state. Reset RNG */ + reset_rng(); + rng_samples = 0; + } } - last = new; - return new; + } + last = new; + return new; #else - return random(); + return random(); #endif } // I miss C++ templates sooo bad. -#define RANDOM_PERMUTE(BUFF, COUNT) \ - do { \ - for (size_t i = (COUNT) - 1; i >= 1; i--) { \ - size_t j = random_uniform(i + 1); \ - typeof(*(BUFF)) t = (BUFF)[j]; \ - (BUFF)[j] = (BUFF)[i]; \ - (BUFF)[i] = t; \ - } \ - } while (0) +#define RANDOM_PERMUTE(BUFF, COUNT) \ + do { \ + for (size_t i = (COUNT)-1; i >= 1; i--) { \ + size_t j = random_uniform(i + 1); \ + typeof(*(BUFF)) t = (BUFF)[j]; \ + (BUFF)[j] = (BUFF)[i]; \ + (BUFF)[i] = t; \ + } \ + } while (0) -void random_permute_char(char *str, size_t len) -{ - RANDOM_PERMUTE(str, len); -} +void random_permute_char(char *str, size_t len) { RANDOM_PERMUTE(str, len); } -void random_permute_u16(uint16_t *buf, size_t count) -{ - RANDOM_PERMUTE(buf, count); +void random_permute_u16(uint16_t *buf, size_t count) { + RANDOM_PERMUTE(buf, count); } #undef RANDOM_PERMUTE - diff --git a/lib/transport/pb_common.c b/lib/transport/pb_common.c index 9a3db0168..5b12eb005 100644 --- a/lib/transport/pb_common.c +++ b/lib/transport/pb_common.c @@ -5,92 +5,79 @@ #include "pb_common.h" -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) -{ - iter->start = fields; - iter->pos = fields; - iter->required_field_index = 0; - iter->dest_struct = dest_struct; - iter->pData = (char*)dest_struct + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - - return (iter->pos->tag != 0); +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, + void *dest_struct) { + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + iter->pData = (char *)dest_struct + iter->pos->data_offset; + iter->pSize = (char *)iter->pData + iter->pos->size_offset; + + return (iter->pos->tag != 0); } -bool pb_field_iter_next(pb_field_iter_t *iter) -{ - const pb_field_t *prev_field = iter->pos; +bool pb_field_iter_next(pb_field_iter_t *iter) { + const pb_field_t *prev_field = iter->pos; - if (prev_field->tag == 0) - { - /* Handle empty message types, where the first field is already the terminator. - * In other cases, the iter->pos never points to the terminator. */ - return false; - } - - iter->pos++; - - if (iter->pos->tag == 0) - { - /* Wrapped back to beginning, reinitialize */ - (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); - return false; + if (prev_field->tag == 0) { + /* Handle empty message types, where the first field is already the + * terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } else { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && + PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && + iter->pos->data_offset == PB_SIZE_MAX) { + /* Don't advance pointers inside unions */ + return true; + } else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void *); } - else - { - /* Increment the pointers based on previous field size */ - size_t prev_size = prev_field->data_size; - - if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && - PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && - iter->pos->data_offset == PB_SIZE_MAX) - { - /* Don't advance pointers inside unions */ - return true; - } - else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && - PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) - { - /* In static arrays, the data_size tells the size of a single entry and - * array_size is the number of entries */ - prev_size *= prev_field->array_size; - } - else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) - { - /* Pointer fields always have a constant size in the main structure. - * The data_size only applies to the dynamically allocated area. */ - prev_size = sizeof(void*); - } - if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) - { - /* Count the required fields, in order to check their presence in the - * decoder. */ - iter->required_field_index++; - } - - iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - return true; + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; } -} -bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) -{ - const pb_field_t *start = iter->pos; - - do { - if (iter->pos->tag == tag && - PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) - { - /* Found the wanted field */ - return true; - } - - (void)pb_field_iter_next(iter); - } while (iter->pos != start); - - /* Searched all the way back to start, and found nothing. */ - return false; + iter->pData = (char *)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char *)iter->pData + iter->pos->size_offset; + return true; + } } +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) { + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} diff --git a/lib/transport/pb_decode.c b/lib/transport/pb_decode.c index 177950360..5ff4ecd7e 100644 --- a/lib/transport/pb_decode.c +++ b/lib/transport/pb_decode.c @@ -7,10 +7,11 @@ * are propagated correctly. On other compilers and gcc before 3.4.0 just * ignore the annotation. */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn +#if !defined(__GNUC__) || (__GNUC__ < 3) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +#define checkreturn #else - #define checkreturn __attribute__((warn_unused_result)) +#define checkreturn __attribute__((warn_unused_result)) #endif #include "pb.h" @@ -21,36 +22,67 @@ * Declarations internal to this file * **************************************/ -typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; - -static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); -static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, + void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, + size_t count); +static bool checkreturn read_raw_value(pb_istream_t *stream, + pb_wire_type_t wire_type, pb_byte_t *buf, + size_t *size); +static bool checkreturn decode_static_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter); +static void iter_from_extension(pb_field_iter_t *iter, + pb_extension_t *extension); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, + uint32_t tag, + pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, + pb_wire_type_t wire_type, + pb_field_iter_t *iter); static bool checkreturn find_extension_field(pb_field_iter_t *iter); static void pb_field_set_to_default(pb_field_iter_t *iter); -static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); -static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); -static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static void pb_message_set_to_defaults(const pb_field_t fields[], + void *dest_struct); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, + uint32_t *dest, bool *eof); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, + const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, + const pb_field_t *field, + void *dest); static bool checkreturn pb_skip_varint(pb_istream_t *stream); static bool checkreturn pb_skip_string(pb_istream_t *stream); #ifdef PB_ENABLE_MALLOC -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); -static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, + size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, + pb_field_iter_t *iter); static void pb_release_single_field(const pb_field_iter_t *iter); #endif @@ -72,411 +104,367 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { &pb_dec_svarint, &pb_dec_fixed32, &pb_dec_fixed64, - + &pb_dec_bytes, &pb_dec_string, &pb_dec_submessage, NULL, /* extensions */ - &pb_dec_fixed_length_bytes -}; + &pb_dec_fixed_length_bytes}; /******************************* * pb_istream_t implementation * *******************************/ -static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) -{ - size_t i; - const pb_byte_t *source = (const pb_byte_t*)stream->state; - stream->state = (pb_byte_t*)stream->state + count; - - if (buf != NULL) - { - for (i = 0; i < count; i++) - buf[i] = source[i]; - } - - return true; +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, + size_t count) { + size_t i; + const pb_byte_t *source = (const pb_byte_t *)stream->state; + stream->state = (pb_byte_t *)stream->state + count; + + if (buf != NULL) { + for (i = 0; i < count; i++) buf[i] = source[i]; + } + + return true; } -bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) -{ - if (count == 0) - return true; +bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) { + if (count == 0) return true; #ifndef PB_BUFFER_ONLY - if (buf == NULL && stream->callback != buf_read) - { - /* Skip input bytes */ - pb_byte_t tmp[16]; - while (count > 16) - { - if (!pb_read(stream, tmp, 16)) - return false; - - count -= 16; - } - - return pb_read(stream, tmp, count); - } + if (buf == NULL && stream->callback != buf_read) { + /* Skip input bytes */ + pb_byte_t tmp[16]; + while (count > 16) { + if (!pb_read(stream, tmp, 16)) return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } #endif - if (stream->bytes_left < count) - PB_RETURN_ERROR(stream, "end-of-stream"); - + if (stream->bytes_left < count) PB_RETURN_ERROR(stream, "end-of-stream"); + #ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); #else - if (!buf_read(stream, buf, count)) - return false; + if (!buf_read(stream, buf, count)) return false; #endif - - stream->bytes_left -= count; - return true; + + stream->bytes_left -= count; + return true; } /* Read a single byte from input stream. buf may not be NULL. * This is an optimization for the varint decoding. */ -static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) -{ - if (stream->bytes_left == 0) - PB_RETURN_ERROR(stream, "end-of-stream"); +static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) { + if (stream->bytes_left == 0) PB_RETURN_ERROR(stream, "end-of-stream"); #ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, 1)) - PB_RETURN_ERROR(stream, "io error"); + if (!stream->callback(stream, buf, 1)) PB_RETURN_ERROR(stream, "io error"); #else - *buf = *(const pb_byte_t*)stream->state; - stream->state = (pb_byte_t*)stream->state + 1; + *buf = *(const pb_byte_t *)stream->state; + stream->state = (pb_byte_t *)stream->state + 1; #endif - stream->bytes_left--; - - return true; + stream->bytes_left--; + + return true; } -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) -{ - pb_istream_t stream; - /* Cast away the const from buf without a compiler error. We are - * careful to use it only in a const manner in the callbacks. - */ - union { - void *state; - const void *c_state; - } state; +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) { + pb_istream_t stream; + /* Cast away the const from buf without a compiler error. We are + * careful to use it only in a const manner in the callbacks. + */ + union { + void *state; + const void *c_state; + } state; #ifdef PB_BUFFER_ONLY - stream.callback = NULL; + stream.callback = NULL; #else - stream.callback = &buf_read; + stream.callback = &buf_read; #endif - state.c_state = buf; - stream.state = state.state; - stream.bytes_left = bufsize; + state.c_state = buf; + stream.state = state.state; + stream.bytes_left = bufsize; #ifndef PB_NO_ERRMSG - stream.errmsg = NULL; + stream.errmsg = NULL; #endif - return stream; + return stream; } /******************** * Helper functions * ********************/ -static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) -{ - pb_byte_t byte; - uint32_t result; - - if (!pb_readbyte(stream, &byte)) - { - if (stream->bytes_left == 0) - { - if (eof) - { - *eof = true; - } - } +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, + uint32_t *dest, bool *eof) { + pb_byte_t byte; + uint32_t result; - return false; - } - - if ((byte & 0x80) == 0) - { - /* Quick case, 1 byte value */ - result = byte; + if (!pb_readbyte(stream, &byte)) { + if (stream->bytes_left == 0) { + if (eof) { + *eof = true; + } } - else - { - /* Multibyte case */ - uint_fast8_t bitpos = 7; - result = byte & 0x7F; - - do - { - if (!pb_readbyte(stream, &byte)) - return false; - - if (bitpos >= 32) - { - /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ - uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; - - if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) - { - PB_RETURN_ERROR(stream, "varint overflow"); - } - } - else - { - result |= (uint32_t)(byte & 0x7F) << bitpos; - } - bitpos = (uint_fast8_t)(bitpos + 7); - } while (byte & 0x80); - - if (bitpos == 35 && (byte & 0x70) != 0) - { - /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ - PB_RETURN_ERROR(stream, "varint overflow"); + + return false; + } + + if ((byte & 0x80) == 0) { + /* Quick case, 1 byte value */ + result = byte; + } else { + /* Multibyte case */ + uint_fast8_t bitpos = 7; + result = byte & 0x7F; + + do { + if (!pb_readbyte(stream, &byte)) return false; + + if (bitpos >= 32) { + /* Note: The varint could have trailing 0x80 bytes, or 0xFF for + * negative. */ + uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; + + if ((byte & 0x7F) != 0x00 && + ((result >> 31) == 0 || byte != sign_extension)) { + PB_RETURN_ERROR(stream, "varint overflow"); } - } - - *dest = result; - return true; + } else { + result |= (uint32_t)(byte & 0x7F) << bitpos; + } + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + if (bitpos == 35 && (byte & 0x70) != 0) { + /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + + *dest = result; + return true; } -bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) -{ - return pb_decode_varint32_eof(stream, dest, NULL); +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) { + return pb_decode_varint32_eof(stream, dest, NULL); } #ifndef PB_WITHOUT_64BIT -bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) -{ - pb_byte_t byte; - uint_fast8_t bitpos = 0; - uint64_t result = 0; - - do - { - if (bitpos >= 64) - PB_RETURN_ERROR(stream, "varint overflow"); - - if (!pb_readbyte(stream, &byte)) - return false; - - result |= (uint64_t)(byte & 0x7F) << bitpos; - bitpos = (uint_fast8_t)(bitpos + 7); - } while (byte & 0x80); - - *dest = result; - return true; +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) { + pb_byte_t byte; + uint_fast8_t bitpos = 0; + uint64_t result = 0; + + do { + if (bitpos >= 64) PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; } #endif -bool checkreturn pb_skip_varint(pb_istream_t *stream) -{ - pb_byte_t byte; - do - { - if (!pb_read(stream, &byte, 1)) - return false; - } while (byte & 0x80); - return true; +bool checkreturn pb_skip_varint(pb_istream_t *stream) { + pb_byte_t byte; + do { + if (!pb_read(stream, &byte, 1)) return false; + } while (byte & 0x80); + return true; } -bool checkreturn pb_skip_string(pb_istream_t *stream) -{ - uint32_t length; - if (!pb_decode_varint32(stream, &length)) - return false; - - return pb_read(stream, NULL, length); +bool checkreturn pb_skip_string(pb_istream_t *stream) { + uint32_t length; + if (!pb_decode_varint32(stream, &length)) return false; + + return pb_read(stream, NULL, length); } -bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) -{ - uint32_t temp; - *eof = false; - *wire_type = (pb_wire_type_t) 0; - *tag = 0; - - if (!pb_decode_varint32_eof(stream, &temp, eof)) - { - return false; - } - - if (temp == 0) - { - *eof = true; /* Special feature: allow 0-terminated messages. */ - return false; - } - - *tag = temp >> 3; - *wire_type = (pb_wire_type_t)(temp & 7); - return true; +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, + uint32_t *tag, bool *eof) { + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t)0; + *tag = 0; + + if (!pb_decode_varint32_eof(stream, &temp, eof)) { + return false; + } + + if (temp == 0) { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; } -bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) -{ - switch (wire_type) - { - case PB_WT_VARINT: return pb_skip_varint(stream); - case PB_WT_64BIT: return pb_read(stream, NULL, 8); - case PB_WT_STRING: return pb_skip_string(stream); - case PB_WT_32BIT: return pb_read(stream, NULL, 4); - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) { + switch (wire_type) { + case PB_WT_VARINT: + return pb_skip_varint(stream); + case PB_WT_64BIT: + return pb_read(stream, NULL, 8); + case PB_WT_STRING: + return pb_skip_string(stream); + case PB_WT_32BIT: + return pb_read(stream, NULL, 4); + default: + PB_RETURN_ERROR(stream, "invalid wire_type"); + } } /* Read a raw value to buffer, for the purpose of passing it to callback as * a substream. Size is maximum size on call, and actual size on return. */ -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) -{ - size_t max_size = *size; - switch (wire_type) - { - case PB_WT_VARINT: - *size = 0; - do - { - (*size)++; - if (*size > max_size) return false; - if (!pb_read(stream, buf, 1)) return false; - } while (*buf++ & 0x80); - return true; - - case PB_WT_64BIT: - *size = 8; - return pb_read(stream, buf, 8); - - case PB_WT_32BIT: - *size = 4; - return pb_read(stream, buf, 4); - - case PB_WT_STRING: - /* Calling read_raw_value with a PB_WT_STRING is an error. - * Explicitly handle this case and fallthrough to default to avoid - * compiler warnings. - */ - - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } +static bool checkreturn read_raw_value(pb_istream_t *stream, + pb_wire_type_t wire_type, pb_byte_t *buf, + size_t *size) { + size_t max_size = *size; + switch (wire_type) { + case PB_WT_VARINT: + *size = 0; + do { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + case PB_WT_STRING: + /* Calling read_raw_value with a PB_WT_STRING is an error. + * Explicitly handle this case and fallthrough to default to avoid + * compiler warnings. + */ + + default: + PB_RETURN_ERROR(stream, "invalid wire_type"); + } } /* Decode string length from stream and return a substream with limited length. * Remember to close the substream using pb_close_string_substream(). */ -bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - uint32_t size; - if (!pb_decode_varint32(stream, &size)) - return false; - - *substream = *stream; - if (substream->bytes_left < size) - PB_RETURN_ERROR(stream, "parent stream too short"); - - substream->bytes_left = size; - stream->bytes_left -= size; - return true; +bool checkreturn pb_make_string_substream(pb_istream_t *stream, + pb_istream_t *substream) { + uint32_t size; + if (!pb_decode_varint32(stream, &size)) return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; } -bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - if (substream->bytes_left) { - if (!pb_read(substream, NULL, substream->bytes_left)) - return false; - } +bool checkreturn pb_close_string_substream(pb_istream_t *stream, + pb_istream_t *substream) { + if (substream->bytes_left) { + if (!pb_read(substream, NULL, substream->bytes_left)) return false; + } - stream->state = substream->state; + stream->state = substream->state; #ifndef PB_NO_ERRMSG - stream->errmsg = substream->errmsg; + stream->errmsg = substream->errmsg; #endif - return true; + return true; } /************************* * Decode a single field * *************************/ -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) -{ - pb_type_t type; - pb_decoder_t func; - - type = iter->pos->type; - func = PB_DECODERS[PB_LTYPE(type)]; - - switch (PB_HTYPE(type)) - { - case PB_HTYPE_REQUIRED: - return func(stream, iter->pos, iter->pData); - - case PB_HTYPE_OPTIONAL: - if (iter->pSize != iter->pData) - *(bool*)iter->pSize = true; - return func(stream, iter->pos, iter->pData); - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array */ - bool status = true; - pb_size_t *size = (pb_size_t*)iter->pSize; - - pb_istream_t substream; - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left > 0 && *size < iter->pos->array_size) - { - void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); - if (!func(&substream, iter->pos, pItem)) - { - status = false; - break; - } - (*size)++; - } - - if (substream.bytes_left != 0) - PB_RETURN_ERROR(stream, "array overflow"); - if (!pb_close_string_substream(stream, &substream)) - return false; - - return status; - } - else - { - /* Repeated field */ - pb_size_t *size = (pb_size_t*)iter->pSize; - char *pItem = (char*)iter->pData + iter->pos->data_size * (*size); +static bool checkreturn decode_static_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter) { + pb_type_t type; + pb_decoder_t func; - if ((*size)++ >= iter->pos->array_size) - PB_RETURN_ERROR(stream, "array overflow"); + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; - return func(stream, iter->pos, pItem); - } + switch (PB_HTYPE(type)) { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); - case PB_HTYPE_ONEOF: - *(pb_size_t*)iter->pSize = iter->pos->tag; - if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) - { - /* We memset to zero so that any callbacks are set to NULL. - * Then set any default values. */ - memset(iter->pData, 0, iter->pos->data_size); - pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); - } - return func(stream, iter->pos, iter->pData); + case PB_HTYPE_OPTIONAL: + if (iter->pSize != iter->pData) *(bool *)iter->pSize = true; + return func(stream, iter->pos, iter->pData); - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING && + PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) { + /* Packed array */ + bool status = true; + pb_size_t *size = (pb_size_t *)iter->pSize; + + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) { + void *pItem = (char *)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) { + status = false; + break; + } + (*size)++; + } + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + if (!pb_close_string_substream(stream, &substream)) return false; + + return status; + } else { + /* Repeated field */ + pb_size_t *size = (pb_size_t *)iter->pSize; + char *pItem = (char *)iter->pData + iter->pos->data_size * (*size); + + if ((*size)++ >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + return func(stream, iter->pos, pItem); + } + + case PB_HTYPE_ONEOF: + *(pb_size_t *)iter->pSize = iter->pos->tag; + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t *)iter->pos->ptr, + iter->pData); + } + return func(stream, iter->pos, iter->pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } } #ifdef PB_ENABLE_MALLOC @@ -484,1051 +472,926 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t * array_size is the number of entries to reserve in an array. * Zero size is not allowed, use pb_free() for releasing. */ -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) -{ - void *ptr = *(void**)pData; - - if (data_size == 0 || array_size == 0) - PB_RETURN_ERROR(stream, "invalid size"); - - /* Check for multiplication overflows. - * This code avoids the costly division if the sizes are small enough. - * Multiplication is safe as long as only half of bits are set - * in either multiplicand. - */ - { - const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); - if (data_size >= check_limit || array_size >= check_limit) - { - const size_t size_max = (size_t)-1; - if (size_max / array_size < data_size) - { - PB_RETURN_ERROR(stream, "size too large"); - } - } +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, + size_t data_size, size_t array_size) { + void *ptr = *(void **)pData; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) { + PB_RETURN_ERROR(stream, "size too large"); + } } - - /* Allocate new or expand previous allocation */ - /* Note: on failure the old pointer will remain in the structure, - * the message must be freed by caller also on error return. */ - ptr = pb_realloc(ptr, array_size * data_size); - if (ptr == NULL) - PB_RETURN_ERROR(stream, "realloc failed"); - - *(void**)pData = ptr; - return true; + } + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, array_size * data_size); + if (ptr == NULL) PB_RETURN_ERROR(stream, "realloc failed"); + + *(void **)pData = ptr; + return true; } -/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ -static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) -{ - if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || - PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) - { - *(void**)pItem = NULL; - } - else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) - { - /* We memset to zero so that any callbacks are set to NULL. - * Then set any default values. */ - memset(pItem, 0, iter->pos->data_size); - pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); - } +/* Clear a newly allocated item in case it contains a pointer, or is a + * submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) { + *(void **)pItem = NULL; + } else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(pItem, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t *)iter->pos->ptr, pItem); + } } #endif -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) -{ +static bool checkreturn decode_pointer_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter) { #ifndef PB_ENABLE_MALLOC - PB_UNUSED(wire_type); - PB_UNUSED(iter); - PB_RETURN_ERROR(stream, "no malloc support"); + PB_UNUSED(wire_type); + PB_UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); #else - pb_type_t type; - pb_decoder_t func; - - type = iter->pos->type; - func = PB_DECODERS[PB_LTYPE(type)]; - - switch (PB_HTYPE(type)) - { - case PB_HTYPE_REQUIRED: - case PB_HTYPE_OPTIONAL: - case PB_HTYPE_ONEOF: - if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && - *(void**)iter->pData != NULL) - { - /* Duplicate field, have to release the old allocation first. */ - pb_release_single_field(iter); - } - - if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - *(pb_size_t*)iter->pSize = iter->pos->tag; - } + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void **)iter->pData != NULL) { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) { + *(pb_size_t *)iter->pSize = iter->pos->tag; + } + + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) { + return func(stream, iter->pos, iter->pData); + } else { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void **)iter->pData, iter); + return func(stream, iter->pos, *(void **)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING && + PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) { + /* Packed array, multiple items come in at once. */ + bool status = true; + pb_size_t *size = (pb_size_t *)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; - if (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES) - { - return func(stream, iter->pos, iter->pData); - } - else - { - if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) - return false; - - initialize_pointer_field(*(void**)iter->pData, iter); - return func(stream, iter->pos, *(void**)iter->pData); + if (!pb_make_string_substream(stream, &substream)) return false; + + while (substream.bytes_left) { + if ((size_t)*size + 1 > allocated_size) { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + allocated_size += + (substream.bytes_left - 1) / iter->pos->data_size + 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, + allocated_size)) { + status = false; + break; } - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array, multiple items come in at once. */ - bool status = true; - pb_size_t *size = (pb_size_t*)iter->pSize; - size_t allocated_size = *size; - void *pItem; - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left) - { - if ((size_t)*size + 1 > allocated_size) - { - /* Allocate more storage. This tries to guess the - * number of remaining entries. Round the division - * upwards. */ - allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; - - if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) - { - status = false; - break; - } - } - - /* Decode the array entry */ - pItem = *(char**)iter->pData + iter->pos->data_size * (*size); - initialize_pointer_field(pItem, iter); - if (!func(&substream, iter->pos, pItem)) - { - status = false; - break; - } - - if (*size == PB_SIZE_MAX) - { + } + + /* Decode the array entry */ + pItem = *(char **)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) { + status = false; + break; + } + + if (*size == PB_SIZE_MAX) { #ifndef PB_NO_ERRMSG - stream->errmsg = "too many array entries"; + stream->errmsg = "too many array entries"; #endif - status = false; - break; - } - - (*size)++; - } - if (!pb_close_string_substream(stream, &substream)) - return false; - - return status; - } - else - { - /* Normal repeated field, i.e. only one item at a time. */ - pb_size_t *size = (pb_size_t*)iter->pSize; - void *pItem; - - if (*size == PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "too many array entries"); - - (*size)++; - if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) - return false; - - pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1); - initialize_pointer_field(pItem, iter); - return func(stream, iter->pos, pItem); - } + status = false; + break; + } - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } + (*size)++; + } + if (!pb_close_string_substream(stream, &substream)) return false; + + return status; + } else { + /* Normal repeated field, i.e. only one item at a time. */ + pb_size_t *size = (pb_size_t *)iter->pSize; + void *pItem; + + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + + (*size)++; + if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) + return false; + + pItem = *(char **)iter->pData + iter->pos->data_size * (*size - 1); + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } #endif } -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) -{ - pb_callback_t *pCallback = (pb_callback_t*)iter->pData; +static bool checkreturn decode_callback_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter) { + pb_callback_t *pCallback = (pb_callback_t *)iter->pData; #ifdef PB_OLD_CALLBACK_STYLE - void *arg; + void *arg; #else - void **arg; + void **arg; #endif - - if (pCallback == NULL || pCallback->funcs.decode == NULL) - return pb_skip_field(stream, wire_type); + + if (pCallback == NULL || pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); #ifdef PB_OLD_CALLBACK_STYLE - arg = pCallback->arg; + arg = pCallback->arg; #else - arg = &(pCallback->arg); + arg = &(pCallback->arg); #endif - - if (wire_type == PB_WT_STRING) - { - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - do - { - if (!pCallback->funcs.decode(&substream, iter->pos, arg)) - PB_RETURN_ERROR(stream, "callback failed"); - } while (substream.bytes_left); - - if (!pb_close_string_substream(stream, &substream)) - return false; - - return true; - } - else - { - /* Copy the single scalar value to stack. - * This is required so that we can limit the stream length, - * which in turn allows to use same callback for packed and - * not-packed fields. */ - pb_istream_t substream; - pb_byte_t buffer[10]; - size_t size = sizeof(buffer); - - if (!read_raw_value(stream, wire_type, buffer, &size)) - return false; - substream = pb_istream_from_buffer(buffer, size); - - return pCallback->funcs.decode(&substream, iter->pos, arg); - } + + if (wire_type == PB_WT_STRING) { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) return false; + + do { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + if (!pb_close_string_substream(stream, &substream)) return false; + + return true; + } else { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + pb_byte_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } } -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) -{ +static bool checkreturn decode_field(pb_istream_t *stream, + pb_wire_type_t wire_type, + pb_field_iter_t *iter) { #ifdef PB_ENABLE_MALLOC - /* When decoding an oneof field, check if there is old data that must be - * released first. */ - if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) - { - if (!pb_release_union_field(stream, iter)) - return false; - } + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) { + if (!pb_release_union_field(stream, iter)) return false; + } #endif - switch (PB_ATYPE(iter->pos->type)) - { - case PB_ATYPE_STATIC: - return decode_static_field(stream, wire_type, iter); - - case PB_ATYPE_POINTER: - return decode_pointer_field(stream, wire_type, iter); - - case PB_ATYPE_CALLBACK: - return decode_callback_field(stream, wire_type, iter); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } + switch (PB_ATYPE(iter->pos->type)) { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } } -static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) -{ - /* Fake a field iterator for the extension field. - * It is not actually safe to advance this iterator, but decode_field - * will not even try to. */ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - (void)pb_field_iter_begin(iter, field, extension->dest); - iter->pData = extension->dest; - iter->pSize = &extension->found; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - /* For pointer extensions, the pointer is stored directly - * in the extension structure. This avoids having an extra - * indirection. */ - iter->pData = &extension->dest; - } +static void iter_from_extension(pb_field_iter_t *iter, + pb_extension_t *extension) { + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + const pb_field_t *field = (const pb_field_t *)extension->type->arg; + (void)pb_field_iter_begin(iter, field, extension->dest); + iter->pData = extension->dest; + iter->pSize = &extension->found; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + iter->pData = &extension->dest; + } } /* Default handler for extension fields. Expects a pb_field_t structure * in extension->type->arg. */ static bool checkreturn default_extension_decoder(pb_istream_t *stream, - pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) -{ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - pb_field_iter_t iter; - - if (field->tag != tag) - return true; - - iter_from_extension(&iter, extension); - extension->found = true; - return decode_field(stream, wire_type, &iter); + pb_extension_t *extension, + uint32_t tag, + pb_wire_type_t wire_type) { + const pb_field_t *field = (const pb_field_t *)extension->type->arg; + pb_field_iter_t iter; + + if (field->tag != tag) return true; + + iter_from_extension(&iter, extension); + extension->found = true; + return decode_field(stream, wire_type, &iter); } /* Try to decode an unknown field as an extension field. Tries each extension * decoder in turn, until one of them handles the field or loop ends. */ -static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) -{ - pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; - size_t pos = stream->bytes_left; - - while (extension != NULL && pos == stream->bytes_left) - { - bool status; - if (extension->type->decode) - status = extension->type->decode(stream, extension, tag, wire_type); - else - status = default_extension_decoder(stream, extension, tag, wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, + pb_wire_type_t wire_type, + pb_field_iter_t *iter) { + pb_extension_t *extension = *(pb_extension_t *const *)iter->pData; + size_t pos = stream->bytes_left; - if (!status) - return false; - - extension = extension->next; - } - - return true; + while (extension != NULL && pos == stream->bytes_left) { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) return false; + + extension = extension->next; + } + + return true; } /* Step through the iterator until an extension field is found or until all * entries have been checked. There can be only one extension field per * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iter_t *iter) -{ - const pb_field_t *start = iter->pos; - - do { - if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) - return true; - (void)pb_field_iter_next(iter); - } while (iter->pos != start); - - return false; +static bool checkreturn find_extension_field(pb_field_iter_t *iter) { + const pb_field_t *start = iter->pos; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) return true; + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + return false; } /* Initialize message fields to default values, recursively */ -static void pb_field_set_to_default(pb_field_iter_t *iter) -{ - pb_type_t type; - type = iter->pos->type; - - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; - while (ext != NULL) - { - pb_field_iter_t ext_iter; - ext->found = false; - iter_from_extension(&ext_iter, ext); - pb_field_set_to_default(&ext_iter); - ext = ext->next; - } +static void pb_field_set_to_default(pb_field_iter_t *iter) { + pb_type_t type; + type = iter->pos->type; + + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) { + pb_extension_t *ext = *(pb_extension_t *const *)iter->pData; + while (ext != NULL) { + pb_field_iter_t ext_iter; + ext->found = false; + iter_from_extension(&ext_iter, ext); + pb_field_set_to_default(&ext_iter); + ext = ext->next; } - else if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - bool init_data = true; - if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) - { - /* Set has_field to false. Still initialize the optional field - * itself also. */ - *(bool*)iter->pSize = false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || - PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - /* REPEATED: Set array count to 0, no need to initialize contents. - ONEOF: Set which_field to 0. */ - *(pb_size_t*)iter->pSize = 0; - init_data = false; - } - - if (init_data) - { - if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) - { - /* Initialize submessage to defaults */ - pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); - } - else if (iter->pos->ptr != NULL) - { - /* Initialize to default value */ - memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); - } - else - { - /* Initialize to zeros */ - memset(iter->pData, 0, iter->pos->data_size); - } - } + } else if (PB_ATYPE(type) == PB_ATYPE_STATIC) { + bool init_data = true; + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool *)iter->pSize = false; + } else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) { + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ + *(pb_size_t *)iter->pSize = 0; + init_data = false; } - else if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - /* Initialize the pointer to NULL. */ - *(void**)iter->pData = NULL; - - /* Initialize array count to 0. */ - if (PB_HTYPE(type) == PB_HTYPE_REPEATED || - PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - *(pb_size_t*)iter->pSize = 0; - } + + if (init_data) { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *)iter->pos->ptr, + iter->pData); + } else if (iter->pos->ptr != NULL) { + /* Initialize to default value */ + memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); + } else { + /* Initialize to zeros */ + memset(iter->pData, 0, iter->pos->data_size); + } } - else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) - { - /* Don't overwrite callback */ + } else if (PB_ATYPE(type) == PB_ATYPE_POINTER) { + /* Initialize the pointer to NULL. */ + *(void **)iter->pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) { + *(pb_size_t *)iter->pSize = 0; } + } else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) { + /* Don't overwrite callback */ + } } -static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) -{ - pb_field_iter_t iter; +static void pb_message_set_to_defaults(const pb_field_t fields[], + void *dest_struct) { + pb_field_iter_t iter; - if (!pb_field_iter_begin(&iter, fields, dest_struct)) - return; /* Empty message type */ - - do - { - pb_field_set_to_default(&iter); - } while (pb_field_iter_next(&iter)); + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do { + pb_field_set_to_default(&iter); + } while (pb_field_iter_next(&iter)); } /********************* * Decode all fields * *********************/ -bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; - const uint32_t allbits = ~(uint32_t)0; - uint32_t extension_range_start = 0; - pb_field_iter_t iter; +bool checkreturn pb_decode_noinit(pb_istream_t *stream, + const pb_field_t fields[], + void *dest_struct) { + uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; + const uint32_t allbits = ~(uint32_t)0; + uint32_t extension_range_start = 0; + pb_field_iter_t iter; + + /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated + * fixed count field. This can only handle _one_ repeated fixed count field + * that is unpacked and unordered among other (non repeated fixed count) + * fields. + */ + const pb_field_t *fixed_count_field = NULL; + pb_size_t fixed_count_size = 0; + + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); + + while (stream->bytes_left) { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) { + if (eof) + break; + else + return false; + } - /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed - * count field. This can only handle _one_ repeated fixed count field that - * is unpacked and unordered among other (non repeated fixed count) fields. - */ - const pb_field_t *fixed_count_field = NULL; - pb_size_t fixed_count_size = 0; - - /* Return value ignored, as empty message types will be correctly handled by - * pb_field_iter_find() anyway. */ - (void)pb_field_iter_begin(&iter, fields, dest_struct); - - while (stream->bytes_left) - { - uint32_t tag; - pb_wire_type_t wire_type; - bool eof; - - if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) - { - if (eof) - break; - else - return false; - } + if (!pb_field_iter_find(&iter, tag)) { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; - if (!pb_field_iter_find(&iter, tag)) - { - /* No match found, check if it matches an extension. */ - if (tag >= extension_range_start) - { - if (!find_extension_field(&iter)) - extension_range_start = (uint32_t)-1; - else - extension_range_start = iter.pos->tag; - - if (tag >= extension_range_start) - { - size_t pos = stream->bytes_left; - - if (!decode_extension(stream, tag, wire_type, &iter)) - return false; - - if (pos != stream->bytes_left) - { - /* The field was handled */ - continue; - } - } - } + if (tag >= extension_range_start) { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) return false; - /* No match found, skip data */ - if (!pb_skip_field(stream, wire_type)) - return false; + if (pos != stream->bytes_left) { + /* The field was handled */ continue; + } } + } - /* If a repeated fixed count field was found, get size from - * 'fixed_count_field' as there is no counter contained in the struct. - */ - if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED - && iter.pSize == iter.pData) - { - if (fixed_count_field != iter.pos) { - /* If the new fixed count field does not match the previous one, - * check that the previous one is NULL or that it finished - * receiving all the expected data. - */ - if (fixed_count_field != NULL && - fixed_count_size != fixed_count_field->array_size) - { - PB_RETURN_ERROR(stream, "wrong size for fixed count field"); - } - - fixed_count_field = iter.pos; - fixed_count_size = 0; - } + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) return false; + continue; + } - iter.pSize = &fixed_count_size; + /* If a repeated fixed count field was found, get size from + * 'fixed_count_field' as there is no counter contained in the struct. + */ + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED && + iter.pSize == iter.pData) { + if (fixed_count_field != iter.pos) { + /* If the new fixed count field does not match the previous one, + * check that the previous one is NULL or that it finished + * receiving all the expected data. + */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); } - if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED - && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) - { - uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); - fields_seen[iter.required_field_index >> 5] |= tmp; - } + fixed_count_field = iter.pos; + fixed_count_size = 0; + } - if (!decode_field(stream, wire_type, &iter)) - return false; + iter.pSize = &fixed_count_size; } - /* Check that all elements of the last decoded fixed count field were present. */ - if (fixed_count_field != NULL && - fixed_count_size != fixed_count_field->array_size) - { - PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED && + iter.required_field_index < PB_MAX_REQUIRED_FIELDS) { + uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); + fields_seen[iter.required_field_index >> 5] |= tmp; } - /* Check that all required fields were present. */ - { - /* First figure out the number of required fields by - * seeking to the end of the field array. Usually we - * are already close to end after decoding. - */ - unsigned req_field_count; - pb_type_t last_type; - unsigned i; - do { - req_field_count = iter.required_field_index; - last_type = iter.pos->type; - } while (pb_field_iter_next(&iter)); - - /* Fixup if last field was also required. */ - if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) - req_field_count++; - - if (req_field_count > PB_MAX_REQUIRED_FIELDS) - req_field_count = PB_MAX_REQUIRED_FIELDS; - - if (req_field_count > 0) - { - /* Check the whole words */ - for (i = 0; i < (req_field_count >> 5); i++) - { - if (fields_seen[i] != allbits) - PB_RETURN_ERROR(stream, "missing required field"); - } - - /* Check the remaining bits (if any) */ - if ((req_field_count & 31) != 0) - { - if (fields_seen[req_field_count >> 5] != - (allbits >> (32 - (req_field_count & 31)))) - { - PB_RETURN_ERROR(stream, "missing required field"); - } - } + if (!decode_field(stream, wire_type, &iter)) return false; + } + + /* Check that all elements of the last decoded fixed count field were present. + */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_iter_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + + if (req_field_count > 0) { + /* Check the whole words */ + for (i = 0; i < (req_field_count >> 5); i++) { + if (fields_seen[i] != allbits) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits (if any) */ + if ((req_field_count & 31) != 0) { + if (fields_seen[req_field_count >> 5] != + (allbits >> (32 - (req_field_count & 31)))) { + PB_RETURN_ERROR(stream, "missing required field"); } + } } - - return true; + } + + return true; } -bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - bool status; - pb_message_set_to_defaults(fields, dest_struct); - status = pb_decode_noinit(stream, fields, dest_struct); - +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct) { + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + #ifdef PB_ENABLE_MALLOC - if (!status) - pb_release(fields, dest_struct); + if (!status) pb_release(fields, dest_struct); #endif - - return status; + + return status; } -bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - pb_istream_t substream; - bool status; +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct) { + pb_istream_t substream; + bool status; - if (!pb_make_string_substream(stream, &substream)) - return false; + if (!pb_make_string_substream(stream, &substream)) return false; - status = pb_decode_noinit(&substream, fields, dest_struct); + status = pb_decode_noinit(&substream, fields, dest_struct); - if (!pb_close_string_substream(stream, &substream)) - return false; - return status; + if (!pb_close_string_substream(stream, &substream)) return false; + return status; } -bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - pb_istream_t substream; - bool status; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - status = pb_decode(&substream, fields, dest_struct); +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct) { + pb_istream_t substream; + bool status; - if (!pb_close_string_substream(stream, &substream)) - return false; - return status; + if (!pb_make_string_substream(stream, &substream)) return false; + + status = pb_decode(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) return false; + return status; } -bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ - return pb_decode(stream, fields, dest_struct); +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], + void *dest_struct) { + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); } #ifdef PB_ENABLE_MALLOC /* Given an oneof field, if there has already been a field inside this oneof, * release it before overwriting with a different one. */ -static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) -{ - pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ - pb_size_t new_tag = iter->pos->tag; /* New which_ value */ +static bool pb_release_union_field(pb_istream_t *stream, + pb_field_iter_t *iter) { + pb_size_t old_tag = *(pb_size_t *)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ - if (old_tag == 0) - return true; /* Ok, no old data in union */ + if (old_tag == 0) return true; /* Ok, no old data in union */ - if (old_tag == new_tag) - return true; /* Ok, old data is of same type => merge */ + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ - /* Release old data. The find can fail if the message struct contains - * invalid data. */ - if (!pb_field_iter_find(iter, old_tag)) - PB_RETURN_ERROR(stream, "invalid union tag"); + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); - pb_release_single_field(iter); + pb_release_single_field(iter); - /* Restore iterator to where it should be. - * This shouldn't fail unless the pb_field_t structure is corrupted. */ - if (!pb_field_iter_find(iter, new_tag)) - PB_RETURN_ERROR(stream, "iterator error"); - - return true; -} + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); -static void pb_release_single_field(const pb_field_iter_t *iter) -{ - pb_type_t type; - type = iter->pos->type; + return true; +} - if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - if (*(pb_size_t*)iter->pSize != iter->pos->tag) - return; /* This is not the current field in the union */ +static void pb_release_single_field(const pb_field_iter_t *iter) { + pb_type_t type; + type = iter->pos->type; + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) { + if (*(pb_size_t *)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t **)iter->pData; + while (ext != NULL) { + pb_field_iter_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + PB_ATYPE(type) != PB_ATYPE_CALLBACK) { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) { + pItem = *(void **)iter->pData; } - /* Release anything contained inside an extension or submsg. - * This has to be done even if the submsg itself is statically - * allocated. */ - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - /* Release fields from all extensions in the linked list */ - pb_extension_t *ext = *(pb_extension_t**)iter->pData; - while (ext != NULL) - { - pb_field_iter_t ext_iter; - iter_from_extension(&ext_iter, ext); - pb_release_single_field(&ext_iter); - ext = ext->next; - } + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { + if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) { + /* No _count field so use size of the array */ + count = iter->pos->array_size; + } else { + count = *(pb_size_t *)iter->pSize; + } + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK) - { - /* Release fields in submessage or submsg array */ - void *pItem = iter->pData; - pb_size_t count = 1; - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - pItem = *(void**)iter->pData; - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) { - /* No _count field so use size of the array */ - count = iter->pos->array_size; - } else { - count = *(pb_size_t*)iter->pSize; - } - if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) - { - /* Protect against corrupted _count fields */ - count = iter->pos->array_size; - } - } - - if (pItem) - { - while (count--) - { - pb_release((const pb_field_t*)iter->pos->ptr, pItem); - pItem = (char*)pItem + iter->pos->data_size; - } - } + if (pItem) { + while (count--) { + pb_release((const pb_field_t *)iter->pos->ptr, pItem); + pItem = (char *)pItem + iter->pos->data_size; + } } - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - if (PB_HTYPE(type) == PB_HTYPE_REPEATED && - (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES)) - { - /* Release entries in repeated string or bytes array */ - void **pItem = *(void***)iter->pData; - pb_size_t count = *(pb_size_t*)iter->pSize; - while (count--) - { - pb_free(*pItem); - *pItem++ = NULL; - } - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* We are going to release the array, so set the size to 0 */ - *(pb_size_t*)iter->pSize = 0; - } - - /* Release main item */ - pb_free(*(void**)iter->pData); - *(void**)iter->pData = NULL; + } + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void ***)iter->pData; + pb_size_t count = *(pb_size_t *)iter->pSize; + while (count--) { + pb_free(*pItem); + *pItem++ = NULL; + } + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t *)iter->pSize = 0; } + + /* Release main item */ + pb_free(*(void **)iter->pData); + *(void **)iter->pData = NULL; + } } -void pb_release(const pb_field_t fields[], void *dest_struct) -{ - pb_field_iter_t iter; - - if (!dest_struct) - return; /* Ignore NULL pointers, similar to free() */ - - if (!pb_field_iter_begin(&iter, fields, dest_struct)) - return; /* Empty message type */ - - do - { - pb_release_single_field(&iter); - } while (pb_field_iter_next(&iter)); +void pb_release(const pb_field_t fields[], void *dest_struct) { + pb_field_iter_t iter; + + if (!dest_struct) return; /* Ignore NULL pointers, similar to free() */ + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); } #endif /* Field decoders */ -bool pb_decode_bool(pb_istream_t *stream, bool *dest) -{ - return pb_dec_bool(stream, NULL, (void*)dest); +bool pb_decode_bool(pb_istream_t *stream, bool *dest) { + return pb_dec_bool(stream, NULL, (void *)dest); } -bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) -{ - pb_uint64_t value; - if (!pb_decode_varint(stream, &value)) - return false; - - if (value & 1) - *dest = (pb_int64_t)(~(value >> 1)); - else - *dest = (pb_int64_t)(value >> 1); - - return true; +bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) { + pb_uint64_t value; + if (!pb_decode_varint(stream, &value)) return false; + + if (value & 1) + *dest = (pb_int64_t)(~(value >> 1)); + else + *dest = (pb_int64_t)(value >> 1); + + return true; } -bool pb_decode_fixed32(pb_istream_t *stream, void *dest) -{ - pb_byte_t bytes[4]; +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) { + pb_byte_t bytes[4]; - if (!pb_read(stream, bytes, 4)) - return false; - - *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | - ((uint32_t)bytes[1] << 8) | - ((uint32_t)bytes[2] << 16) | - ((uint32_t)bytes[3] << 24); - return true; + if (!pb_read(stream, bytes, 4)) return false; + + *(uint32_t *)dest = ((uint32_t)bytes[0] << 0) | ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24); + return true; } #ifndef PB_WITHOUT_64BIT -bool pb_decode_fixed64(pb_istream_t *stream, void *dest) -{ - pb_byte_t bytes[8]; +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) { + pb_byte_t bytes[8]; - if (!pb_read(stream, bytes, 8)) - return false; - - *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | - ((uint64_t)bytes[1] << 8) | - ((uint64_t)bytes[2] << 16) | - ((uint64_t)bytes[3] << 24) | - ((uint64_t)bytes[4] << 32) | - ((uint64_t)bytes[5] << 40) | - ((uint64_t)bytes[6] << 48) | - ((uint64_t)bytes[7] << 56); - - return true; -} -#endif + if (!pb_read(stream, bytes, 8)) return false; -static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t value; - PB_UNUSED(field); - if (!pb_decode_varint32(stream, &value)) - return false; + *(uint64_t *)dest = ((uint64_t)bytes[0] << 0) | ((uint64_t)bytes[1] << 8) | + ((uint64_t)bytes[2] << 16) | ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[4] << 32) | ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[6] << 48) | ((uint64_t)bytes[7] << 56); - *(bool*)dest = (value != 0); - return true; + return true; } +#endif -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - pb_uint64_t value; - pb_int64_t svalue; - pb_int64_t clamped; - if (!pb_decode_varint(stream, &value)) - return false; - - /* See issue 97: Google's C++ protobuf allows negative varint values to - * be cast as int32_t, instead of the int64_t that should be used when - * encoding. Previous nanopb versions had a bug in encoding. In order to - * not break decoding of such messages, we cast <=32 bit fields to - * int32_t first to get the sign correct. - */ - if (field->data_size == sizeof(pb_int64_t)) - svalue = (pb_int64_t)value; - else - svalue = (int32_t)value; - - /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(pb_int64_t)) - clamped = *(pb_int64_t*)dest = svalue; - else if (field->data_size == sizeof(int32_t)) - clamped = *(int32_t*)dest = (int32_t)svalue; - else if (field->data_size == sizeof(int_least16_t)) - clamped = *(int_least16_t*)dest = (int_least16_t)svalue; - else if (field->data_size == sizeof(int_least8_t)) - clamped = *(int_least8_t*)dest = (int_least8_t)svalue; - else - PB_RETURN_ERROR(stream, "invalid data_size"); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + uint32_t value; + PB_UNUSED(field); + if (!pb_decode_varint32(stream, &value)) return false; - if (clamped != svalue) - PB_RETURN_ERROR(stream, "integer too large"); - - return true; + *(bool *)dest = (value != 0); + return true; } -static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - pb_uint64_t value, clamped; - if (!pb_decode_varint(stream, &value)) - return false; - - /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(pb_uint64_t)) - clamped = *(pb_uint64_t*)dest = value; - else if (field->data_size == sizeof(uint32_t)) - clamped = *(uint32_t*)dest = (uint32_t)value; - else if (field->data_size == sizeof(uint_least16_t)) - clamped = *(uint_least16_t*)dest = (uint_least16_t)value; - else if (field->data_size == sizeof(uint_least8_t)) - clamped = *(uint_least8_t*)dest = (uint_least8_t)value; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - if (clamped != value) - PB_RETURN_ERROR(stream, "integer too large"); - - return true; +static bool checkreturn pb_dec_varint(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + pb_uint64_t value; + pb_int64_t svalue; + pb_int64_t clamped; + if (!pb_decode_varint(stream, &value)) return false; + + /* See issue 97: Google's C++ protobuf allows negative varint values to + * be cast as int32_t, instead of the int64_t that should be used when + * encoding. Previous nanopb versions had a bug in encoding. In order to + * not break decoding of such messages, we cast <=32 bit fields to + * int32_t first to get the sign correct. + */ + if (field->data_size == sizeof(pb_int64_t)) + svalue = (pb_int64_t)value; + else + svalue = (int32_t)value; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t *)dest = svalue; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t *)dest = (int32_t)svalue; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t *)dest = (int_least16_t)svalue; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t *)dest = (int_least8_t)svalue; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != svalue) PB_RETURN_ERROR(stream, "integer too large"); + + return true; } -static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - pb_int64_t value, clamped; - if (!pb_decode_svarint(stream, &value)) - return false; - - /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(pb_int64_t)) - clamped = *(pb_int64_t*)dest = value; - else if (field->data_size == sizeof(int32_t)) - clamped = *(int32_t*)dest = (int32_t)value; - else if (field->data_size == sizeof(int_least16_t)) - clamped = *(int_least16_t*)dest = (int_least16_t)value; - else if (field->data_size == sizeof(int_least8_t)) - clamped = *(int_least8_t*)dest = (int_least8_t)value; - else - PB_RETURN_ERROR(stream, "invalid data_size"); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + pb_uint64_t value, clamped; + if (!pb_decode_varint(stream, &value)) return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_uint64_t)) + clamped = *(pb_uint64_t *)dest = value; + else if (field->data_size == sizeof(uint32_t)) + clamped = *(uint32_t *)dest = (uint32_t)value; + else if (field->data_size == sizeof(uint_least16_t)) + clamped = *(uint_least16_t *)dest = (uint_least16_t)value; + else if (field->data_size == sizeof(uint_least8_t)) + clamped = *(uint_least8_t *)dest = (uint_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} - if (clamped != value) - PB_RETURN_ERROR(stream, "integer too large"); - - return true; +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + pb_int64_t value, clamped; + if (!pb_decode_svarint(stream, &value)) return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t *)dest = value; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t *)dest = (int32_t)value; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t *)dest = (int_least16_t)value; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t *)dest = (int_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) PB_RETURN_ERROR(stream, "integer too large"); + + return true; } -static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - PB_UNUSED(field); - return pb_decode_fixed32(stream, dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + PB_UNUSED(field); + return pb_decode_fixed32(stream, dest); } -static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - PB_UNUSED(field); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + PB_UNUSED(field); #ifndef PB_WITHOUT_64BIT - return pb_decode_fixed64(stream, dest); + return pb_decode_fixed64(stream, dest); #else - PB_UNUSED(dest); - PB_RETURN_ERROR(stream, "no 64bit support"); + PB_UNUSED(dest); + PB_RETURN_ERROR(stream, "no 64bit support"); #endif } -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t size; - size_t alloc_size; - pb_bytes_array_t *bdest; - - if (!pb_decode_varint32(stream, &size)) - return false; - - if (size > PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "bytes overflow"); - - alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); - if (size > alloc_size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + uint32_t size; + size_t alloc_size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) return false; + + if (size > PB_SIZE_MAX) PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { #ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); + PB_RETURN_ERROR(stream, "no malloc support"); #else - if (!allocate_field(stream, dest, alloc_size, 1)) - return false; - bdest = *(pb_bytes_array_t**)dest; + if (!allocate_field(stream, dest, alloc_size, 1)) return false; + bdest = *(pb_bytes_array_t **)dest; #endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "bytes overflow"); - bdest = (pb_bytes_array_t*)dest; - } - - bdest->size = (pb_size_t)size; - return pb_read(stream, bdest->bytes, size); + } else { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t *)dest; + } + + bdest->size = (pb_size_t)size; + return pb_read(stream, bdest->bytes, size); } -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t size; - size_t alloc_size; - bool status; - if (!pb_decode_varint32(stream, &size)) - return false; - - /* Space for null terminator */ - alloc_size = size + 1; - - if (alloc_size < size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { +static bool checkreturn pb_dec_string(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (alloc_size < size) PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { #ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); + PB_RETURN_ERROR(stream, "no malloc support"); #else - if (!allocate_field(stream, dest, alloc_size, 1)) - return false; - dest = *(void**)dest; + if (!allocate_field(stream, dest, alloc_size, 1)) return false; + dest = *(void **)dest; #endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "string overflow"); - } - - status = pb_read(stream, (pb_byte_t*)dest, size); - *((pb_byte_t*)dest + size) = 0; - return status; + } else { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (pb_byte_t *)dest, size); + *((pb_byte_t *)dest + size) = 0; + return status; } -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - bool status; - pb_istream_t substream; - const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - if (field->ptr == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - /* New array entries need to be initialized, while required and optional - * submessages have already been initialized in the top-level pb_decode. */ - if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) - status = pb_decode(&substream, submsg_fields, dest); - else - status = pb_decode_noinit(&substream, submsg_fields, dest); - - if (!pb_close_string_substream(stream, &substream)) - return false; - return status; +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, + const pb_field_t *field, void *dest) { + bool status; + pb_istream_t substream; + const pb_field_t *submsg_fields = (const pb_field_t *)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) return false; + + if (field->ptr == NULL) PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + if (!pb_close_string_substream(stream, &substream)) return false; + return status; } -static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t size; +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, + const pb_field_t *field, + void *dest) { + uint32_t size; - if (!pb_decode_varint32(stream, &size)) - return false; + if (!pb_decode_varint32(stream, &size)) return false; - if (size > PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "bytes overflow"); + if (size > PB_SIZE_MAX) PB_RETURN_ERROR(stream, "bytes overflow"); - if (size == 0) - { - /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ - memset(dest, 0, field->data_size); - return true; - } + if (size == 0) { + /* As a special case, treat empty bytes string as all zeros for + * fixed_length_bytes. */ + memset(dest, 0, field->data_size); + return true; + } - if (size != field->data_size) - PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); + if (size != field->data_size) + PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); - return pb_read(stream, (pb_byte_t*)dest, field->data_size); + return pb_read(stream, (pb_byte_t *)dest, field->data_size); } diff --git a/lib/transport/pb_encode.c b/lib/transport/pb_encode.c index 7a4ba3169..2409323e6 100644 --- a/lib/transport/pb_encode.c +++ b/lib/transport/pb_encode.c @@ -11,39 +11,66 @@ * are propagated correctly. On other compilers and gcc before 3.4.0 just * ignore the annotation. */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn +#if !defined(__GNUC__) || (__GNUC__ < 3) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +#define checkreturn #else - #define checkreturn __attribute__((warn_unused_result)) +#define checkreturn __attribute__((warn_unused_result)) #endif /************************************** * Declarations internal to this file * **************************************/ -typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; - -static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); -static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); -static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, + const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, + size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, + const pb_field_t *field, const void *pData, + size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, + const void *pData); +static bool checkreturn default_extension_encoder( + pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, + const void *pData); static void *pb_const_cast(const void *p); -static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, + const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, + const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, + const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, + const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, + const pb_field_t *field, + const void *src); #ifdef PB_WITHOUT_64BIT #define pb_int64_t int32_t #define pb_uint64_t uint32_t -static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value); +static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, + pb_uint64_t value); #else #define pb_int64_t int64_t #define pb_uint64_t uint64_t @@ -59,65 +86,60 @@ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { &pb_enc_svarint, &pb_enc_fixed32, &pb_enc_fixed64, - + &pb_enc_bytes, &pb_enc_string, &pb_enc_submessage, NULL, /* extensions */ - &pb_enc_fixed_length_bytes -}; + &pb_enc_fixed_length_bytes}; /******************************* * pb_ostream_t implementation * *******************************/ -static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) -{ - size_t i; - pb_byte_t *dest = (pb_byte_t*)stream->state; - stream->state = dest + count; - - for (i = 0; i < count; i++) - dest[i] = buf[i]; - - return true; +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, + size_t count) { + size_t i; + pb_byte_t *dest = (pb_byte_t *)stream->state; + stream->state = dest + count; + + for (i = 0; i < count; i++) dest[i] = buf[i]; + + return true; } -pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) -{ - pb_ostream_t stream; +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) { + pb_ostream_t stream; #ifdef PB_BUFFER_ONLY - stream.callback = (void*)1; /* Just a marker value */ + stream.callback = (void *)1; /* Just a marker value */ #else - stream.callback = &buf_write; + stream.callback = &buf_write; #endif - stream.state = buf; - stream.max_size = bufsize; - stream.bytes_written = 0; + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; #ifndef PB_NO_ERRMSG - stream.errmsg = NULL; + stream.errmsg = NULL; #endif - return stream; + return stream; } -bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) -{ - if (count > 0 && stream->callback != NULL) - { - if (stream->bytes_written + count > stream->max_size) - PB_RETURN_ERROR(stream, "stream full"); +bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, + size_t count) { + if (count > 0 && stream->callback != NULL) { + if (stream->bytes_written + count > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); #ifdef PB_BUFFER_ONLY - if (!buf_write(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#else - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); + if (!buf_write(stream, buf, count)) PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); #endif - } - - stream->bytes_written += count; - return true; + } + + stream->bytes_written += count; + return true; } /************************* @@ -128,442 +150,366 @@ bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t cou * is invalid. See issue #434 and * https://stackoverflow.com/questions/27661768/weird-results-for-conditional */ -static bool safe_read_bool(const void *pSize) -{ - const char *p = (const char *)pSize; - size_t i; - for (i = 0; i < sizeof(bool); i++) - { - if (p[i] != 0) - return true; - } - return false; +static bool safe_read_bool(const void *pSize) { + const char *p = (const char *)pSize; + size_t i; + for (i = 0; i < sizeof(bool); i++) { + if (p[i] != 0) return true; + } + return false; } /* Encode a static array. Handles the size calculations and possible packing. */ -static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, - const void *pData, size_t count, pb_encoder_t func) -{ - size_t i; - const void *p; +static bool checkreturn encode_array(pb_ostream_t *stream, + const pb_field_t *field, const void *pData, + size_t count, pb_encoder_t func) { + size_t i; + const void *p; #ifndef PB_ENCODE_ARRAYS_UNPACKED - size_t size; + size_t size; #endif - if (count == 0) - return true; + if (count == 0) return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); - if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) - PB_RETURN_ERROR(stream, "array max size exceeded"); - #ifndef PB_ENCODE_ARRAYS_UNPACKED - /* We always pack arrays if the datatype allows it. */ - if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) - { - if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) - return false; - - /* Determine the total size of packed array. */ - if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) - { - size = 4 * count; - } - else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - size = 8 * count; - } - else - { - pb_ostream_t sizestream = PB_OSTREAM_SIZING; - p = pData; - for (i = 0; i < count; i++) - { - if (!func(&sizestream, field, p)) - return false; - p = (const char*)p + field->data_size; - } - size = sizestream.bytes_written; - } - - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing.. */ - - /* Write the data */ - p = pData; - for (i = 0; i < count; i++) - { - if (!func(stream, field, p)) - return false; - p = (const char*)p + field->data_size; - } + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) { + size = 4 * count; + } else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) { + size = 8 * count; + } else { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) { + if (!func(&sizestream, field, p)) return false; + p = (const char *)p + field->data_size; + } + size = sizestream.bytes_written; } - else + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) { + if (!func(stream, field, p)) return false; + p = (const char *)p + field->data_size; + } + } else #endif - { - p = pData; - for (i = 0; i < count; i++) - { - if (!pb_encode_tag_for_field(stream, field)) - return false; - - /* Normally the data is stored directly in the array entries, but - * for pointer-type string and bytes fields, the array entries are - * actually pointers themselves also. So we have to dereference once - * more to get to the actual data. */ - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && - (PB_LTYPE(field->type) == PB_LTYPE_STRING || - PB_LTYPE(field->type) == PB_LTYPE_BYTES)) - { - if (!func(stream, field, *(const void* const*)p)) - return false; - } - else - { - if (!func(stream, field, p)) - return false; - } - p = (const char*)p + field->data_size; - } + { + p = pData; + for (i = 0; i < count; i++) { + if (!pb_encode_tag_for_field(stream, field)) return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) { + if (!func(stream, field, *(const void *const *)p)) return false; + } else { + if (!func(stream, field, p)) return false; + } + p = (const char *)p + field->data_size; } - - return true; + } + + return true; } -/* In proto3, all fields are optional and are only encoded if their value is "non-zero". - * This function implements the check for the zero value. */ -static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData) -{ - pb_type_t type = field->type; - const void *pSize = (const char*)pData + field->size_offset; +/* In proto3, all fields are optional and are only encoded if their value is + * "non-zero". This function implements the check for the zero value. */ +static bool pb_check_proto3_default_value(const pb_field_t *field, + const void *pData) { + pb_type_t type = field->type; + const void *pSize = (const char *)pData + field->size_offset; - if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) - { - /* Required proto2 fields inside proto3 submessage, pretty rare case */ - return false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* Repeated fields inside proto3 submessage: present if count != 0 */ - if (field->size_offset != 0) - return *(const pb_size_t*)pSize == 0; - else - return false; /* Fixed length array */ - } - else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - /* Oneof fields */ - return *(const pb_size_t*)pSize == 0; - } - else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) - { - /* Proto2 optional fields inside proto3 submessage */ - return safe_read_bool(pSize) == false; + if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) { + /* Required proto2 fields inside proto3 submessage, pretty rare case */ + return false; + } else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { + /* Repeated fields inside proto3 submessage: present if count != 0 */ + if (field->size_offset != 0) + return *(const pb_size_t *)pSize == 0; + else + return false; /* Fixed length array */ + } else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) { + /* Oneof fields */ + return *(const pb_size_t *)pSize == 0; + } else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) { + /* Proto2 optional fields inside proto3 submessage */ + return safe_read_bool(pSize) == false; + } + + /* Rest is proto3 singular fields */ + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) { + if (PB_LTYPE(type) == PB_LTYPE_BYTES) { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t *)pData; + return bytes->size == 0; + } else if (PB_LTYPE(type) == PB_LTYPE_STRING) { + return *(const char *)pData == '\0'; + } else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) { + /* Fixed length bytes is only empty if its length is fixed + * as 0. Which would be pretty strange, but we can check + * it anyway. */ + return field->data_size == 0; + } else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) { + /* Check all fields in the submessage to find if any of them + * are non-zero. The comparison cannot be done byte-per-byte + * because the C struct may contain padding bytes that must + * be skipped. + */ + pb_field_iter_t iter; + if (pb_field_iter_begin(&iter, (const pb_field_t *)field->ptr, + pb_const_cast(pData))) { + do { + if (!pb_check_proto3_default_value(iter.pos, iter.pData)) { + return false; + } + } while (pb_field_iter_next(&iter)); + } + return true; } + } - /* Rest is proto3 singular fields */ - - if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - if (PB_LTYPE(type) == PB_LTYPE_BYTES) - { - const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; - return bytes->size == 0; - } - else if (PB_LTYPE(type) == PB_LTYPE_STRING) - { - return *(const char*)pData == '\0'; - } - else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) - { - /* Fixed length bytes is only empty if its length is fixed - * as 0. Which would be pretty strange, but we can check - * it anyway. */ - return field->data_size == 0; - } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) - { - /* Check all fields in the submessage to find if any of them - * are non-zero. The comparison cannot be done byte-per-byte - * because the C struct may contain padding bytes that must - * be skipped. - */ - pb_field_iter_t iter; - if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData))) - { - do - { - if (!pb_check_proto3_default_value(iter.pos, iter.pData)) - { - return false; - } - } while (pb_field_iter_next(&iter)); - } - return true; - } + { + /* Catch-all branch that does byte-per-byte comparison for zero value. + * + * This is for all pointer fields, and for static PB_LTYPE_VARINT, + * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also + * callback fields. These all have integer or pointer value which + * can be compared with 0. + */ + pb_size_t i; + const char *p = (const char *)pData; + for (i = 0; i < field->data_size; i++) { + if (p[i] != 0) { + return false; + } } - - { - /* Catch-all branch that does byte-per-byte comparison for zero value. - * - * This is for all pointer fields, and for static PB_LTYPE_VARINT, - * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also - * callback fields. These all have integer or pointer value which - * can be compared with 0. - */ - pb_size_t i; - const char *p = (const char*)pData; - for (i = 0; i < field->data_size; i++) - { - if (p[i] != 0) - { - return false; - } - } - - return true; - } + + return true; + } } /* Encode a field with static or pointer allocation, i.e. one whose data * is available to the encoder directly. */ static bool checkreturn encode_basic_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - pb_encoder_t func; - bool implicit_has; - const void *pSize = &implicit_has; - - func = PB_ENCODERS[PB_LTYPE(field->type)]; - - if (field->size_offset) - { - /* Static optional, repeated or oneof field */ - pSize = (const char*)pData + field->size_offset; - } - else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) - { - /* Proto3 style field, optional but without explicit has_ field. */ - implicit_has = !pb_check_proto3_default_value(field, pData); - } - else - { - /* Required field, always present */ - implicit_has = true; - } + const pb_field_t *field, + const void *pData) { + pb_encoder_t func; + bool implicit_has; + const void *pSize = &implicit_has; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) { + /* Static optional, repeated or oneof field */ + pSize = (const char *)pData + field->size_offset; + } else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } else { + /* Required field, always present */ + implicit_has = true; + } - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - /* pData is a pointer to the field, which contains pointer to - * the data. If the 2nd pointer is NULL, it is interpreted as if - * the has_field was false. - */ - pData = *(const void* const*)pData; - implicit_has = (pData != NULL); - } + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + pData = *(const void *const *)pData; + implicit_has = (pData != NULL); + } - switch (PB_HTYPE(field->type)) - { - case PB_HTYPE_REQUIRED: - if (!pData) - PB_RETURN_ERROR(stream, "missing required field"); - if (!pb_encode_tag_for_field(stream, field)) - return false; - if (!func(stream, field, pData)) - return false; - break; - - case PB_HTYPE_OPTIONAL: - if (safe_read_bool(pSize)) - { - if (!pb_encode_tag_for_field(stream, field)) - return false; - - if (!func(stream, field, pData)) - return false; - } - break; - - case PB_HTYPE_REPEATED: { - pb_size_t count; - if (field->size_offset != 0) { - count = *(const pb_size_t*)pSize; - } else { - count = field->array_size; - } - if (!encode_array(stream, field, pData, count, func)) - return false; - break; - } - - case PB_HTYPE_ONEOF: - if (*(const pb_size_t*)pSize == field->tag) - { - if (!pb_encode_tag_for_field(stream, field)) - return false; - - if (!func(stream, field, pData)) - return false; - } - break; - - default: - PB_RETURN_ERROR(stream, "invalid field type"); + switch (PB_HTYPE(field->type)) { + case PB_HTYPE_REQUIRED: + if (!pData) PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) return false; + if (!func(stream, field, pData)) return false; + break; + + case PB_HTYPE_OPTIONAL: + if (safe_read_bool(pSize)) { + if (!pb_encode_tag_for_field(stream, field)) return false; + + if (!func(stream, field, pData)) return false; + } + break; + + case PB_HTYPE_REPEATED: { + pb_size_t count; + if (field->size_offset != 0) { + count = *(const pb_size_t *)pSize; + } else { + count = field->array_size; + } + if (!encode_array(stream, field, pData, count, func)) return false; + break; } - - return true; + + case PB_HTYPE_ONEOF: + if (*(const pb_size_t *)pSize == field->tag) { + if (!pb_encode_tag_for_field(stream, field)) return false; + + if (!func(stream, field, pData)) return false; + } + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; } /* Encode a field with callback semantics. This means that a user function is * called to provide and encode the actual data. */ static bool checkreturn encode_callback_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - const pb_callback_t *callback = (const pb_callback_t*)pData; - + const pb_field_t *field, + const void *pData) { + const pb_callback_t *callback = (const pb_callback_t *)pData; + #ifdef PB_OLD_CALLBACK_STYLE - const void *arg = callback->arg; + const void *arg = callback->arg; #else - void * const *arg = &(callback->arg); -#endif - - if (callback->funcs.encode != NULL) - { - if (!callback->funcs.encode(stream, field, arg)) - PB_RETURN_ERROR(stream, "callback error"); - } - return true; + void *const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; } /* Encode a single field of any callback or static type. */ static bool checkreturn encode_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - switch (PB_ATYPE(field->type)) - { - case PB_ATYPE_STATIC: - case PB_ATYPE_POINTER: - return encode_basic_field(stream, field, pData); - - case PB_ATYPE_CALLBACK: - return encode_callback_field(stream, field, pData); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } + const pb_field_t *field, + const void *pData) { + switch (PB_ATYPE(field->type)) { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } } /* Default handler for extension fields. Expects to have a pb_field_t * pointer in the extension->type->arg field. */ -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, - const pb_extension_t *extension) -{ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - /* For pointer extensions, the pointer is stored directly - * in the extension structure. This avoids having an extra - * indirection. */ - return encode_field(stream, field, &extension->dest); - } - else - { - return encode_field(stream, field, extension->dest); - } +static bool checkreturn default_extension_encoder( + pb_ostream_t *stream, const pb_extension_t *extension) { + const pb_field_t *field = (const pb_field_t *)extension->type->arg; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + return encode_field(stream, field, &extension->dest); + } else { + return encode_field(stream, field, extension->dest); + } } /* Walk through all the registered extensions and give them a chance * to encode themselves. */ static bool checkreturn encode_extension_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - const pb_extension_t *extension = *(const pb_extension_t* const *)pData; - PB_UNUSED(field); - - while (extension) - { - bool status; - if (extension->type->encode) - status = extension->type->encode(stream, extension); - else - status = default_extension_encoder(stream, extension); - - if (!status) - return false; - - extension = extension->next; - } - - return true; + const pb_field_t *field, + const void *pData) { + const pb_extension_t *extension = *(const pb_extension_t *const *)pData; + PB_UNUSED(field); + + while (extension) { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) return false; + + extension = extension->next; + } + + return true; } /********************* * Encode all fields * *********************/ -static void *pb_const_cast(const void *p) -{ - /* Note: this casts away const, in order to use the common field iterator - * logic for both encoding and decoding. */ - union { - void *p1; - const void *p2; - } t; - t.p2 = p; - return t.p1; -} - -bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - pb_field_iter_t iter; - if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) - return true; /* Empty message type */ - - do { - if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) - { - /* Special case for the extension field placeholder */ - if (!encode_extension_field(stream, iter.pos, iter.pData)) - return false; - } - else - { - /* Regular field */ - if (!encode_field(stream, iter.pos, iter.pData)) - return false; - } - } while (pb_field_iter_next(&iter)); - - return true; +static void *pb_const_cast(const void *p) { + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct) { + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) + return true; /* Empty message type */ + + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, iter.pos, iter.pData)) return false; + } else { + /* Regular field */ + if (!encode_field(stream, iter.pos, iter.pData)) return false; + } + } while (pb_field_iter_next(&iter)); + + return true; } -bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - return pb_encode_submessage(stream, fields, src_struct); +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct) { + return pb_encode_submessage(stream, fields, src_struct); } -bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - const pb_byte_t zero = 0; +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], + const void *src_struct) { + const pb_byte_t zero = 0; - if (!pb_encode(stream, fields, src_struct)) - return false; + if (!pb_encode(stream, fields, src_struct)) return false; - return pb_write(stream, &zero, 1); + return pb_write(stream, &zero, 1); } -bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) -{ - pb_ostream_t stream = PB_OSTREAM_SIZING; - - if (!pb_encode(&stream, fields, src_struct)) - return false; - - *size = stream.bytes_written; - return true; +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], + const void *src_struct) { + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) return false; + + *size = stream.bytes_written; + return true; } /******************** @@ -571,21 +517,21 @@ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *sr ********************/ #ifdef PB_WITHOUT_64BIT -bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value) -{ +bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, + pb_uint64_t value) { pb_byte_t buffer[10]; size_t i = 0; - size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */ + size_t compensation = 32; /* we need to compensate 32 bits all set to 1 */ - while (value) - { + while (value) { buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); value >>= 7; - if (compensation) - { + if (compensation) { /* re-set all the compensation bits we can or need */ size_t bits = compensation > 7 ? 7 : compensation; - value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */ + value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) + << 25); /* set the number of bits needed on the + lowest of the most significant 7 bits */ compensation -= bits; } i++; @@ -596,307 +542,297 @@ bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t val } #endif -bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) -{ - pb_byte_t buffer[10]; - size_t i = 0; - - if (value <= 0x7F) - { - pb_byte_t v = (pb_byte_t)value; - return pb_write(stream, &v, 1); - } - - while (value) - { - buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); - value >>= 7; - i++; - } - buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ - - return pb_write(stream, buffer, i); +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) { + pb_byte_t buffer[10]; + size_t i = 0; + + if (value <= 0x7F) { + pb_byte_t v = (pb_byte_t)value; + return pb_write(stream, &v, 1); + } + + while (value) { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); } -bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) -{ - pb_uint64_t zigzagged; - if (value < 0) - zigzagged = ~((pb_uint64_t)value << 1); - else - zigzagged = (pb_uint64_t)value << 1; - - return pb_encode_varint(stream, zigzagged); +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) { + pb_uint64_t zigzagged; + if (value < 0) + zigzagged = ~((pb_uint64_t)value << 1); + else + zigzagged = (pb_uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); } -bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) -{ - uint32_t val = *(const uint32_t*)value; - pb_byte_t bytes[4]; - bytes[0] = (pb_byte_t)(val & 0xFF); - bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); - bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); - bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); - return pb_write(stream, bytes, 4); +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) { + uint32_t val = *(const uint32_t *)value; + pb_byte_t bytes[4]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + return pb_write(stream, bytes, 4); } #ifndef PB_WITHOUT_64BIT -bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) -{ - uint64_t val = *(const uint64_t*)value; - pb_byte_t bytes[8]; - bytes[0] = (pb_byte_t)(val & 0xFF); - bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); - bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); - bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); - bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); - bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); - bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); - bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); - return pb_write(stream, bytes, 8); +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) { + uint64_t val = *(const uint64_t *)value; + pb_byte_t bytes[8]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); + bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); + bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); + bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); + return pb_write(stream, bytes, 8); } #endif -bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) -{ - pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; - return pb_encode_varint(stream, tag); -} - -bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) -{ - pb_wire_type_t wiretype; - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - wiretype = PB_WT_VARINT; - break; - - case PB_LTYPE_FIXED32: - wiretype = PB_WT_32BIT; - break; - - case PB_LTYPE_FIXED64: - wiretype = PB_WT_64BIT; - break; - - case PB_LTYPE_BYTES: - case PB_LTYPE_STRING: - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_FIXED_LENGTH_BYTES: - wiretype = PB_WT_STRING; - break; - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } - - return pb_encode_tag(stream, wiretype, field->tag); +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, + uint32_t field_number) { + pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, + const pb_field_t *field) { + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) { + case PB_LTYPE_BOOL: + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); } -bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) -{ - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - return pb_write(stream, buffer, size); +bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, + size_t size) { + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; + + return pb_write(stream, buffer, size); } -bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - /* First calculate the message size using a non-writing substream. */ - pb_ostream_t substream = PB_OSTREAM_SIZING; - size_t size; - bool status; - - if (!pb_encode(&substream, fields, src_struct)) - { +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, + const pb_field_t fields[], + const void *src_struct) { + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) { #ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; + stream->errmsg = substream.errmsg; #endif - return false; - } - - size = substream.bytes_written; - - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing */ - - if (stream->bytes_written + size > stream->max_size) - PB_RETURN_ERROR(stream, "stream full"); - - /* Use a substream to verify that a callback doesn't write more than - * what it did the first time. */ - substream.callback = stream->callback; - substream.state = stream->state; - substream.max_size = size; - substream.bytes_written = 0; + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; #ifndef PB_NO_ERRMSG - substream.errmsg = NULL; + substream.errmsg = NULL; #endif - - status = pb_encode(&substream, fields, src_struct); - - stream->bytes_written += substream.bytes_written; - stream->state = substream.state; + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; #ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; + stream->errmsg = substream.errmsg; #endif - - if (substream.bytes_written != size) - PB_RETURN_ERROR(stream, "submsg size changed"); - - return status; + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; } /* Field encoders */ -static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - uint32_t value = (uint32_t)safe_read_bool(src); - PB_UNUSED(field); - return pb_encode_varint(stream, value); -} - -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - pb_int64_t value = 0; - - if (field->data_size == sizeof(int_least8_t)) - value = *(const int_least8_t*)src; - else if (field->data_size == sizeof(int_least16_t)) - value = *(const int_least16_t*)src; - else if (field->data_size == sizeof(int32_t)) - value = *(const int32_t*)src; - else if (field->data_size == sizeof(pb_int64_t)) - value = *(const pb_int64_t*)src; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, + const pb_field_t *field, const void *src) { + uint32_t value = (uint32_t)safe_read_bool(src); + PB_UNUSED(field); + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t *)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t *)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t *)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t *)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + #ifdef PB_WITHOUT_64BIT - if (value < 0) - return pb_encode_negative_varint(stream, (pb_uint64_t)value); - else + if (value < 0) + return pb_encode_negative_varint(stream, (pb_uint64_t)value); + else #endif - return pb_encode_varint(stream, (pb_uint64_t)value); -} - -static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - pb_uint64_t value = 0; - - if (field->data_size == sizeof(uint_least8_t)) - value = *(const uint_least8_t*)src; - else if (field->data_size == sizeof(uint_least16_t)) - value = *(const uint_least16_t*)src; - else if (field->data_size == sizeof(uint32_t)) - value = *(const uint32_t*)src; - else if (field->data_size == sizeof(pb_uint64_t)) - value = *(const pb_uint64_t*)src; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - return pb_encode_varint(stream, value); -} - -static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - pb_int64_t value = 0; - - if (field->data_size == sizeof(int_least8_t)) - value = *(const int_least8_t*)src; - else if (field->data_size == sizeof(int_least16_t)) - value = *(const int_least16_t*)src; - else if (field->data_size == sizeof(int32_t)) - value = *(const int32_t*)src; - else if (field->data_size == sizeof(pb_int64_t)) - value = *(const pb_int64_t*)src; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - return pb_encode_svarint(stream, value); -} - -static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - PB_UNUSED(field); + return pb_encode_varint(stream, (pb_uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + pb_uint64_t value = 0; + + if (field->data_size == sizeof(uint_least8_t)) + value = *(const uint_least8_t *)src; + else if (field->data_size == sizeof(uint_least16_t)) + value = *(const uint_least16_t *)src; + else if (field->data_size == sizeof(uint32_t)) + value = *(const uint32_t *)src; + else if (field->data_size == sizeof(pb_uint64_t)) + value = *(const pb_uint64_t *)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t *)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t *)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t *)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t *)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + PB_UNUSED(field); #ifndef PB_WITHOUT_64BIT - return pb_encode_fixed64(stream, src); + return pb_encode_fixed64(stream, src); #else - PB_UNUSED(src); - PB_RETURN_ERROR(stream, "no 64bit support"); + PB_UNUSED(src); + PB_RETURN_ERROR(stream, "no 64bit support"); #endif } -static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - PB_UNUSED(field); - return pb_encode_fixed32(stream, src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + PB_UNUSED(field); + return pb_encode_fixed32(stream, src); } -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - const pb_bytes_array_t *bytes = NULL; +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, + const pb_field_t *field, const void *src) { + const pb_bytes_array_t *bytes = NULL; - bytes = (const pb_bytes_array_t*)src; - - if (src == NULL) - { - /* Treat null pointer as an empty bytes field */ - return pb_encode_string(stream, NULL, 0); - } - - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) - { - PB_RETURN_ERROR(stream, "bytes size exceeded"); - } - - return pb_encode_string(stream, bytes->bytes, bytes->size); -} - -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - size_t size = 0; - size_t max_size = field->data_size; - const char *p = (const char*)src; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - max_size = (size_t)-1; - - if (src == NULL) - { - size = 0; /* Treat null pointer as an empty string */ - } - else - { - /* strnlen() is not always available, so just use a loop */ - while (size < max_size && *p != '\0') - { - size++; - p++; - } - } + bytes = (const pb_bytes_array_t *)src; + + if (src == NULL) { + /* Treat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } - return pb_encode_string(stream, (const pb_byte_t*)src, size); + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); } -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - if (field->ptr == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char *)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) max_size = (size_t)-1; + + if (src == NULL) { + size = 0; /* Treat null pointer as an empty string */ + } else { + /* strnlen() is not always available, so just use a loop */ + while (size < max_size && *p != '\0') { + size++; + p++; + } + } + + return pb_encode_string(stream, (const pb_byte_t *)src, size); } -static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + if (field->ptr == NULL) PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t *)field->ptr, src); } +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, + const pb_field_t *field, + const void *src) { + return pb_encode_string(stream, (const pb_byte_t *)src, field->data_size); +} diff --git a/lib/variant/keepkey/keepkey.c b/lib/variant/keepkey/keepkey.c index 880c8c22b..616a7822a 100644 --- a/lib/variant/keepkey/keepkey.c +++ b/lib/variant/keepkey/keepkey.c @@ -3,7 +3,4 @@ #include "keepkey/board/timer.h" #include "keepkey/board/variant.h" -const VariantInfo variant_keepkey = { - VARIANTINFO_KEEPKEY -}; - +const VariantInfo variant_keepkey = {VARIANTINFO_KEEPKEY}; diff --git a/lib/variant/keepkey/logo.c b/lib/variant/keepkey/logo.c index 8bbc537ca..e3fe0115c 100644 --- a/lib/variant/keepkey/logo.c +++ b/lib/variant/keepkey/logo.c @@ -19,64 +19,135 @@ #include "keepkey/board/resources.h" -static const uint8_t kk_logo_1_data[1189] = -{ - 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x34, 0x00, 0x03, 0xff, 0xff, 0xdd, 0x34, 0x00, 0xff, 0xe2, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xfd, 0x11, 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, 0x07, 0x05, 0x00, 0xfd, 0x11, 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, 0x07, 0x03, 0x00, 0xf4, 0xb5, 0xf7, 0xeb, 0x58, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x07, 0x02, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x1c, 0xdd, 0x07, 0xff, 0xfe, 0xb5, 0x07, 0x03, 0x00, 0xfe, 0x1c, 0xdd, 0x07, 0xff, 0xfe, 0xb5, 0x07, 0x02, 0x00, 0x03, 0xff, 0x02, 0xdd, 0x06, 0xff, 0xfd, 0xdd, 0x1c, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0xff, 0xe2, 0x0b, 0xff, 0xfe, 0xb5, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x58, 0x02, 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, 0xfe, 0x1c, 0xeb, 0x02, 0xff, 0xfd, 0x11, 0x00, 0x58, 0x02, 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, 0xfe, 0x1c, 0xeb, 0x02, 0xff, 0xff, 0x11, 0x02, 0x00, 0x03, 0xff, 0xfe, 0xa3, 0x33, 0x02, 0x07, 0xfe, 0x33, 0xdd, 0x02, 0xff, 0xfe, 0xf7, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x8f, 0x05, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xfd, 0x58, 0x00, 0xa3, 0x02, 0xff, 0xff, 0x8f, 0x05, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x58, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x58, 0x03, 0xff, 0xff, 0x00, 0x08, 0xff, 0xff, 0x79, 0x05, 0x00, 0xff, 0xdd, 0x02, 0xff, 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xfd, 0x8f, 0x00, 0xdd, 0x02, 0xff, 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x1c, 0x03, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xfe, 0xb5, 0x00, 0x0c, 0xff, 0xff, 0xb5, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x07, 0x03, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xfe, 0xa3, 0x00, 0x0c, 0xff, 0xff, 0xa3, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x07, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x8f, 0x03, 0xff, 0xff, 0x79, 0x05, 0x00, 0xfd, 0xe2, 0xff, 0xf7, 0x0b, 0x00, 0xfd, 0xe2, 0xff, 0xf7, 0x0c, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x1c, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x11, 0x0a, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x11, 0x0b, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x58, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x04, 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x02, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x04, 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x03, 0x00, 0x03, 0xff, 0xfe, 0xa3, 0x33, 0x02, 0x07, 0xfe, 0x33, 0xdd, 0x02, 0xff, 0xfe, 0xf7, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xeb, 0x02, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0xfe, 0x07, 0xeb, 0x02, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x02, 0xff, 0xff, 0x8f, 0x03, 0x00, 0x0b, 0xff, 0xfe, 0xb5, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, 0x00, 0x03, 0xff, 0xff, 0xdd, 0x06, 0xff, 0xfd, 0xdd, 0x1c, 0x00, 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x05, 0x00, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x04, 0x00, 0x03, 0xff, 0xf8, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x07, 0x02, 0x00, 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xfd, 0x11, 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, 0x07, 0x02, 0x00, 0x05, 0xff, 0x04, 0x00, 0x05, 0xff, 0x02, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x1c, 0xdd, 0x07, 0xff, 0xfd, 0xb5, 0x07, 0x00, 0x05, 0xff, 0x04, 0x00, 0x05, 0xff, 0x02, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, 0x03, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x02, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x58, 0x02, 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, 0xfe, 0x1c, 0xeb, 0x02, 0xff, 0xff, 0x11, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x8f, 0x05, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x58, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x08, 0xff, 0xff, 0x79, 0x05, 0x00, 0xff, 0xdd, 0x02, 0xff, 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xff, 0xb5, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xff, 0xa3, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x8f, 0x03, 0xff, 0xff, 0x79, 0x05, 0x00, 0xfd, 0xe2, 0xff, 0xf7, 0x0c, 0x00, 0x03, 0xff, 0xff, 0x07, 0x05, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x11, 0x0b, 0x00, 0xff, 0xeb, 0x02, 0xff, 0xff, 0x1c, 0x04, 0x00, 0xff, 0x11, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x04, 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x03, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x58, 0x03, 0x00, 0xfe, 0x07, 0xb5, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xeb, 0x02, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x02, 0xff, 0xff, 0x8f, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xfb, 0xf7, 0xa3, 0x8f, 0xb5, 0xe2, 0x04, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, 0x00, 0xfe, 0x07, 0xdd, 0x06, 0xff, 0xff, 0x8f, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x05, 0x00, 0xf8, 0x11, 0xa3, 0xe2, 0xff, 0xeb, 0xb5, 0x58, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x34, 0x00, 0xff, 0xe2, 0x03, 0xff, 0x34, 0x00, 0x03, 0xff, 0xff, 0xdd, 0x34, 0x00, 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x7f, 0x00, 0x37, 0x00 -}; -static const Image kk_logo_1_image = {56, 49, sizeof(kk_logo_1_data), kk_logo_1_data}; +static const uint8_t kk_logo_1_data[1189] = { + 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x34, 0x00, 0x03, 0xff, 0xff, 0xdd, 0x34, + 0x00, 0xff, 0xe2, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, + 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, + 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xfd, 0x11, + 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, 0x07, 0x05, 0x00, 0xfd, 0x11, + 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, 0x07, 0x03, 0x00, 0xf4, 0xb5, + 0xf7, 0xeb, 0x58, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x07, 0x02, + 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, 0x03, 0x00, + 0xfe, 0x1c, 0xdd, 0x07, 0xff, 0xfe, 0xb5, 0x07, 0x03, 0x00, 0xfe, 0x1c, + 0xdd, 0x07, 0xff, 0xfe, 0xb5, 0x07, 0x02, 0x00, 0x03, 0xff, 0x02, 0xdd, + 0x06, 0xff, 0xfd, 0xdd, 0x1c, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, + 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xfc, 0xb5, + 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0xfe, 0x07, 0xcd, + 0x03, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, 0x02, + 0x00, 0xff, 0xe2, 0x0b, 0xff, 0xfe, 0xb5, 0x00, 0x03, 0xff, 0x02, 0x00, + 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x58, 0x02, + 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, 0xfe, 0x1c, 0xeb, 0x02, 0xff, 0xfd, + 0x11, 0x00, 0x58, 0x02, 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, 0xfe, 0x1c, + 0xeb, 0x02, 0xff, 0xff, 0x11, 0x02, 0x00, 0x03, 0xff, 0xfe, 0xa3, 0x33, + 0x02, 0x07, 0xfe, 0x33, 0xdd, 0x02, 0xff, 0xfe, 0xf7, 0x00, 0x03, 0xff, + 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xa3, + 0x02, 0xff, 0xff, 0x8f, 0x05, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xfd, 0x58, + 0x00, 0xa3, 0x02, 0xff, 0xff, 0x8f, 0x05, 0x00, 0xff, 0xa3, 0x02, 0xff, + 0xff, 0x58, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x58, 0x03, 0xff, + 0xff, 0x00, 0x08, 0xff, 0xff, 0x79, 0x05, 0x00, 0xff, 0xdd, 0x02, 0xff, + 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xfd, 0x8f, 0x00, 0xdd, + 0x02, 0xff, 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, + 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x1c, 0x03, 0xff, 0xff, 0x00, + 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xfe, 0xb5, 0x00, 0x0c, + 0xff, 0xff, 0xb5, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x07, 0x03, + 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xfe, + 0xa3, 0x00, 0x0c, 0xff, 0xff, 0xa3, 0x02, 0x00, 0x03, 0xff, 0x05, 0x00, + 0xff, 0x07, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x8f, 0x03, + 0xff, 0xff, 0x79, 0x05, 0x00, 0xfd, 0xe2, 0xff, 0xf7, 0x0b, 0x00, 0xfd, + 0xe2, 0xff, 0xf7, 0x0c, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, 0x1c, 0x03, + 0xff, 0xff, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, 0xff, 0xff, + 0x79, 0x04, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x11, 0x0a, 0x00, 0xff, + 0xb5, 0x02, 0xff, 0xff, 0x11, 0x0b, 0x00, 0x03, 0xff, 0x05, 0x00, 0xff, + 0x58, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, + 0x03, 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, + 0x04, 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x02, 0x00, 0xff, 0x79, 0x02, + 0xff, 0xff, 0x8f, 0x04, 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x03, 0x00, + 0x03, 0xff, 0xfe, 0xa3, 0x33, 0x02, 0x07, 0xfe, 0x33, 0xdd, 0x02, 0xff, + 0xfe, 0xf7, 0x00, 0x03, 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, + 0x02, 0x00, 0xfe, 0x07, 0xeb, 0x02, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, + 0xe2, 0x02, 0xff, 0xff, 0x8f, 0x02, 0x00, 0xfe, 0x07, 0xeb, 0x02, 0xff, + 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x02, 0xff, 0xff, 0x8f, 0x03, 0x00, + 0x0b, 0xff, 0xfe, 0xb5, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, + 0x03, 0xff, 0x03, 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, + 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, 0x00, 0x03, 0xff, + 0xff, 0xdd, 0x06, 0xff, 0xfd, 0xdd, 0x1c, 0x00, 0x03, 0xff, 0x05, 0x00, + 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, + 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x05, 0x00, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, + 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x04, 0x00, 0x03, 0xff, 0xf8, 0x11, 0x8f, + 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x07, 0x02, 0x00, 0x03, 0xff, 0x28, 0x00, + 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, + 0x03, 0xff, 0x28, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x28, 0x00, + 0x03, 0xff, 0x0a, 0x00, 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, + 0xff, 0x04, 0x00, 0xfd, 0x11, 0x8f, 0xe2, 0x03, 0xff, 0xfd, 0xdd, 0x79, + 0x07, 0x02, 0x00, 0x05, 0xff, 0x04, 0x00, 0x05, 0xff, 0x02, 0x00, 0x03, + 0xff, 0x0a, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, 0x03, 0xff, + 0x03, 0x00, 0xfe, 0x1c, 0xdd, 0x07, 0xff, 0xfd, 0xb5, 0x07, 0x00, 0x05, + 0xff, 0x04, 0x00, 0x05, 0xff, 0x02, 0x00, 0x03, 0xff, 0x0a, 0x00, 0x03, + 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, + 0xcd, 0x03, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x02, 0xff, 0xff, 0x8f, + 0x03, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x02, 0x00, 0x03, 0xff, + 0x0a, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, 0xff, 0xff, + 0x79, 0x03, 0x00, 0xff, 0x58, 0x02, 0xff, 0xfe, 0xf7, 0x33, 0x03, 0x00, + 0xfe, 0x1c, 0xeb, 0x02, 0xff, 0xff, 0x11, 0x02, 0x00, 0x03, 0xff, 0x06, + 0x00, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, 0x03, + 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x8f, 0x05, + 0x00, 0xff, 0xa3, 0x02, 0xff, 0xff, 0x58, 0x02, 0x00, 0x03, 0xff, 0x06, + 0x00, 0x03, 0xff, 0x0f, 0x00, 0x08, 0xff, 0xff, 0x79, 0x05, 0x00, 0xff, + 0xdd, 0x02, 0xff, 0xff, 0x33, 0x05, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, + 0x8f, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x07, + 0xff, 0xff, 0x79, 0x06, 0x00, 0x0c, 0xff, 0xff, 0xb5, 0x02, 0x00, 0x03, + 0xff, 0x06, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x07, 0xff, 0xff, 0x79, 0x06, + 0x00, 0x0c, 0xff, 0xff, 0xa3, 0x02, 0x00, 0x03, 0xff, 0x06, 0x00, 0x03, + 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x8f, 0x03, 0xff, 0xff, 0x79, + 0x05, 0x00, 0xfd, 0xe2, 0xff, 0xf7, 0x0c, 0x00, 0x03, 0xff, 0xff, 0x07, + 0x05, 0x00, 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0xfd, 0x00, 0x07, 0xb5, + 0x03, 0xff, 0xff, 0x79, 0x04, 0x00, 0xff, 0xb5, 0x02, 0xff, 0xff, 0x11, + 0x0b, 0x00, 0xff, 0xeb, 0x02, 0xff, 0xff, 0x1c, 0x04, 0x00, 0xff, 0x11, + 0x03, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x02, 0x00, 0xfe, 0x07, 0xcd, 0x03, + 0xff, 0xff, 0x79, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xff, 0x8f, 0x04, + 0x00, 0xfc, 0x07, 0x58, 0x8f, 0x11, 0x03, 0x00, 0xff, 0xb5, 0x02, 0xff, + 0xff, 0x58, 0x03, 0x00, 0xfe, 0x07, 0xb5, 0x03, 0xff, 0x0f, 0x00, 0x03, + 0xff, 0x03, 0x00, 0xfe, 0x11, 0xdd, 0x04, 0xff, 0x02, 0x00, 0xfe, 0x07, + 0xeb, 0x02, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x02, 0xff, 0xff, + 0x8f, 0x03, 0x00, 0xff, 0x79, 0x02, 0xff, 0xfb, 0xf7, 0xa3, 0x8f, 0xb5, + 0xe2, 0x04, 0xff, 0x0f, 0x00, 0x03, 0xff, 0x04, 0x00, 0xfe, 0x1c, 0xeb, + 0x03, 0xff, 0x03, 0x00, 0xfe, 0x33, 0xf7, 0x08, 0xff, 0xff, 0xa3, 0x03, + 0x00, 0xfe, 0x07, 0xdd, 0x06, 0xff, 0xff, 0x8f, 0x03, 0xff, 0x0f, 0x00, + 0x03, 0xff, 0x05, 0x00, 0xfe, 0x33, 0xf7, 0x02, 0xff, 0x04, 0x00, 0xf7, + 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x05, 0x00, 0xf8, + 0x11, 0xa3, 0xe2, 0xff, 0xeb, 0xb5, 0x58, 0x00, 0x03, 0xff, 0x35, 0x00, + 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, 0x03, 0xff, 0x35, 0x00, + 0x03, 0xff, 0x34, 0x00, 0xff, 0xe2, 0x03, 0xff, 0x34, 0x00, 0x03, 0xff, + 0xff, 0xdd, 0x34, 0x00, 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x7f, 0x00, 0x37, + 0x00}; +static const Image kk_logo_1_image = {56, 49, sizeof(kk_logo_1_data), + kk_logo_1_data}; const VariantAnimation kk_logo = { - 21, - { - {100, 9, 25, 0, &kk_logo_1_image}, - {100, 9, 25, 5, &kk_logo_1_image}, - {100, 9, 25, 10, &kk_logo_1_image}, - {100, 9, 25, 15, &kk_logo_1_image}, - {100, 9, 25, 20, &kk_logo_1_image}, - {100, 9, 25, 25, &kk_logo_1_image}, - {100, 9, 25, 30, &kk_logo_1_image}, - {100, 9, 25, 35, &kk_logo_1_image}, - {100, 9, 25, 40, &kk_logo_1_image}, - {100, 9, 25, 45, &kk_logo_1_image}, - {100, 9, 25, 50, &kk_logo_1_image}, - {100, 9, 25, 55, &kk_logo_1_image}, - {100, 9, 25, 60, &kk_logo_1_image}, - {100, 9, 25, 65, &kk_logo_1_image}, - {100, 9, 25, 70, &kk_logo_1_image}, - {100, 9, 25, 75, &kk_logo_1_image}, - {100, 9, 25, 80, &kk_logo_1_image}, - {100, 9, 25, 85, &kk_logo_1_image}, - {100, 9, 25, 90, &kk_logo_1_image}, - {100, 9, 25, 95, &kk_logo_1_image}, - {100, 9, 25, 100, &kk_logo_1_image} - } -}; + 21, {{100, 9, 25, 0, &kk_logo_1_image}, {100, 9, 25, 5, &kk_logo_1_image}, + {100, 9, 25, 10, &kk_logo_1_image}, {100, 9, 25, 15, &kk_logo_1_image}, + {100, 9, 25, 20, &kk_logo_1_image}, {100, 9, 25, 25, &kk_logo_1_image}, + {100, 9, 25, 30, &kk_logo_1_image}, {100, 9, 25, 35, &kk_logo_1_image}, + {100, 9, 25, 40, &kk_logo_1_image}, {100, 9, 25, 45, &kk_logo_1_image}, + {100, 9, 25, 50, &kk_logo_1_image}, {100, 9, 25, 55, &kk_logo_1_image}, + {100, 9, 25, 60, &kk_logo_1_image}, {100, 9, 25, 65, &kk_logo_1_image}, + {100, 9, 25, 70, &kk_logo_1_image}, {100, 9, 25, 75, &kk_logo_1_image}, + {100, 9, 25, 80, &kk_logo_1_image}, {100, 9, 25, 85, &kk_logo_1_image}, + {100, 9, 25, 90, &kk_logo_1_image}, {100, 9, 25, 95, &kk_logo_1_image}, + {100, 9, 25, 100, &kk_logo_1_image}}}; const VariantAnimation kk_logo_reversed = { 21, - { - {100, 9, 25, 100, &kk_logo_1_image}, - {100, 9, 25, 95, &kk_logo_1_image}, - {100, 9, 25, 90, &kk_logo_1_image}, - {100, 9, 25, 85, &kk_logo_1_image}, - {100, 9, 25, 80, &kk_logo_1_image}, - {100, 9, 25, 75, &kk_logo_1_image}, - {100, 9, 25, 70, &kk_logo_1_image}, - {100, 9, 25, 65, &kk_logo_1_image}, - {100, 9, 25, 60, &kk_logo_1_image}, - {100, 9, 25, 55, &kk_logo_1_image}, - {100, 9, 25, 50, &kk_logo_1_image}, - {100, 9, 25, 45, &kk_logo_1_image}, - {100, 9, 25, 40, &kk_logo_1_image}, - {100, 9, 25, 35, &kk_logo_1_image}, - {100, 9, 25, 30, &kk_logo_1_image}, - {100, 9, 25, 25, &kk_logo_1_image}, - {100, 9, 25, 20, &kk_logo_1_image}, - {100, 9, 25, 15, &kk_logo_1_image}, - {100, 9, 25, 10, &kk_logo_1_image}, - {100, 9, 25, 5, &kk_logo_1_image}, - {100, 9, 25, 0, &kk_logo_1_image} - } -}; + {{100, 9, 25, 100, &kk_logo_1_image}, {100, 9, 25, 95, &kk_logo_1_image}, + {100, 9, 25, 90, &kk_logo_1_image}, {100, 9, 25, 85, &kk_logo_1_image}, + {100, 9, 25, 80, &kk_logo_1_image}, {100, 9, 25, 75, &kk_logo_1_image}, + {100, 9, 25, 70, &kk_logo_1_image}, {100, 9, 25, 65, &kk_logo_1_image}, + {100, 9, 25, 60, &kk_logo_1_image}, {100, 9, 25, 55, &kk_logo_1_image}, + {100, 9, 25, 50, &kk_logo_1_image}, {100, 9, 25, 45, &kk_logo_1_image}, + {100, 9, 25, 40, &kk_logo_1_image}, {100, 9, 25, 35, &kk_logo_1_image}, + {100, 9, 25, 30, &kk_logo_1_image}, {100, 9, 25, 25, &kk_logo_1_image}, + {100, 9, 25, 20, &kk_logo_1_image}, {100, 9, 25, 15, &kk_logo_1_image}, + {100, 9, 25, 10, &kk_logo_1_image}, {100, 9, 25, 5, &kk_logo_1_image}, + {100, 9, 25, 0, &kk_logo_1_image}}}; const VariantAnimation kk_screensaver = { 199, @@ -281,5 +352,4 @@ const VariantAnimation kk_screensaver = { {94, 9, 150, 60, &kk_logo_1_image}, {96, 9, 150, 60, &kk_logo_1_image}, {98, 9, 150, 60, &kk_logo_1_image}, - } -}; + }}; diff --git a/lib/variant/poweredBy/logo.c b/lib/variant/poweredBy/logo.c index d6587927e..924831cb9 100644 --- a/lib/variant/poweredBy/logo.c +++ b/lib/variant/poweredBy/logo.c @@ -10,17 +10,162 @@ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this library. If not, see + * . */ #include "keepkey/board/resources.h" -const uint8_t poweredBy_logo_1_data[1734] = -{ - 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x4, 0x0, 0x2, 0x1, 0x9, 0x0, 0x2, 0x1, 0x7f, 0x0, 0x60, 0x0, 0xff, 0xab, 0x2, 0xff, 0xef, 0xe6, 0x65, 0x3, 0x81, 0xe4, 0xe7, 0x89, 0xd, 0xf3, 0x99, 0x1, 0xf2, 0x83, 0x9, 0xff, 0x8a, 0xaa, 0x3, 0xff, 0xfe, 0xb3, 0xab, 0x2, 0xff, 0xfc, 0xf0, 0x70, 0x0, 0xaa, 0x3, 0xff, 0xfe, 0xb3, 0xa9, 0x2, 0xff, 0xfd, 0xe2, 0x7b, 0x1, 0x2, 0x0, 0xff, 0xa9, 0x2, 0xff, 0xf8, 0xf1, 0x84, 0xdb, 0xd9, 0x2, 0x4e, 0xff, 0x73, 0x7f, 0x0, 0x4a, 0x0, 0xd7, 0xa0, 0xdd, 0x54, 0xb4, 0xf7, 0x76, 0xfa, 0x78, 0x88, 0xfd, 0x72, 0xae, 0xc7, 0x31, 0xff, 0xc3, 0x38, 0xff, 0x3e, 0xa0, 0xe0, 0x57, 0x5a, 0x46, 0xa0, 0xdc, 0x50, 0xb0, 0xf8, 0x2, 0xa0, 0xe0, 0x57, 0x5a, 0x46, 0x9c, 0xe1, 0x5d, 0x94, 0xff, 0x4e, 0x2, 0x0, 0xf5, 0x9f, 0xdc, 0x4f, 0xa8, 0xfa, 0x43, 0xff, 0x68, 0xd5, 0xc8, 0x2, 0x7f, 0x0, 0x4a, 0x0, 0xf9, 0x9f, 0xdc, 0x50, 0xb0, 0xf5, 0xc8, 0xbe, 0x2, 0x0, 0xf5, 0xb5, 0xc4, 0x67, 0xf9, 0x82, 0xff, 0xfb, 0x82, 0xf3, 0x5, 0x9f, 0x3, 0xff, 0xf8, 0x63, 0x9f, 0xdc, 0x50, 0xb7, 0xbe, 0x0, 0x9f, 0x3, 0xff, 0xf9, 0x63, 0x9b, 0xcf, 0x0, 0x1, 0xe1, 0x93, 0x2, 0x0, 0xff, 0x9f, 0x3, 0xff, 0xfd, 0xbe, 0x0, 0xa0, 0x2, 0xfc, 0xff, 0x30, 0x7f, 0x0, 0x44, 0x0, 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x3, 0x0, 0xff, 0x9f, 0x2, 0xff, 0xfc, 0xe5, 0x5f, 0xc5, 0xbf, 0x2, 0x0, 0x2, 0xc2, 0xf2, 0x22, 0xff, 0xf9, 0x89, 0xf1, 0xfa, 0xb2, 0x0, 0x9f, 0xdd, 0x53, 0x59, 0x28, 0x9f, 0x3, 0xff, 0xf3, 0x60, 0x0, 0x9f, 0xdd, 0x53, 0x59, 0x28, 0x9b, 0xcf, 0x0, 0x1, 0xe4, 0x8e, 0x2, 0x0, 0xf7, 0x9f, 0xda, 0x47, 0x8d, 0xed, 0xf, 0x15, 0xfa, 0x9b, 0x7f, 0x0, 0x45, 0x0, 0x3, 0xff, 0xff, 0xdd, 0x3, 0x0, 0xfe, 0xa0, 0xcc, 0x3, 0x0, 0xfe, 0x70, 0xfa, 0x2, 0x77, 0xe0, 0xfb, 0x6c, 0x0, 0xdb, 0xff, 0x3e, 0xaf, 0xff, 0x6d, 0x0, 0xa0, 0xdd, 0x57, 0x58, 0x4c, 0x9f, 0xcb, 0x9, 0xbb, 0xe0, 0x5, 0xa0, 0xdd, 0x57, 0x58, 0x4c, 0x9c, 0xe0, 0x59, 0x97, 0xff, 0x47, 0x2, 0x0, 0xf7, 0xa0, 0xdb, 0x4b, 0x91, 0xff, 0x2c, 0x0, 0xf4, 0x80, 0x7f, 0x0, 0x45, 0x0, 0xff, 0xe2, 0x3, 0xff, 0x3, 0x0, 0xfe, 0xaa, 0xd6, 0x3, 0x0, 0xf1, 0x3, 0x84, 0xe6, 0xe5, 0x80, 0x2, 0x0, 0x97, 0xf8, 0x6, 0x6f, 0xff, 0x2a, 0x0, 0xaa, 0x3, 0xff, 0xf8, 0xc3, 0xa7, 0xd7, 0x0, 0x49, 0xff, 0x5f, 0xaa, 0x3, 0xff, 0xfe, 0xc3, 0xa6, 0x2, 0xff, 0xfe, 0xe3, 0x77, 0x3, 0x0, 0xff, 0xab, 0x2, 0xff, 0xfe, 0xf4, 0x94, 0x2, 0x1, 0xfe, 0xfc, 0x87, 0x7f, 0x0, 0x46, 0x0, 0x3, 0xff, 0x16, 0x0, 0xfb, 0x3, 0x1, 0x0, 0x1, 0xa, 0x6, 0x0, 0xf9, 0x3, 0x1, 0x0, 0x1, 0xa, 0x4, 0x1, 0x6, 0x0, 0xfe, 0x3, 0x1, 0x7f, 0x0, 0x4d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, 0xff, 0xfd, 0xdd, 0x79, 0x7, 0x5, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, 0xff, 0xfd, 0xdd, 0x79, 0x7, 0x3, 0x0, 0xf4, 0xb5, 0xf7, 0xeb, 0x58, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x7, 0x7f, 0x0, 0x4a, 0x0, 0x3, 0xff, 0x4, 0x0, 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x1c, 0xdd, 0x7, 0xff, 0xfe, 0xb5, 0x7, 0x3, 0x0, 0xfe, 0x1c, 0xdd, 0x7, 0xff, 0xfe, 0xb5, 0x7, 0x2, 0x0, 0x3, 0xff, 0x2, 0xdd, 0x6, 0xff, 0xfe, 0xdd, 0x1c, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0xff, 0xe2, 0xb, 0xff, 0xff, 0xb5, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, 0x3, 0x0, 0xff, 0x58, 0x2, 0xff, 0xfe, 0xf7, 0x33, 0x3, 0x0, 0xfe, 0x1c, 0xeb, 0x2, 0xff, 0xfd, 0x11, 0x0, 0x58, 0x2, 0xff, 0xfe, 0xf7, 0x33, 0x3, 0x0, 0xfe, 0x1c, 0xeb, 0x2, 0xff, 0xff, 0x11, 0x2, 0x0, 0x3, 0xff, 0xfe, 0xa3, 0x33, 0x2, 0x7, 0xfe, 0x33, 0xdd, 0x2, 0xff, 0xff, 0xf7, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x8f, 0x5, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xfd, 0x58, 0x0, 0xa3, 0x2, 0xff, 0xff, 0x8f, 0x5, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x58, 0x2, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x58, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x8, 0xff, 0xff, 0x79, 0x5, 0x0, 0xff, 0xdd, 0x2, 0xff, 0xff, 0x33, 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, 0xfd, 0x8f, 0x0, 0xdd, 0x2, 0xff, 0xff, 0x33, 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x1c, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xfe, 0xb5, 0x0, 0xc, 0xff, 0xff, 0xb5, 0x2, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x7, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xfe, 0xa3, 0x0, 0xc, 0xff, 0xff, 0xa3, 0x2, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x7, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x8f, 0x3, 0xff, 0xff, 0x79, 0x5, 0x0, 0xfd, 0xe2, 0xff, 0xf7, 0xb, 0x0, 0xfd, 0xe2, 0xff, 0xf7, 0xc, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x1c, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x11, 0xa, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x11, 0xb, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x58, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, 0x0, 0xfc, 0x7, 0x58, 0x8f, 0x11, 0x2, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, 0x0, 0xfc, 0x7, 0x58, 0x8f, 0x11, 0x3, 0x0, 0x3, 0xff, 0xfe, 0xa3, 0x33, 0x2, 0x7, 0xfe, 0x33, 0xdd, 0x2, 0xff, 0xff, 0xf7, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xeb, 0x2, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0xfe, 0x7, 0xeb, 0x2, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x2, 0xff, 0xff, 0x8f, 0x3, 0x0, 0xb, 0xff, 0xff, 0xb5, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x4, 0x0, 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, 0xff, 0xa3, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, 0xff, 0xa3, 0x3, 0x0, 0x3, 0xff, 0xff, 0xdd, 0x6, 0xff, 0xfe, 0xdd, 0x1c, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x5, 0x0, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x4, 0x0, 0x3, 0xff, 0xf8, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x7, 0x7f, 0x0, 0x4a, 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, 0xff, 0xfd, 0xdd, 0x79, 0x7, 0x2, 0x0, 0x5, 0xff, 0x4, 0x0, 0x5, 0xff, 0x2, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x4, 0x0, 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x1c, 0xdd, 0x7, 0xff, 0xfd, 0xb5, 0x7, 0x0, 0x5, 0xff, 0x4, 0x0, 0x5, 0xff, 0x2, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, 0x8f, 0x3, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x2, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, 0x3, 0x0, 0xff, 0x58, 0x2, 0xff, 0xfe, 0xf7, 0x33, 0x3, 0x0, 0xfe, 0x1c, 0xeb, 0x2, 0xff, 0xff, 0x11, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x8f, 0x5, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x58, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x8, 0xff, 0xff, 0x79, 0x5, 0x0, 0xff, 0xdd, 0x2, 0xff, 0xff, 0x33, 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xff, 0xb5, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xff, 0xa3, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x8f, 0x3, 0xff, 0xff, 0x79, 0x5, 0x0, 0xfd, 0xe2, 0xff, 0xf7, 0xc, 0x0, 0x3, 0xff, 0xff, 0x7, 0x5, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x11, 0xb, 0x0, 0xff, 0xeb, 0x2, 0xff, 0xff, 0x1c, 0x4, 0x0, 0xff, 0x11, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, 0x0, 0xfc, 0x7, 0x58, 0x8f, 0x11, 0x3, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x58, 0x3, 0x0, 0xfe, 0x7, 0xb5, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xeb, 0x2, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x2, 0xff, 0xff, 0x8f, 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xfb, 0xf7, 0xa3, 0x8f, 0xb5, 0xe2, 0x4, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x4, 0x0, 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, 0xff, 0xa3, 0x3, 0x0, 0xfe, 0x7, 0xdd, 0x6, 0xff, 0xff, 0x8f, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x5, 0x0, 0xf8, 0x11, 0xa3, 0xe2, 0xff, 0xeb, 0xb5, 0x58, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7c, 0x0, 0xff, 0xe2, 0x3, 0xff, 0x7f, 0x0, 0x7c, 0x0, 0x3, 0xff, 0xff, 0xdd, 0x7f, 0x0, 0x7c, 0x0, 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7a, 0x0 -}; -static const Image poweredBy_logo_1_image = {255, 64, 1734, poweredBy_logo_1_data}; +const uint8_t poweredBy_logo_1_data[1734] = { + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x4, 0x0, + 0x2, 0x1, 0x9, 0x0, 0x2, 0x1, 0x7f, 0x0, 0x60, 0x0, 0xff, 0xab, + 0x2, 0xff, 0xef, 0xe6, 0x65, 0x3, 0x81, 0xe4, 0xe7, 0x89, 0xd, 0xf3, + 0x99, 0x1, 0xf2, 0x83, 0x9, 0xff, 0x8a, 0xaa, 0x3, 0xff, 0xfe, 0xb3, + 0xab, 0x2, 0xff, 0xfc, 0xf0, 0x70, 0x0, 0xaa, 0x3, 0xff, 0xfe, 0xb3, + 0xa9, 0x2, 0xff, 0xfd, 0xe2, 0x7b, 0x1, 0x2, 0x0, 0xff, 0xa9, 0x2, + 0xff, 0xf8, 0xf1, 0x84, 0xdb, 0xd9, 0x2, 0x4e, 0xff, 0x73, 0x7f, 0x0, + 0x4a, 0x0, 0xd7, 0xa0, 0xdd, 0x54, 0xb4, 0xf7, 0x76, 0xfa, 0x78, 0x88, + 0xfd, 0x72, 0xae, 0xc7, 0x31, 0xff, 0xc3, 0x38, 0xff, 0x3e, 0xa0, 0xe0, + 0x57, 0x5a, 0x46, 0xa0, 0xdc, 0x50, 0xb0, 0xf8, 0x2, 0xa0, 0xe0, 0x57, + 0x5a, 0x46, 0x9c, 0xe1, 0x5d, 0x94, 0xff, 0x4e, 0x2, 0x0, 0xf5, 0x9f, + 0xdc, 0x4f, 0xa8, 0xfa, 0x43, 0xff, 0x68, 0xd5, 0xc8, 0x2, 0x7f, 0x0, + 0x4a, 0x0, 0xf9, 0x9f, 0xdc, 0x50, 0xb0, 0xf5, 0xc8, 0xbe, 0x2, 0x0, + 0xf5, 0xb5, 0xc4, 0x67, 0xf9, 0x82, 0xff, 0xfb, 0x82, 0xf3, 0x5, 0x9f, + 0x3, 0xff, 0xf8, 0x63, 0x9f, 0xdc, 0x50, 0xb7, 0xbe, 0x0, 0x9f, 0x3, + 0xff, 0xf9, 0x63, 0x9b, 0xcf, 0x0, 0x1, 0xe1, 0x93, 0x2, 0x0, 0xff, + 0x9f, 0x3, 0xff, 0xfd, 0xbe, 0x0, 0xa0, 0x2, 0xfc, 0xff, 0x30, 0x7f, + 0x0, 0x44, 0x0, 0xfc, 0xb5, 0xf7, 0xeb, 0x58, 0x3, 0x0, 0xff, 0x9f, + 0x2, 0xff, 0xfc, 0xe5, 0x5f, 0xc5, 0xbf, 0x2, 0x0, 0x2, 0xc2, 0xf2, + 0x22, 0xff, 0xf9, 0x89, 0xf1, 0xfa, 0xb2, 0x0, 0x9f, 0xdd, 0x53, 0x59, + 0x28, 0x9f, 0x3, 0xff, 0xf3, 0x60, 0x0, 0x9f, 0xdd, 0x53, 0x59, 0x28, + 0x9b, 0xcf, 0x0, 0x1, 0xe4, 0x8e, 0x2, 0x0, 0xf7, 0x9f, 0xda, 0x47, + 0x8d, 0xed, 0xf, 0x15, 0xfa, 0x9b, 0x7f, 0x0, 0x45, 0x0, 0x3, 0xff, + 0xff, 0xdd, 0x3, 0x0, 0xfe, 0xa0, 0xcc, 0x3, 0x0, 0xfe, 0x70, 0xfa, + 0x2, 0x77, 0xe0, 0xfb, 0x6c, 0x0, 0xdb, 0xff, 0x3e, 0xaf, 0xff, 0x6d, + 0x0, 0xa0, 0xdd, 0x57, 0x58, 0x4c, 0x9f, 0xcb, 0x9, 0xbb, 0xe0, 0x5, + 0xa0, 0xdd, 0x57, 0x58, 0x4c, 0x9c, 0xe0, 0x59, 0x97, 0xff, 0x47, 0x2, + 0x0, 0xf7, 0xa0, 0xdb, 0x4b, 0x91, 0xff, 0x2c, 0x0, 0xf4, 0x80, 0x7f, + 0x0, 0x45, 0x0, 0xff, 0xe2, 0x3, 0xff, 0x3, 0x0, 0xfe, 0xaa, 0xd6, + 0x3, 0x0, 0xf1, 0x3, 0x84, 0xe6, 0xe5, 0x80, 0x2, 0x0, 0x97, 0xf8, + 0x6, 0x6f, 0xff, 0x2a, 0x0, 0xaa, 0x3, 0xff, 0xf8, 0xc3, 0xa7, 0xd7, + 0x0, 0x49, 0xff, 0x5f, 0xaa, 0x3, 0xff, 0xfe, 0xc3, 0xa6, 0x2, 0xff, + 0xfe, 0xe3, 0x77, 0x3, 0x0, 0xff, 0xab, 0x2, 0xff, 0xfe, 0xf4, 0x94, + 0x2, 0x1, 0xfe, 0xfc, 0x87, 0x7f, 0x0, 0x46, 0x0, 0x3, 0xff, 0x16, + 0x0, 0xfb, 0x3, 0x1, 0x0, 0x1, 0xa, 0x6, 0x0, 0xf9, 0x3, 0x1, + 0x0, 0x1, 0xa, 0x4, 0x1, 0x6, 0x0, 0xfe, 0x3, 0x1, 0x7f, 0x0, + 0x4d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, + 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x5, 0x0, + 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, + 0xff, 0xfd, 0xdd, 0x79, 0x7, 0x5, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, + 0xff, 0xfd, 0xdd, 0x79, 0x7, 0x3, 0x0, 0xf4, 0xb5, 0xf7, 0xeb, 0x58, + 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x7, 0x7f, 0x0, 0x4a, 0x0, + 0x3, 0xff, 0x4, 0x0, 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, + 0x1c, 0xdd, 0x7, 0xff, 0xfe, 0xb5, 0x7, 0x3, 0x0, 0xfe, 0x1c, 0xdd, + 0x7, 0xff, 0xfe, 0xb5, 0x7, 0x2, 0x0, 0x3, 0xff, 0x2, 0xdd, 0x6, + 0xff, 0xfe, 0xdd, 0x1c, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x3, 0x0, + 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, + 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0xfe, + 0x7, 0xcd, 0x3, 0xff, 0xfc, 0xb5, 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, + 0x8f, 0x2, 0x0, 0xff, 0xe2, 0xb, 0xff, 0xff, 0xb5, 0x7f, 0x0, 0x49, + 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, + 0x3, 0x0, 0xff, 0x58, 0x2, 0xff, 0xfe, 0xf7, 0x33, 0x3, 0x0, 0xfe, + 0x1c, 0xeb, 0x2, 0xff, 0xfd, 0x11, 0x0, 0x58, 0x2, 0xff, 0xfe, 0xf7, + 0x33, 0x3, 0x0, 0xfe, 0x1c, 0xeb, 0x2, 0xff, 0xff, 0x11, 0x2, 0x0, + 0x3, 0xff, 0xfe, 0xa3, 0x33, 0x2, 0x7, 0xfe, 0x33, 0xdd, 0x2, 0xff, + 0xff, 0xf7, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, + 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x8f, + 0x5, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xfd, 0x58, 0x0, 0xa3, 0x2, 0xff, + 0xff, 0x8f, 0x5, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x58, 0x2, 0x0, + 0x3, 0xff, 0x5, 0x0, 0xff, 0x58, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, + 0x8, 0xff, 0xff, 0x79, 0x5, 0x0, 0xff, 0xdd, 0x2, 0xff, 0xff, 0x33, + 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, 0xfd, 0x8f, 0x0, 0xdd, 0x2, 0xff, + 0xff, 0x33, 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, + 0x3, 0xff, 0x5, 0x0, 0xff, 0x1c, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, + 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xfe, 0xb5, 0x0, 0xc, + 0xff, 0xff, 0xb5, 0x2, 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x7, 0x3, + 0xff, 0x7f, 0x0, 0x49, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, + 0xff, 0xfe, 0xa3, 0x0, 0xc, 0xff, 0xff, 0xa3, 0x2, 0x0, 0x3, 0xff, + 0x5, 0x0, 0xff, 0x7, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, + 0xfe, 0x0, 0x8f, 0x3, 0xff, 0xff, 0x79, 0x5, 0x0, 0xfd, 0xe2, 0xff, + 0xf7, 0xb, 0x0, 0xfd, 0xe2, 0xff, 0xf7, 0xc, 0x0, 0x3, 0xff, 0x5, + 0x0, 0xff, 0x1c, 0x3, 0xff, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0xfd, + 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, 0x79, 0x4, 0x0, 0xff, 0xb5, 0x2, + 0xff, 0xff, 0x11, 0xa, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x11, 0xb, + 0x0, 0x3, 0xff, 0x5, 0x0, 0xff, 0x58, 0x3, 0xff, 0x7f, 0x0, 0x49, + 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, + 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, 0x0, 0xfc, 0x7, + 0x58, 0x8f, 0x11, 0x2, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, + 0x0, 0xfc, 0x7, 0x58, 0x8f, 0x11, 0x3, 0x0, 0x3, 0xff, 0xfe, 0xa3, + 0x33, 0x2, 0x7, 0xfe, 0x33, 0xdd, 0x2, 0xff, 0xff, 0xf7, 0x7f, 0x0, + 0x49, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, + 0x0, 0xfe, 0x7, 0xeb, 0x2, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, + 0x2, 0xff, 0xff, 0x8f, 0x2, 0x0, 0xfe, 0x7, 0xeb, 0x2, 0xff, 0xfb, + 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x2, 0xff, 0xff, 0x8f, 0x3, 0x0, 0xb, + 0xff, 0xff, 0xb5, 0x7f, 0x0, 0x49, 0x0, 0x3, 0xff, 0x4, 0x0, 0xfe, + 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, 0xff, + 0xa3, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, 0xff, 0xa3, 0x3, 0x0, + 0x3, 0xff, 0xff, 0xdd, 0x6, 0xff, 0xfe, 0xdd, 0x1c, 0x7f, 0x0, 0x49, + 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, + 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x5, 0x0, + 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, 0x8f, 0x33, 0x4, 0x0, + 0x3, 0xff, 0xf8, 0x11, 0x8f, 0xdd, 0xff, 0xeb, 0xb5, 0x79, 0x7, 0x7f, + 0x0, 0x4a, 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, + 0x0, 0x3, 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, + 0xff, 0x28, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x28, + 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, + 0x33, 0xf7, 0x2, 0xff, 0x4, 0x0, 0xfd, 0x11, 0x8f, 0xe2, 0x3, 0xff, + 0xfd, 0xdd, 0x79, 0x7, 0x2, 0x0, 0x5, 0xff, 0x4, 0x0, 0x5, 0xff, + 0x2, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x4, 0x0, + 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x1c, 0xdd, 0x7, 0xff, + 0xfd, 0xb5, 0x7, 0x0, 0x5, 0xff, 0x4, 0x0, 0x5, 0xff, 0x2, 0x0, + 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, + 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xfc, 0xb5, + 0x8f, 0xa3, 0xeb, 0x2, 0xff, 0xff, 0x8f, 0x3, 0x0, 0x3, 0xff, 0x6, + 0x0, 0x3, 0xff, 0x2, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x52, 0x0, 0x3, + 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, 0xff, 0x79, 0x3, 0x0, + 0xff, 0x58, 0x2, 0xff, 0xfe, 0xf7, 0x33, 0x3, 0x0, 0xfe, 0x1c, 0xeb, + 0x2, 0xff, 0xff, 0x11, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, + 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, + 0xff, 0x79, 0x4, 0x0, 0xff, 0xa3, 0x2, 0xff, 0xff, 0x8f, 0x5, 0x0, + 0xff, 0xa3, 0x2, 0xff, 0xff, 0x58, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, + 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x8, 0xff, 0xff, 0x79, 0x5, 0x0, + 0xff, 0xdd, 0x2, 0xff, 0xff, 0x33, 0x5, 0x0, 0xff, 0x79, 0x2, 0xff, + 0xff, 0x8f, 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, + 0x57, 0x0, 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xff, 0xb5, + 0x2, 0x0, 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, + 0x7, 0xff, 0xff, 0x79, 0x6, 0x0, 0xc, 0xff, 0xff, 0xa3, 0x2, 0x0, + 0x3, 0xff, 0x6, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, + 0xfe, 0x0, 0x8f, 0x3, 0xff, 0xff, 0x79, 0x5, 0x0, 0xfd, 0xe2, 0xff, + 0xf7, 0xc, 0x0, 0x3, 0xff, 0xff, 0x7, 0x5, 0x0, 0x3, 0xff, 0x7f, + 0x0, 0x57, 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xb5, 0x3, 0xff, 0xff, + 0x79, 0x4, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, 0x11, 0xb, 0x0, 0xff, + 0xeb, 0x2, 0xff, 0xff, 0x1c, 0x4, 0x0, 0xff, 0x11, 0x3, 0xff, 0x7f, + 0x0, 0x57, 0x0, 0x3, 0xff, 0x2, 0x0, 0xfe, 0x7, 0xcd, 0x3, 0xff, + 0xff, 0x79, 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xff, 0x8f, 0x4, 0x0, + 0xfc, 0x7, 0x58, 0x8f, 0x11, 0x3, 0x0, 0xff, 0xb5, 0x2, 0xff, 0xff, + 0x58, 0x3, 0x0, 0xfe, 0x7, 0xb5, 0x3, 0xff, 0x7f, 0x0, 0x57, 0x0, + 0x3, 0xff, 0x3, 0x0, 0xfe, 0x11, 0xdd, 0x4, 0xff, 0x2, 0x0, 0xfe, + 0x7, 0xeb, 0x2, 0xff, 0xfb, 0xdd, 0xa3, 0x8f, 0xb5, 0xe2, 0x2, 0xff, + 0xff, 0x8f, 0x3, 0x0, 0xff, 0x79, 0x2, 0xff, 0xfb, 0xf7, 0xa3, 0x8f, + 0xb5, 0xe2, 0x4, 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x4, 0x0, + 0xfe, 0x1c, 0xeb, 0x3, 0xff, 0x3, 0x0, 0xfe, 0x33, 0xf7, 0x8, 0xff, + 0xff, 0xa3, 0x3, 0x0, 0xfe, 0x7, 0xdd, 0x6, 0xff, 0xff, 0x8f, 0x3, + 0xff, 0x7f, 0x0, 0x57, 0x0, 0x3, 0xff, 0x5, 0x0, 0xfe, 0x33, 0xf7, + 0x2, 0xff, 0x4, 0x0, 0xf7, 0x1c, 0xa3, 0xe2, 0xff, 0xf7, 0xe2, 0xb5, + 0x8f, 0x33, 0x5, 0x0, 0xf8, 0x11, 0xa3, 0xe2, 0xff, 0xeb, 0xb5, 0x58, + 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, + 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7d, + 0x0, 0x3, 0xff, 0x7f, 0x0, 0x7c, 0x0, 0xff, 0xe2, 0x3, 0xff, 0x7f, + 0x0, 0x7c, 0x0, 0x3, 0xff, 0xff, 0xdd, 0x7f, 0x0, 0x7c, 0x0, 0xfc, + 0xb5, 0xf7, 0xeb, 0x58, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7a, 0x0}; +static const Image poweredBy_logo_1_image = {255, 64, 1734, + poweredBy_logo_1_data}; const VariantAnimation poweredBy_logo = { 21, @@ -46,33 +191,27 @@ const VariantAnimation poweredBy_logo = { {0, 0, 25, 90, &poweredBy_logo_1_image}, {0, 0, 25, 95, &poweredBy_logo_1_image}, {0, 0, 25, 100, &poweredBy_logo_1_image}, - } -}; + }}; const VariantAnimation poweredBy_logo_reversed = { 21, - { - {0, 0, 25, 100, &poweredBy_logo_1_image}, - {0, 0, 25, 95, &poweredBy_logo_1_image}, - {0, 0, 25, 90, &poweredBy_logo_1_image}, - {0, 0, 25, 85, &poweredBy_logo_1_image}, - {0, 0, 25, 80, &poweredBy_logo_1_image}, - {0, 0, 25, 75, &poweredBy_logo_1_image}, - {0, 0, 25, 70, &poweredBy_logo_1_image}, - {0, 0, 25, 65, &poweredBy_logo_1_image}, - {0, 0, 25, 60, &poweredBy_logo_1_image}, - {0, 0, 25, 55, &poweredBy_logo_1_image}, - {0, 0, 25, 50, &poweredBy_logo_1_image}, - {0, 0, 25, 45, &poweredBy_logo_1_image}, - {0, 0, 25, 40, &poweredBy_logo_1_image}, - {0, 0, 25, 35, &poweredBy_logo_1_image}, - {0, 0, 25, 30, &poweredBy_logo_1_image}, - {0, 0, 25, 25, &poweredBy_logo_1_image}, - {0, 0, 25, 20, &poweredBy_logo_1_image}, - {0, 0, 25, 15, &poweredBy_logo_1_image}, - {0, 0, 25, 10, &poweredBy_logo_1_image}, - {0, 0, 25, 5, &poweredBy_logo_1_image}, - {0, 0, 25, 0, &poweredBy_logo_1_image} - } -}; - - + {{0, 0, 25, 100, &poweredBy_logo_1_image}, + {0, 0, 25, 95, &poweredBy_logo_1_image}, + {0, 0, 25, 90, &poweredBy_logo_1_image}, + {0, 0, 25, 85, &poweredBy_logo_1_image}, + {0, 0, 25, 80, &poweredBy_logo_1_image}, + {0, 0, 25, 75, &poweredBy_logo_1_image}, + {0, 0, 25, 70, &poweredBy_logo_1_image}, + {0, 0, 25, 65, &poweredBy_logo_1_image}, + {0, 0, 25, 60, &poweredBy_logo_1_image}, + {0, 0, 25, 55, &poweredBy_logo_1_image}, + {0, 0, 25, 50, &poweredBy_logo_1_image}, + {0, 0, 25, 45, &poweredBy_logo_1_image}, + {0, 0, 25, 40, &poweredBy_logo_1_image}, + {0, 0, 25, 35, &poweredBy_logo_1_image}, + {0, 0, 25, 30, &poweredBy_logo_1_image}, + {0, 0, 25, 25, &poweredBy_logo_1_image}, + {0, 0, 25, 20, &poweredBy_logo_1_image}, + {0, 0, 25, 15, &poweredBy_logo_1_image}, + {0, 0, 25, 10, &poweredBy_logo_1_image}, + {0, 0, 25, 5, &poweredBy_logo_1_image}, + {0, 0, 25, 0, &poweredBy_logo_1_image}}}; diff --git a/lib/variant/poweredBy/poweredBy.c b/lib/variant/poweredBy/poweredBy.c index c35fabd26..b7d8e1738 100644 --- a/lib/variant/poweredBy/poweredBy.c +++ b/lib/variant/poweredBy/poweredBy.c @@ -4,7 +4,4 @@ #include "keepkey/board/timer.h" #include "keepkey/board/variant.h" -const VariantInfo variant_poweredBy = { - VARIANTINFO_POWERED_BY -}; - +const VariantInfo variant_poweredBy = {VARIANTINFO_POWERED_BY}; diff --git a/lib/variant/salt/logo.c b/lib/variant/salt/logo.c index 3f20a827c..6884c0684 100644 --- a/lib/variant/salt/logo.c +++ b/lib/variant/salt/logo.c @@ -19,64 +19,215 @@ #include "keepkey/board/resources.h" -const uint8_t salt_logo_1_data[1915] = -{ - 0x7f, 0x0, 0x3a, 0x0, 0xff, 0x1, 0x6, 0x2, 0xff, 0x1, 0x59, 0x0, 0xfe, 0x1, 0x3, 0x3, 0x2, 0x22, 0x0, 0xff, 0x1, 0x1a, 0x2, 0x9, 0x0, 0xf2, 0x1, 0x5, 0xd, 0x31, 0x5f, 0x79, 0x84, 0x83, 0x78, 0x5f, 0x35, 0xf, 0x6, 0x3, 0x2b, 0x0, 0xfe, 0x19, 0x18, 0x28, 0x0, 0xf9, 0x3, 0x36, 0x87, 0x81, 0x84, 0x65, 0x4, 0x21, 0x0, 0xfd, 0x33, 0x77, 0x83, 0x16, 0x81, 0xfd, 0x85, 0x65, 0x14, 0x7, 0x0, 0xfc, 0xa, 0x38, 0xa1, 0xed, 0x8, 0xff, 0xfb, 0xfa, 0xbd, 0x64, 0x16, 0x5, 0x28, 0x0, 0xfd, 0x3, 0x90, 0x80, 0x28, 0x0, 0xfe, 0x5, 0x6d, 0x3, 0xff, 0xfe, 0xcb, 0x8, 0x21, 0x0, 0xfe, 0x67, 0xef, 0x18, 0xff, 0xfe, 0xcb, 0x27, 0x5, 0x0, 0xfd, 0x1, 0x24, 0xa8, 0xe, 0xff, 0xfc, 0xf2, 0x7d, 0x15, 0x2, 0x26, 0x0, 0xfc, 0x3c, 0xdc, 0xc4, 0x2a, 0x27, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x21, 0x0, 0xfe, 0x65, 0xeb, 0x18, 0xff, 0xfe, 0xc8, 0x27, 0x4, 0x0, 0xfd, 0x2, 0x3f, 0xe6, 0x4, 0xff, 0xf9, 0xfd, 0xf6, 0xf2, 0xf1, 0xf2, 0xf4, 0xf9, 0x6, 0xff, 0xfd, 0xdb, 0x3d, 0x5, 0x25, 0x0, 0xff, 0x7d, 0x2, 0xff, 0xff, 0x67, 0x27, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x21, 0x0, 0xfd, 0x61, 0xe0, 0xf6, 0x8, 0xf4, 0xff, 0xf7, 0x3, 0xff, 0xfe, 0xfd, 0xf5, 0x8, 0xf4, 0xfd, 0xfb, 0xbf, 0x25, 0x4, 0x0, 0xfe, 0x31, 0xf0, 0x3, 0xff, 0xf4, 0xfb, 0xe7, 0xb9, 0x79, 0x57, 0x4d, 0x55, 0x6c, 0x95, 0xca, 0xe8, 0xf6, 0x5, 0xff, 0xff, 0x5a, 0x24, 0x0, 0xfe, 0x33, 0xcb, 0x2, 0xff, 0xfe, 0xb4, 0x22, 0x26, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x21, 0x0, 0xfd, 0x29, 0x60, 0x6a, 0x7, 0x69, 0xfe, 0x6a, 0x96, 0x3, 0xff, 0xfd, 0xea, 0x78, 0x67, 0x7, 0x69, 0xfd, 0x6c, 0x52, 0x10, 0x3, 0x0, 0xfe, 0x10, 0xc5, 0x3, 0xff, 0xfd, 0xf7, 0xad, 0x29, 0x8, 0x0, 0xfc, 0x25, 0x87, 0xda, 0xfa, 0x3, 0xff, 0xfe, 0xcb, 0x1, 0x23, 0x0, 0xff, 0x70, 0x3, 0xff, 0xfe, 0xfd, 0x5a, 0x26, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2c, 0x0, 0xff, 0x48, 0x3, 0xff, 0xfe, 0xda, 0x14, 0xd, 0x0, 0xfe, 0x2, 0x50, 0x3, 0xff, 0xfe, 0xf9, 0x9c, 0xc, 0x0, 0xfa, 0x19, 0xa1, 0xef, 0xff, 0xdc, 0x1b, 0x23, 0x0, 0xfe, 0x2a, 0xc2, 0x4, 0xff, 0xfe, 0xa9, 0x1b, 0x25, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x5, 0xb1, 0x3, 0xff, 0xfe, 0xd1, 0x16, 0xe, 0x0, 0xfd, 0x76, 0xdc, 0x36, 0x24, 0x0, 0xff, 0x63, 0x5, 0xff, 0xfe, 0xf8, 0x4e, 0x25, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x7, 0xe9, 0x2, 0xff, 0xfe, 0xfb, 0xa0, 0x10, 0x0, 0xff, 0x24, 0x24, 0x0, 0xfe, 0x21, 0xb9, 0x6, 0xff, 0xfe, 0x9d, 0x14, 0x24, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xff, 0x8, 0x3, 0xff, 0xfe, 0xf4, 0x82, 0x35, 0x0, 0xff, 0x55, 0x3, 0xff, 0x2, 0xf9, 0x2, 0xff, 0xfe, 0xf2, 0x42, 0x24, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x8, 0xfe, 0x2, 0xff, 0xfe, 0xfa, 0x9c, 0x34, 0x0, 0xfe, 0x1a, 0xae, 0x3, 0xff, 0xfe, 0xb8, 0xbe, 0x3, 0xff, 0xfe, 0x8f, 0xf, 0x23, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x7, 0xde, 0x3, 0xff, 0xfe, 0xda, 0x29, 0x33, 0x0, 0xfe, 0x49, 0xfe, 0x2, 0xff, 0xfc, 0xe7, 0x46, 0x5d, 0xf5, 0x2, 0xff, 0xfe, 0xec, 0x37, 0x23, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x5, 0x9b, 0x3, 0xff, 0xfc, 0xfd, 0xbe, 0x36, 0x6, 0x30, 0x0, 0xfe, 0x13, 0xa3, 0x3, 0xff, 0xfc, 0xa6, 0xa, 0x1d, 0xbb, 0x3, 0xff, 0xfe, 0x82, 0xb, 0x22, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfd, 0x1, 0x3d, 0xfd, 0x4, 0xff, 0xfc, 0xdf, 0x7a, 0x3e, 0x1b, 0x2e, 0x0, 0xfe, 0x3e, 0xf9, 0x2, 0xff, 0xfe, 0xec, 0x5f, 0x2, 0x0, 0xfe, 0x77, 0xf8, 0x2, 0xff, 0xfe, 0xe6, 0x2c, 0x22, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xe, 0x0, 0xfe, 0x3, 0x93, 0x6, 0xff, 0xfa, 0xe6, 0xa6, 0x70, 0x49, 0x2c, 0xd, 0x29, 0x0, 0xfe, 0xe, 0x96, 0x3, 0xff, 0xfe, 0xb3, 0x14, 0x2, 0x0, 0xfe, 0x26, 0xc6, 0x3, 0xff, 0xfe, 0x76, 0x8, 0x21, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xf, 0x0, 0xfd, 0x11, 0xa0, 0xfa, 0x7, 0xff, 0xfa, 0xec, 0xbf, 0x93, 0x66, 0x40, 0x19, 0x26, 0x0, 0xfe, 0x33, 0xf4, 0x2, 0xff, 0xfe, 0xf0, 0x6c, 0x4, 0x0, 0xfe, 0x85, 0xfa, 0x2, 0xff, 0xfe, 0xe0, 0x22, 0x21, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x10, 0x0, 0xfd, 0xe, 0x7b, 0xd2, 0xa, 0xff, 0xfc, 0xd9, 0xa6, 0x70, 0x39, 0x23, 0x0, 0xfe, 0xa, 0x8a, 0x3, 0xff, 0xfe, 0xbf, 0x19, 0x4, 0x0, 0xfe, 0x2d, 0xd0, 0x3, 0xff, 0xfe, 0x69, 0x6, 0x20, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x12, 0x0, 0xfc, 0x3c, 0x87, 0xc2, 0xf2, 0xa, 0xff, 0xfd, 0xce, 0x89, 0x39, 0x21, 0x0, 0xfe, 0x28, 0xef, 0x2, 0xff, 0xfe, 0xf4, 0x79, 0x6, 0x0, 0xfe, 0x92, 0xfb, 0x2, 0xff, 0xfe, 0xd9, 0x18, 0x20, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x14, 0x0, 0xfb, 0x2d, 0x60, 0x90, 0xbd, 0xe9, 0x9, 0xff, 0xfd, 0xcd, 0x6c, 0x2, 0x1e, 0x0, 0xfe, 0x6, 0x7d, 0x3, 0xff, 0xfe, 0xcb, 0x1e, 0x6, 0x0, 0xfe, 0x36, 0xda, 0x3, 0xff, 0xfe, 0x5d, 0x4, 0x1f, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x16, 0x0, 0xf9, 0x4, 0x2b, 0x50, 0x75, 0x9e, 0xcc, 0xfc, 0x6, 0xff, 0xfe, 0xf5, 0x83, 0x1e, 0x0, 0xfe, 0x1d, 0xe9, 0x2, 0xff, 0xfe, 0xf6, 0x86, 0x8, 0x0, 0xfe, 0x9f, 0xfc, 0x2, 0xff, 0xfe, 0xd1, 0xf, 0x1f, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x1a, 0x0, 0xfb, 0x12, 0x36, 0x5c, 0x90, 0xd7, 0x5, 0xff, 0xfe, 0xfb, 0x60, 0x1c, 0x0, 0xfe, 0x4, 0x71, 0x3, 0xff, 0xfe, 0xd6, 0x24, 0x8, 0x0, 0xfe, 0x40, 0xe3, 0x3, 0xff, 0xfe, 0x52, 0x2, 0x1e, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x1d, 0x0, 0xfc, 0xd, 0x39, 0x7c, 0xe8, 0x4, 0xff, 0xfe, 0xe3, 0x11, 0x1b, 0x0, 0xfe, 0x13, 0xe3, 0x2, 0xff, 0xfe, 0xf8, 0x93, 0xa, 0x0, 0xfe, 0xac, 0xfd, 0x2, 0xff, 0xfe, 0xc9, 0x8, 0x1e, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x1f, 0x0, 0xfd, 0x5, 0x46, 0xdd, 0x4, 0xff, 0xff, 0x60, 0x1a, 0x0, 0xfe, 0x2, 0x66, 0x3, 0xff, 0xfe, 0xdf, 0x2d, 0xa, 0x0, 0xfe, 0x4b, 0xe9, 0x3, 0xff, 0xfe, 0x47, 0x1, 0x1d, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x21, 0x0, 0xfe, 0x56, 0xf5, 0x3, 0xff, 0xff, 0xaa, 0x1a, 0x0, 0xfe, 0xa, 0xdc, 0x2, 0xff, 0xfe, 0xfa, 0xa0, 0xc, 0x0, 0xfe, 0xb9, 0xfe, 0x2, 0xff, 0xfe, 0xbf, 0x1, 0x1d, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x22, 0x0, 0xfe, 0xd2, 0xfe, 0x2, 0xff, 0xff, 0xd1, 0x1a, 0x0, 0xff, 0x5b, 0x3, 0xff, 0xfe, 0xe8, 0x35, 0xc, 0x0, 0xfe, 0x57, 0xef, 0x3, 0xff, 0xff, 0x3c, 0x1d, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x22, 0x0, 0xfe, 0xad, 0xfc, 0x2, 0xff, 0xff, 0xde, 0x19, 0x0, 0xfe, 0x3, 0xd4, 0x2, 0xff, 0xfe, 0xfc, 0xac, 0xd, 0x0, 0xfe, 0x1, 0xc6, 0x3, 0xff, 0xff, 0xb5, 0x1d, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xf, 0x0, 0xfd, 0xb, 0x0, 0x1, 0x10, 0x0, 0xfe, 0xb4, 0xfd, 0x2, 0xff, 0xff, 0xd1, 0x19, 0x0, 0xff, 0x50, 0x3, 0xff, 0xfe, 0xef, 0x40, 0xe, 0x0, 0xfe, 0x63, 0xf4, 0x2, 0xff, 0xfe, 0xfc, 0x31, 0x1c, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xe, 0x0, 0xfd, 0x2d, 0xc8, 0x40, 0x11, 0x0, 0xff, 0xdf, 0x3, 0xff, 0xff, 0xaa, 0x19, 0x0, 0xff, 0xcb, 0x2, 0xff, 0xfe, 0xfd, 0xba, 0xf, 0x0, 0xfe, 0x3, 0xd3, 0x3, 0xff, 0xff, 0xa9, 0x1c, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfb, 0x10, 0xd0, 0xff, 0xda, 0x5e, 0xd, 0x0, 0xfc, 0x1, 0x0, 0x6c, 0xf6, 0x3, 0xff, 0xff, 0x64, 0x18, 0x0, 0xfe, 0x46, 0xfe, 0x2, 0xff, 0xfe, 0xf4, 0x4c, 0x10, 0x0, 0xfe, 0x6f, 0xf7, 0x2, 0xff, 0xfe, 0xf8, 0x27, 0x1b, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xc, 0x0, 0xfe, 0x5, 0xb8, 0x3, 0xff, 0xfd, 0xea, 0x9e, 0x1e, 0xc, 0x0, 0xfe, 0x49, 0xe1, 0x3, 0xff, 0xfe, 0xf2, 0xf, 0x18, 0x0, 0xff, 0xc1, 0x2, 0xff, 0xfe, 0xfe, 0xc7, 0x11, 0x0, 0xfe, 0x8, 0xdf, 0x3, 0xff, 0xff, 0x9d, 0x1b, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xc, 0x0, 0xfe, 0x2, 0x9c, 0x4, 0xff, 0xfc, 0xfa, 0xdb, 0x93, 0x30, 0x8, 0x0, 0xfd, 0x18, 0x88, 0xe4, 0x4, 0xff, 0xff, 0x6f, 0x18, 0x0, 0xfe, 0x3b, 0xfa, 0x2, 0xff, 0xfe, 0xf5, 0x4b, 0x12, 0x0, 0xfe, 0x6d, 0xf9, 0x2, 0xff, 0xfe, 0xf4, 0x1d, 0x1a, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xff, 0xc5, 0x2c, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x12, 0x88, 0x5, 0xff, 0xf4, 0xf8, 0xeb, 0xd2, 0xa1, 0x7a, 0x64, 0x5f, 0x6b, 0x87, 0xbb, 0xe3, 0xf7, 0x4, 0xff, 0xfe, 0xa8, 0xa, 0x18, 0x0, 0xff, 0xb6, 0x3, 0xff, 0xfe, 0xfb, 0xb8, 0x11, 0xb1, 0xfd, 0xb0, 0xc2, 0xfc, 0x2, 0xff, 0xfe, 0xfe, 0x90, 0x1a, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfd, 0xe2, 0x7f, 0x79, 0xc, 0x7b, 0xfd, 0x7c, 0x6b, 0x2, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xe, 0x0, 0xfd, 0xb, 0x52, 0xe9, 0x6, 0xff, 0xfe, 0xfa, 0xf6, 0x2, 0xf3, 0xfd, 0xf4, 0xf7, 0xfd, 0x5, 0xff, 0xfe, 0xa1, 0x12, 0x18, 0x0, 0xfe, 0x31, 0xf5, 0x4, 0xff, 0xff, 0xfb, 0x13, 0xfc, 0x4, 0xff, 0xfe, 0xed, 0x13, 0x19, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xff, 0xfd, 0xe, 0xf6, 0xfd, 0xf8, 0xd7, 0x5, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xf, 0x0, 0xfc, 0x3, 0x1b, 0x81, 0xec, 0xe, 0xff, 0xfd, 0xe4, 0x5e, 0xd, 0x19, 0x0, 0xfe, 0xa8, 0xfd, 0x1c, 0xff, 0xfe, 0xfb, 0x84, 0x19, 0x0, 0xfe, 0x5, 0x6b, 0x13, 0xff, 0xfe, 0xe0, 0x5, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x11, 0x0, 0xfb, 0x5, 0x15, 0x59, 0xab, 0xeb, 0x8, 0xff, 0xfb, 0xf5, 0xb7, 0x5c, 0x13, 0x3, 0x19, 0x0, 0xfe, 0x29, 0xf6, 0x1e, 0xff, 0xfe, 0xeb, 0xd, 0x18, 0x0, 0xfe, 0x5, 0x6d, 0x13, 0xff, 0xfe, 0xe4, 0x5, 0x1b, 0x0, 0xfe, 0x1, 0x4f, 0x3, 0xff, 0xfe, 0xe0, 0x1b, 0x13, 0x0, 0xf2, 0x2, 0x5, 0xa, 0x1f, 0x45, 0x5f, 0x6a, 0x69, 0x62, 0x4b, 0x26, 0xc, 0x6, 0x3, 0x1b, 0x0, 0xfe, 0x36, 0x71, 0x1d, 0x73, 0xfd, 0x74, 0x6f, 0x26, 0x18, 0x0, 0xfd, 0x2, 0x31, 0x79, 0x11, 0x74, 0xfd, 0x75, 0x65, 0x2, 0x1b, 0x0, 0xf9, 0x1, 0x23, 0x78, 0x74, 0x76, 0x64, 0xc, 0x17, 0x0, 0xff, 0x1, 0x4, 0x2, 0xff, 0x1, 0x1f, 0x0, 0xff, 0x1, 0x20, 0x2, 0xff, 0x1, 0x19, 0x0, 0xff, 0x1, 0x14, 0x2, 0x1d, 0x0, 0xff, 0x1, 0x4, 0x2, 0x7f, 0x0, 0x3d, 0x0 -}; +const uint8_t salt_logo_1_data[1915] = { + 0x7f, 0x0, 0x3a, 0x0, 0xff, 0x1, 0x6, 0x2, 0xff, 0x1, 0x59, 0x0, + 0xfe, 0x1, 0x3, 0x3, 0x2, 0x22, 0x0, 0xff, 0x1, 0x1a, 0x2, 0x9, + 0x0, 0xf2, 0x1, 0x5, 0xd, 0x31, 0x5f, 0x79, 0x84, 0x83, 0x78, 0x5f, + 0x35, 0xf, 0x6, 0x3, 0x2b, 0x0, 0xfe, 0x19, 0x18, 0x28, 0x0, 0xf9, + 0x3, 0x36, 0x87, 0x81, 0x84, 0x65, 0x4, 0x21, 0x0, 0xfd, 0x33, 0x77, + 0x83, 0x16, 0x81, 0xfd, 0x85, 0x65, 0x14, 0x7, 0x0, 0xfc, 0xa, 0x38, + 0xa1, 0xed, 0x8, 0xff, 0xfb, 0xfa, 0xbd, 0x64, 0x16, 0x5, 0x28, 0x0, + 0xfd, 0x3, 0x90, 0x80, 0x28, 0x0, 0xfe, 0x5, 0x6d, 0x3, 0xff, 0xfe, + 0xcb, 0x8, 0x21, 0x0, 0xfe, 0x67, 0xef, 0x18, 0xff, 0xfe, 0xcb, 0x27, + 0x5, 0x0, 0xfd, 0x1, 0x24, 0xa8, 0xe, 0xff, 0xfc, 0xf2, 0x7d, 0x15, + 0x2, 0x26, 0x0, 0xfc, 0x3c, 0xdc, 0xc4, 0x2a, 0x27, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x21, 0x0, 0xfe, 0x65, 0xeb, 0x18, + 0xff, 0xfe, 0xc8, 0x27, 0x4, 0x0, 0xfd, 0x2, 0x3f, 0xe6, 0x4, 0xff, + 0xf9, 0xfd, 0xf6, 0xf2, 0xf1, 0xf2, 0xf4, 0xf9, 0x6, 0xff, 0xfd, 0xdb, + 0x3d, 0x5, 0x25, 0x0, 0xff, 0x7d, 0x2, 0xff, 0xff, 0x67, 0x27, 0x0, + 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x21, 0x0, 0xfd, 0x61, + 0xe0, 0xf6, 0x8, 0xf4, 0xff, 0xf7, 0x3, 0xff, 0xfe, 0xfd, 0xf5, 0x8, + 0xf4, 0xfd, 0xfb, 0xbf, 0x25, 0x4, 0x0, 0xfe, 0x31, 0xf0, 0x3, 0xff, + 0xf4, 0xfb, 0xe7, 0xb9, 0x79, 0x57, 0x4d, 0x55, 0x6c, 0x95, 0xca, 0xe8, + 0xf6, 0x5, 0xff, 0xff, 0x5a, 0x24, 0x0, 0xfe, 0x33, 0xcb, 0x2, 0xff, + 0xfe, 0xb4, 0x22, 0x26, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, + 0x8, 0x21, 0x0, 0xfd, 0x29, 0x60, 0x6a, 0x7, 0x69, 0xfe, 0x6a, 0x96, + 0x3, 0xff, 0xfd, 0xea, 0x78, 0x67, 0x7, 0x69, 0xfd, 0x6c, 0x52, 0x10, + 0x3, 0x0, 0xfe, 0x10, 0xc5, 0x3, 0xff, 0xfd, 0xf7, 0xad, 0x29, 0x8, + 0x0, 0xfc, 0x25, 0x87, 0xda, 0xfa, 0x3, 0xff, 0xfe, 0xcb, 0x1, 0x23, + 0x0, 0xff, 0x70, 0x3, 0xff, 0xfe, 0xfd, 0x5a, 0x26, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2c, 0x0, 0xff, 0x48, 0x3, 0xff, + 0xfe, 0xda, 0x14, 0xd, 0x0, 0xfe, 0x2, 0x50, 0x3, 0xff, 0xfe, 0xf9, + 0x9c, 0xc, 0x0, 0xfa, 0x19, 0xa1, 0xef, 0xff, 0xdc, 0x1b, 0x23, 0x0, + 0xfe, 0x2a, 0xc2, 0x4, 0xff, 0xfe, 0xa9, 0x1b, 0x25, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x5, 0xb1, 0x3, 0xff, 0xfe, + 0xd1, 0x16, 0xe, 0x0, 0xfd, 0x76, 0xdc, 0x36, 0x24, 0x0, 0xff, 0x63, + 0x5, 0xff, 0xfe, 0xf8, 0x4e, 0x25, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, + 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, + 0x1b, 0xd, 0x0, 0xfe, 0x7, 0xe9, 0x2, 0xff, 0xfe, 0xfb, 0xa0, 0x10, + 0x0, 0xff, 0x24, 0x24, 0x0, 0xfe, 0x21, 0xb9, 0x6, 0xff, 0xfe, 0x9d, + 0x14, 0x24, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, + 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xff, + 0x8, 0x3, 0xff, 0xfe, 0xf4, 0x82, 0x35, 0x0, 0xff, 0x55, 0x3, 0xff, + 0x2, 0xf9, 0x2, 0xff, 0xfe, 0xf2, 0x42, 0x24, 0x0, 0xfe, 0x5, 0x6b, + 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, + 0xfe, 0xdb, 0x1b, 0xd, 0x0, 0xfe, 0x8, 0xfe, 0x2, 0xff, 0xfe, 0xfa, + 0x9c, 0x34, 0x0, 0xfe, 0x1a, 0xae, 0x3, 0xff, 0xfe, 0xb8, 0xbe, 0x3, + 0xff, 0xfe, 0x8f, 0xf, 0x23, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, + 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, + 0xd, 0x0, 0xfe, 0x7, 0xde, 0x3, 0xff, 0xfe, 0xda, 0x29, 0x33, 0x0, + 0xfe, 0x49, 0xfe, 0x2, 0xff, 0xfc, 0xe7, 0x46, 0x5d, 0xf5, 0x2, 0xff, + 0xfe, 0xec, 0x37, 0x23, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, + 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xd, + 0x0, 0xfe, 0x5, 0x9b, 0x3, 0xff, 0xfc, 0xfd, 0xbe, 0x36, 0x6, 0x30, + 0x0, 0xfe, 0x13, 0xa3, 0x3, 0xff, 0xfc, 0xa6, 0xa, 0x1d, 0xbb, 0x3, + 0xff, 0xfe, 0x82, 0xb, 0x22, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, + 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, + 0xd, 0x0, 0xfd, 0x1, 0x3d, 0xfd, 0x4, 0xff, 0xfc, 0xdf, 0x7a, 0x3e, + 0x1b, 0x2e, 0x0, 0xfe, 0x3e, 0xf9, 0x2, 0xff, 0xfe, 0xec, 0x5f, 0x2, + 0x0, 0xfe, 0x77, 0xf8, 0x2, 0xff, 0xfe, 0xe6, 0x2c, 0x22, 0x0, 0xfe, + 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, + 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xe, 0x0, 0xfe, 0x3, 0x93, 0x6, 0xff, + 0xfa, 0xe6, 0xa6, 0x70, 0x49, 0x2c, 0xd, 0x29, 0x0, 0xfe, 0xe, 0x96, + 0x3, 0xff, 0xfe, 0xb3, 0x14, 0x2, 0x0, 0xfe, 0x26, 0xc6, 0x3, 0xff, + 0xfe, 0x76, 0x8, 0x21, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, + 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xf, + 0x0, 0xfd, 0x11, 0xa0, 0xfa, 0x7, 0xff, 0xfa, 0xec, 0xbf, 0x93, 0x66, + 0x40, 0x19, 0x26, 0x0, 0xfe, 0x33, 0xf4, 0x2, 0xff, 0xfe, 0xf0, 0x6c, + 0x4, 0x0, 0xfe, 0x85, 0xfa, 0x2, 0xff, 0xfe, 0xe0, 0x22, 0x21, 0x0, + 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, + 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x10, 0x0, 0xfd, 0xe, 0x7b, 0xd2, + 0xa, 0xff, 0xfc, 0xd9, 0xa6, 0x70, 0x39, 0x23, 0x0, 0xfe, 0xa, 0x8a, + 0x3, 0xff, 0xfe, 0xbf, 0x19, 0x4, 0x0, 0xfe, 0x2d, 0xd0, 0x3, 0xff, + 0xfe, 0x69, 0x6, 0x20, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, + 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x12, + 0x0, 0xfc, 0x3c, 0x87, 0xc2, 0xf2, 0xa, 0xff, 0xfd, 0xce, 0x89, 0x39, + 0x21, 0x0, 0xfe, 0x28, 0xef, 0x2, 0xff, 0xfe, 0xf4, 0x79, 0x6, 0x0, + 0xfe, 0x92, 0xfb, 0x2, 0xff, 0xfe, 0xd9, 0x18, 0x20, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0x14, 0x0, 0xfb, 0x2d, 0x60, 0x90, 0xbd, 0xe9, + 0x9, 0xff, 0xfd, 0xcd, 0x6c, 0x2, 0x1e, 0x0, 0xfe, 0x6, 0x7d, 0x3, + 0xff, 0xfe, 0xcb, 0x1e, 0x6, 0x0, 0xfe, 0x36, 0xda, 0x3, 0xff, 0xfe, + 0x5d, 0x4, 0x1f, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, + 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x16, 0x0, + 0xf9, 0x4, 0x2b, 0x50, 0x75, 0x9e, 0xcc, 0xfc, 0x6, 0xff, 0xfe, 0xf5, + 0x83, 0x1e, 0x0, 0xfe, 0x1d, 0xe9, 0x2, 0xff, 0xfe, 0xf6, 0x86, 0x8, + 0x0, 0xfe, 0x9f, 0xfc, 0x2, 0xff, 0xfe, 0xd1, 0xf, 0x1f, 0x0, 0xfe, + 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, + 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x1a, 0x0, 0xfb, 0x12, 0x36, 0x5c, 0x90, + 0xd7, 0x5, 0xff, 0xfe, 0xfb, 0x60, 0x1c, 0x0, 0xfe, 0x4, 0x71, 0x3, + 0xff, 0xfe, 0xd6, 0x24, 0x8, 0x0, 0xfe, 0x40, 0xe3, 0x3, 0xff, 0xfe, + 0x52, 0x2, 0x1e, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, + 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x1d, 0x0, + 0xfc, 0xd, 0x39, 0x7c, 0xe8, 0x4, 0xff, 0xfe, 0xe3, 0x11, 0x1b, 0x0, + 0xfe, 0x13, 0xe3, 0x2, 0xff, 0xfe, 0xf8, 0x93, 0xa, 0x0, 0xfe, 0xac, + 0xfd, 0x2, 0xff, 0xfe, 0xc9, 0x8, 0x1e, 0x0, 0xfe, 0x5, 0x6b, 0x3, + 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, + 0xdb, 0x1b, 0x1f, 0x0, 0xfd, 0x5, 0x46, 0xdd, 0x4, 0xff, 0xff, 0x60, + 0x1a, 0x0, 0xfe, 0x2, 0x66, 0x3, 0xff, 0xfe, 0xdf, 0x2d, 0xa, 0x0, + 0xfe, 0x4b, 0xe9, 0x3, 0xff, 0xfe, 0x47, 0x1, 0x1d, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0x21, 0x0, 0xfe, 0x56, 0xf5, 0x3, 0xff, 0xff, + 0xaa, 0x1a, 0x0, 0xfe, 0xa, 0xdc, 0x2, 0xff, 0xfe, 0xfa, 0xa0, 0xc, + 0x0, 0xfe, 0xb9, 0xfe, 0x2, 0xff, 0xfe, 0xbf, 0x1, 0x1d, 0x0, 0xfe, + 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, + 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x22, 0x0, 0xfe, 0xd2, 0xfe, 0x2, 0xff, + 0xff, 0xd1, 0x1a, 0x0, 0xff, 0x5b, 0x3, 0xff, 0xfe, 0xe8, 0x35, 0xc, + 0x0, 0xfe, 0x57, 0xef, 0x3, 0xff, 0xff, 0x3c, 0x1d, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0x22, 0x0, 0xfe, 0xad, 0xfc, 0x2, 0xff, 0xff, + 0xde, 0x19, 0x0, 0xfe, 0x3, 0xd4, 0x2, 0xff, 0xfe, 0xfc, 0xac, 0xd, + 0x0, 0xfe, 0x1, 0xc6, 0x3, 0xff, 0xff, 0xb5, 0x1d, 0x0, 0xfe, 0x5, + 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0xf, 0x0, 0xfd, 0xb, 0x0, 0x1, 0x10, 0x0, + 0xfe, 0xb4, 0xfd, 0x2, 0xff, 0xff, 0xd1, 0x19, 0x0, 0xff, 0x50, 0x3, + 0xff, 0xfe, 0xef, 0x40, 0xe, 0x0, 0xfe, 0x63, 0xf4, 0x2, 0xff, 0xfe, + 0xfc, 0x31, 0x1c, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, 0xc7, 0x8, + 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0xe, 0x0, + 0xfd, 0x2d, 0xc8, 0x40, 0x11, 0x0, 0xff, 0xdf, 0x3, 0xff, 0xff, 0xaa, + 0x19, 0x0, 0xff, 0xcb, 0x2, 0xff, 0xfe, 0xfd, 0xba, 0xf, 0x0, 0xfe, + 0x3, 0xd3, 0x3, 0xff, 0xff, 0xa9, 0x1c, 0x0, 0xfe, 0x5, 0x6b, 0x3, + 0xff, 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, + 0xdb, 0x1b, 0xd, 0x0, 0xfb, 0x10, 0xd0, 0xff, 0xda, 0x5e, 0xd, 0x0, + 0xfc, 0x1, 0x0, 0x6c, 0xf6, 0x3, 0xff, 0xff, 0x64, 0x18, 0x0, 0xfe, + 0x46, 0xfe, 0x2, 0xff, 0xfe, 0xf4, 0x4c, 0x10, 0x0, 0xfe, 0x6f, 0xf7, + 0x2, 0xff, 0xfe, 0xf8, 0x27, 0x1b, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, + 0xfe, 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, + 0x1b, 0xc, 0x0, 0xfe, 0x5, 0xb8, 0x3, 0xff, 0xfd, 0xea, 0x9e, 0x1e, + 0xc, 0x0, 0xfe, 0x49, 0xe1, 0x3, 0xff, 0xfe, 0xf2, 0xf, 0x18, 0x0, + 0xff, 0xc1, 0x2, 0xff, 0xfe, 0xfe, 0xc7, 0x11, 0x0, 0xfe, 0x8, 0xdf, + 0x3, 0xff, 0xff, 0x9d, 0x1b, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfe, + 0xc7, 0x8, 0x2b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, + 0xc, 0x0, 0xfe, 0x2, 0x9c, 0x4, 0xff, 0xfc, 0xfa, 0xdb, 0x93, 0x30, + 0x8, 0x0, 0xfd, 0x18, 0x88, 0xe4, 0x4, 0xff, 0xff, 0x6f, 0x18, 0x0, + 0xfe, 0x3b, 0xfa, 0x2, 0xff, 0xfe, 0xf5, 0x4b, 0x12, 0x0, 0xfe, 0x6d, + 0xf9, 0x2, 0xff, 0xfe, 0xf4, 0x1d, 0x1a, 0x0, 0xfe, 0x5, 0x6b, 0x3, + 0xff, 0xff, 0xc5, 0x2c, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, + 0x1b, 0xd, 0x0, 0xfe, 0x12, 0x88, 0x5, 0xff, 0xf4, 0xf8, 0xeb, 0xd2, + 0xa1, 0x7a, 0x64, 0x5f, 0x6b, 0x87, 0xbb, 0xe3, 0xf7, 0x4, 0xff, 0xfe, + 0xa8, 0xa, 0x18, 0x0, 0xff, 0xb6, 0x3, 0xff, 0xfe, 0xfb, 0xb8, 0x11, + 0xb1, 0xfd, 0xb0, 0xc2, 0xfc, 0x2, 0xff, 0xfe, 0xfe, 0x90, 0x1a, 0x0, + 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xfd, 0xe2, 0x7f, 0x79, 0xc, 0x7b, 0xfd, + 0x7c, 0x6b, 0x2, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, + 0x1b, 0xe, 0x0, 0xfd, 0xb, 0x52, 0xe9, 0x6, 0xff, 0xfe, 0xfa, 0xf6, + 0x2, 0xf3, 0xfd, 0xf4, 0xf7, 0xfd, 0x5, 0xff, 0xfe, 0xa1, 0x12, 0x18, + 0x0, 0xfe, 0x31, 0xf5, 0x4, 0xff, 0xff, 0xfb, 0x13, 0xfc, 0x4, 0xff, + 0xfe, 0xed, 0x13, 0x19, 0x0, 0xfe, 0x5, 0x6b, 0x3, 0xff, 0xff, 0xfd, + 0xe, 0xf6, 0xfd, 0xf8, 0xd7, 0x5, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, + 0xff, 0xfe, 0xdb, 0x1b, 0xf, 0x0, 0xfc, 0x3, 0x1b, 0x81, 0xec, 0xe, + 0xff, 0xfd, 0xe4, 0x5e, 0xd, 0x19, 0x0, 0xfe, 0xa8, 0xfd, 0x1c, 0xff, + 0xfe, 0xfb, 0x84, 0x19, 0x0, 0xfe, 0x5, 0x6b, 0x13, 0xff, 0xfe, 0xe0, + 0x5, 0x1b, 0x0, 0xfe, 0x1, 0x4e, 0x3, 0xff, 0xfe, 0xdb, 0x1b, 0x11, + 0x0, 0xfb, 0x5, 0x15, 0x59, 0xab, 0xeb, 0x8, 0xff, 0xfb, 0xf5, 0xb7, + 0x5c, 0x13, 0x3, 0x19, 0x0, 0xfe, 0x29, 0xf6, 0x1e, 0xff, 0xfe, 0xeb, + 0xd, 0x18, 0x0, 0xfe, 0x5, 0x6d, 0x13, 0xff, 0xfe, 0xe4, 0x5, 0x1b, + 0x0, 0xfe, 0x1, 0x4f, 0x3, 0xff, 0xfe, 0xe0, 0x1b, 0x13, 0x0, 0xf2, + 0x2, 0x5, 0xa, 0x1f, 0x45, 0x5f, 0x6a, 0x69, 0x62, 0x4b, 0x26, 0xc, + 0x6, 0x3, 0x1b, 0x0, 0xfe, 0x36, 0x71, 0x1d, 0x73, 0xfd, 0x74, 0x6f, + 0x26, 0x18, 0x0, 0xfd, 0x2, 0x31, 0x79, 0x11, 0x74, 0xfd, 0x75, 0x65, + 0x2, 0x1b, 0x0, 0xf9, 0x1, 0x23, 0x78, 0x74, 0x76, 0x64, 0xc, 0x17, + 0x0, 0xff, 0x1, 0x4, 0x2, 0xff, 0x1, 0x1f, 0x0, 0xff, 0x1, 0x20, + 0x2, 0xff, 0x1, 0x19, 0x0, 0xff, 0x1, 0x14, 0x2, 0x1d, 0x0, 0xff, + 0x1, 0x4, 0x2, 0x7f, 0x0, 0x3d, 0x0}; static const Image salt_logo_1_image = {175, 40, 1915, salt_logo_1_data}; -const VariantAnimation salt_logo = { - 21, - { - {40, 12, 25, 0, &salt_logo_1_image}, - {40, 12, 25, 5, &salt_logo_1_image}, - {40, 12, 25, 10, &salt_logo_1_image}, - {40, 12, 25, 15, &salt_logo_1_image}, - {40, 12, 25, 20, &salt_logo_1_image}, - {40, 12, 25, 25, &salt_logo_1_image}, - {40, 12, 25, 30, &salt_logo_1_image}, - {40, 12, 25, 35, &salt_logo_1_image}, - {40, 12, 25, 40, &salt_logo_1_image}, - {40, 12, 25, 45, &salt_logo_1_image}, - {40, 12, 25, 50, &salt_logo_1_image}, - {40, 12, 25, 55, &salt_logo_1_image}, - {40, 12, 25, 60, &salt_logo_1_image}, - {40, 12, 25, 65, &salt_logo_1_image}, - {40, 12, 25, 70, &salt_logo_1_image}, - {40, 12, 25, 75, &salt_logo_1_image}, - {40, 12, 25, 80, &salt_logo_1_image}, - {40, 12, 25, 85, &salt_logo_1_image}, - {40, 12, 25, 90, &salt_logo_1_image}, - {40, 12, 25, 95, &salt_logo_1_image}, - {40, 12, 25, 100, &salt_logo_1_image}, - } -}; +const VariantAnimation salt_logo = {21, + { + {40, 12, 25, 0, &salt_logo_1_image}, + {40, 12, 25, 5, &salt_logo_1_image}, + {40, 12, 25, 10, &salt_logo_1_image}, + {40, 12, 25, 15, &salt_logo_1_image}, + {40, 12, 25, 20, &salt_logo_1_image}, + {40, 12, 25, 25, &salt_logo_1_image}, + {40, 12, 25, 30, &salt_logo_1_image}, + {40, 12, 25, 35, &salt_logo_1_image}, + {40, 12, 25, 40, &salt_logo_1_image}, + {40, 12, 25, 45, &salt_logo_1_image}, + {40, 12, 25, 50, &salt_logo_1_image}, + {40, 12, 25, 55, &salt_logo_1_image}, + {40, 12, 25, 60, &salt_logo_1_image}, + {40, 12, 25, 65, &salt_logo_1_image}, + {40, 12, 25, 70, &salt_logo_1_image}, + {40, 12, 25, 75, &salt_logo_1_image}, + {40, 12, 25, 80, &salt_logo_1_image}, + {40, 12, 25, 85, &salt_logo_1_image}, + {40, 12, 25, 90, &salt_logo_1_image}, + {40, 12, 25, 95, &salt_logo_1_image}, + {40, 12, 25, 100, &salt_logo_1_image}, + }}; const VariantAnimation salt_logo_reversed = { - 21, - { - {40, 12, 25, 100, &salt_logo_1_image}, - {40, 12, 25, 95, &salt_logo_1_image}, - {40, 12, 25, 90, &salt_logo_1_image}, - {40, 12, 25, 85, &salt_logo_1_image}, - {40, 12, 25, 80, &salt_logo_1_image}, - {40, 12, 25, 75, &salt_logo_1_image}, - {40, 12, 25, 70, &salt_logo_1_image}, - {40, 12, 25, 65, &salt_logo_1_image}, - {40, 12, 25, 60, &salt_logo_1_image}, - {40, 12, 25, 55, &salt_logo_1_image}, - {40, 12, 25, 50, &salt_logo_1_image}, - {40, 12, 25, 45, &salt_logo_1_image}, - {40, 12, 25, 40, &salt_logo_1_image}, - {40, 12, 25, 35, &salt_logo_1_image}, - {40, 12, 25, 30, &salt_logo_1_image}, - {40, 12, 25, 25, &salt_logo_1_image}, - {40, 12, 25, 20, &salt_logo_1_image}, - {40, 12, 25, 15, &salt_logo_1_image}, - {40, 12, 25, 10, &salt_logo_1_image}, - {40, 12, 25, 5, &salt_logo_1_image}, - {40, 12, 25, 0, &salt_logo_1_image} - } -}; + 21, {{40, 12, 25, 100, &salt_logo_1_image}, + {40, 12, 25, 95, &salt_logo_1_image}, + {40, 12, 25, 90, &salt_logo_1_image}, + {40, 12, 25, 85, &salt_logo_1_image}, + {40, 12, 25, 80, &salt_logo_1_image}, + {40, 12, 25, 75, &salt_logo_1_image}, + {40, 12, 25, 70, &salt_logo_1_image}, + {40, 12, 25, 65, &salt_logo_1_image}, + {40, 12, 25, 60, &salt_logo_1_image}, + {40, 12, 25, 55, &salt_logo_1_image}, + {40, 12, 25, 50, &salt_logo_1_image}, + {40, 12, 25, 45, &salt_logo_1_image}, + {40, 12, 25, 40, &salt_logo_1_image}, + {40, 12, 25, 35, &salt_logo_1_image}, + {40, 12, 25, 30, &salt_logo_1_image}, + {40, 12, 25, 25, &salt_logo_1_image}, + {40, 12, 25, 20, &salt_logo_1_image}, + {40, 12, 25, 15, &salt_logo_1_image}, + {40, 12, 25, 10, &salt_logo_1_image}, + {40, 12, 25, 5, &salt_logo_1_image}, + {40, 12, 25, 0, &salt_logo_1_image}}}; const VariantAnimation salt_screensaver = { 82, @@ -163,6 +314,4 @@ const VariantAnimation salt_screensaver = { {34, 10, 150, 60, &salt_logo_1_image}, {36, 10, 150, 60, &salt_logo_1_image}, {38, 10, 150, 60, &salt_logo_1_image}, - } -}; - + }}; diff --git a/lib/variant/salt/salt.c b/lib/variant/salt/salt.c index 99bcd75a7..e728c9b60 100644 --- a/lib/variant/salt/salt.c +++ b/lib/variant/salt/salt.c @@ -3,7 +3,4 @@ #include "keepkey/board/timer.h" #include "keepkey/board/variant.h" -const VariantInfo variant_salt = { - VARIANTINFO_SALT -}; - +const VariantInfo variant_salt = {VARIANTINFO_SALT}; diff --git a/scripts/format-source-files.sh b/scripts/format-source-files.sh new file mode 100755 index 000000000..90a373d88 --- /dev/null +++ b/scripts/format-source-files.sh @@ -0,0 +1,10 @@ +#! /bin/bash -e + +KEEPKEY_FIRMWARE="$(dirname "$( cd "$(dirname "$0")" ; pwd -P )")" +declare -a subdirs=("docs" "fuzzer" "include" "lib" "scripts" "tools" "unittests") +cd $KEEPKEY_FIRMWARE + +for i in "${subdirs[@]}" +do + find ./${i} -name '*.c' -o -name '*.h' -o -name '*.cpp' -o -name '*.hpp' | xargs clang-format -i --verbose -style=file +done \ No newline at end of file diff --git a/tools/blupdater/header.s b/tools/blupdater/header.s index 431a706fa..e8534bd5a 100644 --- a/tools/blupdater/header.s +++ b/tools/blupdater/header.s @@ -11,8 +11,9 @@ g_header: .byte 0 // sigindex1 .byte 0 // sigindex2 .byte 0 // sigindex3 - .byte 3 // flags: Preserve | UpdateAfter - . = . + 52 // reserved + .byte 1 // sig_flag: Preserve + .word 1 // meta_flags: UpdateAfter + . = . + 48 // reserved . = . + 64 // sig1 . = . + 64 // sig2 . = . + 64 // sig3 diff --git a/tools/blupdater/main.c b/tools/blupdater/main.c index 84ba8c511..62928a995 100644 --- a/tools/blupdater/main.c +++ b/tools/blupdater/main.c @@ -59,12 +59,12 @@ #include #define NUM_RETRIES 8 -#define CHUNK_SIZE 0x100 +#define CHUNK_SIZE 0x100 -#define BL_VERSION \ - VERSION_STR(BOOTLOADER_MAJOR_VERSION) "." \ - VERSION_STR(BOOTLOADER_MINOR_VERSION) "." \ - VERSION_STR(BOOTLOADER_PATCH_VERSION) +#define BL_VERSION \ + VERSION_STR(BOOTLOADER_MAJOR_VERSION) \ + "." VERSION_STR(BOOTLOADER_MINOR_VERSION) "." VERSION_STR( \ + BOOTLOADER_PATCH_VERSION) static uint8_t payload_hash[SHA256_DIGEST_LENGTH]; extern const uint8_t _binary_payload_bin_start[]; @@ -76,67 +76,71 @@ void mpu_blup(void); /* These variables will be used by host application to read the version info */ static const char *const application_version -__attribute__((used, section("version"))) = "VERSION" BL_VERSION; + __attribute__((used, section("version"))) = "VERSION" BL_VERSION; /// \returns true iff there was a problem while writing. -static bool write_bootloader(void) -{ - static uint8_t hash[SHA256_DIGEST_LENGTH]; +static bool write_bootloader(void) { + static uint8_t hash[SHA256_DIGEST_LENGTH]; + memset(hash, 0, sizeof(hash)); + sha256_Raw((const uint8_t *)_binary_payload_bin_start, + _binary_payload_bin_size, hash); + + for (int i = 0; i < NUM_RETRIES; ++i) { + // Enable writing to the read-only sectors + memory_unlock(); + flash_unlock(); + + // erase the bootloader sectors, do not use flash_erase_word() + layoutProgress("Updating. DO NOT UNPLUG", 0); + flash_erase_sector(5, FLASH_CR_PROGRAM_X32); + flash_wait_for_last_operation(); + layoutProgress("Updating. DO NOT UNPLUG", 100); + flash_erase_sector(6, FLASH_CR_PROGRAM_X32); + flash_wait_for_last_operation(); + + // Write into the sector. + for (int chunkstart = 0; chunkstart < _binary_payload_bin_size; + chunkstart += CHUNK_SIZE) { + layoutProgress("Updating. DO NOT UNPLUG", + 200 + chunkstart * 800 / _binary_payload_bin_size); + + size_t chunksize; + if (_binary_payload_bin_size > chunkstart + CHUNK_SIZE) { + chunksize = CHUNK_SIZE; + } else { + chunksize = _binary_payload_bin_size - chunkstart; + } + + flash_program((uint32_t)(FLASH_BOOT_START + chunkstart), + &_binary_payload_bin_start[chunkstart], chunksize); + flash_wait_for_last_operation(); + } + + // Disallow writing to flash. + flash_lock(); + + // Ignore any reported errors, we only care about the end result. + flash_clear_status_flags(); + memset(hash, 0, sizeof(hash)); - sha256_Raw((const uint8_t*)_binary_payload_bin_start, _binary_payload_bin_size, hash); - - for (int i = 0; i < NUM_RETRIES; ++i) { - // Enable writing to the read-only sectors - memory_unlock(); - flash_unlock(); - - // erase the bootloader sectors, do not use flash_erase_word() - layoutProgress("Updating. DO NOT UNPLUG", 0); - flash_erase_sector(5, FLASH_CR_PROGRAM_X32); - flash_wait_for_last_operation(); - layoutProgress("Updating. DO NOT UNPLUG", 100); - flash_erase_sector(6, FLASH_CR_PROGRAM_X32); - flash_wait_for_last_operation(); - - // Write into the sector. - for (int chunkstart = 0; chunkstart < _binary_payload_bin_size; chunkstart += CHUNK_SIZE) { - layoutProgress("Updating. DO NOT UNPLUG", 200 + chunkstart * 800 / _binary_payload_bin_size); - - size_t chunksize; - if (_binary_payload_bin_size > chunkstart+CHUNK_SIZE) { - chunksize = CHUNK_SIZE; - } else { - chunksize = _binary_payload_bin_size - chunkstart; - } - - flash_program((uint32_t)(FLASH_BOOT_START+chunkstart), &_binary_payload_bin_start[chunkstart], chunksize); - flash_wait_for_last_operation(); - } - - // Disallow writing to flash. - flash_lock(); - - // Ignore any reported errors, we only care about the end result. - flash_clear_status_flags(); - - memset(hash, 0, sizeof(hash)); - sha256_Raw((const uint8_t*)FLASH_BOOT_START, _binary_payload_bin_size, hash); - - if (!memcmp(hash, payload_hash, sizeof(hash))) { - // Success - return false; - } + sha256_Raw((const uint8_t *)FLASH_BOOT_START, _binary_payload_bin_size, + hash); + + if (!memcmp(hash, payload_hash, sizeof(hash))) { + // Success + return false; } + } - // Failure - return true; + // Failure + return true; } /// \returns true iff the bootloader is something we don't recognize static bool unknown_bootloader(void) { - switch (get_bootloaderKind()) { + switch (get_bootloaderKind()) { case BLK_UNKNOWN: - return true; + return true; case BLK_v1_0_0: case BLK_v1_0_1: @@ -147,31 +151,31 @@ static bool unknown_bootloader(void) { case BLK_v1_0_4: case BLK_v1_1_0: case BLK_v2_0_0: - return false; - } + case BLK_v2_1_0: + return false; + } - __builtin_unreachable(); + __builtin_unreachable(); } /// \brief Success: everything went smoothly as expected, and the device has a /// new bootloader installed. static void success(void) { - layout_standard_notification("Bootloader Update Complete", - "Your device will now restart", - NOTIFICATION_CONFIRMED); - display_refresh(); - delay_ms(3000); - board_reset(); + layout_standard_notification("Bootloader Update Complete", + "Your device will now restart", + NOTIFICATION_CONFIRMED); + display_refresh(); + delay_ms(3000); + board_reset(); } /// \brief Hard Failure: something went wrong during the write, and it's /// exceedingly unlikely that we'll be able to recover. static void failure(void) { - layout_warning_static("Update failed. Please contact support."); - display_refresh(); + layout_warning_static("Update failed. Please contact support."); + display_refresh(); } - /// \brief Byte-wise substring search, using the Two-Way algorithm. /// /// Locates the first occurrence in the memory region pointed to @@ -189,142 +193,144 @@ static void failure(void) { /// https://github.com/eblot/newlib/blob/2a63fa0fd26ffb6603f69d9e369e944fe449c246/newlib/libc/string/memmem.c static void *memmem(const void *haystack_start, size_t haystack_len, const void *needle_start, size_t needle_len) { - /* Abstract memory is considered to be an array of 'unsigned char' values, - not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ - const unsigned char *haystack = (const unsigned char *) haystack_start; - const unsigned char *needle = (const unsigned char *) needle_start; - - if (needle_len == 0) { - /* The first occurrence of the empty string is deemed to occur at - the beginning of the string. */ - return (void*)haystack; - } - - /* Less code size, but quadratic performance in the worst case. */ - while (needle_len <= haystack_len) { - if (!memcmp(haystack, needle, needle_len)) - return (void*)haystack; - haystack++; - haystack_len--; - } - return NULL; + /* Abstract memory is considered to be an array of 'unsigned char' values, + not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ + const unsigned char *haystack = (const unsigned char *)haystack_start; + const unsigned char *needle = (const unsigned char *)needle_start; + + if (needle_len == 0) { + /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + return (void *)haystack; + } + + /* Less code size, but quadratic performance in the worst case. */ + while (needle_len <= haystack_len) { + if (!memcmp(haystack, needle, needle_len)) return (void *)haystack; + haystack++; + haystack_len--; + } + return NULL; } -int main(void) -{ - _buttonusr_isr = (void *)&buttonisr_usr; - _timerusr_isr = (void *)&timerisr_usr; - _mmhusr_isr = (void *)&mmhisr; +int main(void) { + _buttonusr_isr = (void *)&buttonisr_usr; + _timerusr_isr = (void *)&timerisr_usr; + _mmhusr_isr = (void *)&mmhisr; - mpu_blup(); + mpu_blup(); - // Legacy bootloader code will have interrupts disabled at this point. To maintain compatibility, the timer - // and button interrupts need to be enabled and then global interrupts enabled. This is a nop in the modern - // scheme - cm_enable_interrupts(); + // Legacy bootloader code will have interrupts disabled at this point. To + // maintain compatibility, the timer and button interrupts need to be enabled + // and then global interrupts enabled. This is a nop in the modern scheme + cm_enable_interrupts(); - kk_board_init(); + kk_board_init(); - memset(payload_hash, 0, sizeof(payload_hash)); - _binary_payload_bin_size = _binary_payload_bin_end - _binary_payload_bin_start; - sha256_Raw((const uint8_t*)_binary_payload_bin_start, _binary_payload_bin_size, payload_hash); + memset(payload_hash, 0, sizeof(payload_hash)); + _binary_payload_bin_size = + _binary_payload_bin_end - _binary_payload_bin_start; + sha256_Raw((const uint8_t *)_binary_payload_bin_start, + _binary_payload_bin_size, payload_hash); -#ifndef DEBUG_ON // for testing, update every time even if it's the same bl - // Check if we've already updated - static uint8_t hash[SHA256_DIGEST_LENGTH]; - memset(hash, 0, sizeof(hash)); - sha256_Raw((const uint8_t*)FLASH_BOOT_START, _binary_payload_bin_size, hash); +#ifndef DEBUG_ON // for testing, update every time even if it's the same bl + // Check if we've already updated + static uint8_t hash[SHA256_DIGEST_LENGTH]; + memset(hash, 0, sizeof(hash)); + sha256_Raw((const uint8_t *)FLASH_BOOT_START, _binary_payload_bin_size, hash); - if (!memcmp(hash, payload_hash, sizeof(hash))) { - success(); - return 0; - } + if (!memcmp(hash, payload_hash, sizeof(hash))) { + success(); + return 0; + } #endif - // Check that we're familiar with this bootloader, and refuse to update - // anything we don't recognize. This prevents use of this tool in a - // hypothetical bootloader downgrade attack. - if (unknown_bootloader()) { + // Check that we're familiar with this bootloader, and refuse to update + // anything we don't recognize. This prevents use of this tool in a + // hypothetical bootloader downgrade attack. + if (unknown_bootloader()) { #ifndef DEBUG_ON - layout_warning_static("Unknown bootloader. Please contact support."); - display_refresh(); - return 0; + layout_warning_static("Unknown bootloader. Please contact support."); + display_refresh(); + return 0; #endif - } - - // Make sure that we cannot mismatch BL_VERSION with the version string - // that's actually in the bootloader we're about to write to the device. - // This implies that the version of blupdater, and the bootloader it writes - // must always be the same. - if (!memmem((const char*)_binary_payload_bin_start, _binary_payload_bin_size, - application_version, strlen(application_version))) { + } + + // Make sure that we cannot mismatch BL_VERSION with the version string + // that's actually in the bootloader we're about to write to the device. + // This implies that the version of blupdater, and the bootloader it writes + // must always be the same. + if (!memmem((const char *)_binary_payload_bin_start, _binary_payload_bin_size, + application_version, strlen(application_version))) { #ifndef DEBUG_ON - layout_warning_static("version mismatch"); - display_refresh(); - return 0; + layout_warning_static("version mismatch"); + display_refresh(); + return 0; #endif - } + } - // Shove the model # into OTP if it wasn't already there. - (void)flash_programModel(); + // Shove the model # into OTP if it wasn't already there. + (void)flash_programModel(); - // Add Storage Protection magic, since older firmwares have never written it. - Allocation active_storage; - if (find_active_storage(&active_storage)) { - storage_protect_off(); - } + // Add Storage Protection magic, since older firmwares have never written it. + Allocation active_storage; + if (find_active_storage(&active_storage)) { + storage_protect_off(); + } - if (write_bootloader()) { - failure(); - return 0; - } - - success(); + if (write_bootloader()) { + failure(); return 0; + } + + success(); + return 0; } /* - The blupdater scheme is designed to run as a privileged mode fw version. The blupdater must be signed just as - any other kk defined firmware, however the bootloader needs to distinguish this firmware from normal operating - firmware. This is the ethernet DMA isr (61), extremely unlikely to ever be required in a kk device. This unique vector - can be read by the bootloader that will then subsequently allow continuation in a mode appropriate for the blupdater, - that is, privileged mode execution using its own vector table. + The blupdater scheme is designed to run as a privileged mode fw version. The + blupdater must be signed just as any other kk defined firmware, however the + bootloader needs to distinguish this firmware from normal operating firmware. + This is the ethernet DMA isr (61), extremely unlikely to ever be required in + a kk device. This unique vector can be read by the bootloader that will then + subsequently allow continuation in a mode appropriate for the blupdater, that + is, privileged mode execution using its own vector table. */ void eth_isr(void) { - while(1); + while (1) + ; } - void mpu_blup(void) { - #ifndef EMULATOR - // basic memory protection for the blupdater. More regions can be added if needed. - // CAUTION: It is possible to disable access to critical resources even in privileged mode. This - // can potentially brick devices - - // Disable MPU - MPU_CTRL = 0; - - // Note: later entries overwrite previous ones - // Flash (0x08000000 - 0x080FFFFF, 1 MiB, read-only) - MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRW_URO; - // Sector 0 (bootstrap) is protected - // (0x08000000 - 0x08003FFF, 16 KiB) - MPU_RBAR = (FLASH_BASE) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRO_UNO; - - // Enable MPU and allow privileged execution of the system memory map. If unprivileged access - // of the system memory map is desired, do not set this bit and add mpu coverage of the region. - MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA; - - // Enable memory fault handler - SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; - - __asm__ volatile("dsb"); - __asm__ volatile("isb"); -#endif //EMULATOR + // basic memory protection for the blupdater. More regions can be added if + // needed. CAUTION: It is possible to disable access to critical resources + // even in privileged mode. This can potentially brick devices + + // Disable MPU + MPU_CTRL = 0; + + // Note: later entries overwrite previous ones + // Flash (0x08000000 - 0x080FFFFF, 1 MiB, read-only) + MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | + MPU_RASR_ATTR_AP_PRW_URO; + // Sector 0 (bootstrap) is protected + // (0x08000000 - 0x08003FFF, 16 KiB) + MPU_RBAR = (FLASH_BASE) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_16KB | + MPU_RASR_ATTR_AP_PRO_UNO; + + // Enable MPU and allow privileged execution of the system memory map. If + // unprivileged access of the system memory map is desired, do not set this + // bit and add mpu coverage of the region. + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA; + + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +#endif // EMULATOR } - - diff --git a/tools/bootloader/bl_mpu.c b/tools/bootloader/bl_mpu.c index 321c90a58..7895ff897 100644 --- a/tools/bootloader/bl_mpu.c +++ b/tools/bootloader/bl_mpu.c @@ -34,58 +34,54 @@ #include #include - /// \brief bootloader-only version of flash erase in word (32bit) size /// /// Must be run from bootloader with privileged access or it may cause a memory /// protect failure. -void bl_flash_erase_word(Allocation group) -{ +void bl_flash_erase_word(Allocation group) { #ifndef EMULATOR - const FlashSector* s = flash_sector_map; - while (s->use != FLASH_INVALID) { - if (s->use == group) { - bl_flash_erase_sector(s->sector); - } - ++s; + const FlashSector* s = flash_sector_map; + while (s->use != FLASH_INVALID) { + if (s->use == group) { + bl_flash_erase_sector(s->sector); } + ++s; + } #endif } /// bootloader-only: flash-erase that erases a given sector in 32bit chunks void bl_flash_erase_sector(int sector) { #ifndef EMULATOR - const FlashSector* s = flash_sector_map; - while (s->use != FLASH_INVALID) { - if (s->sector == sector) { - // unlock the flash - flash_clear_status_flags(); - flash_unlock(); + const FlashSector* s = flash_sector_map; + while (s->use != FLASH_INVALID) { + if (s->sector == sector) { + // unlock the flash + flash_clear_status_flags(); + flash_unlock(); - // erase the sector - flash_erase_sector(s->sector, FLASH_CR_PROGRAM_X32); + // erase the sector + flash_erase_sector(s->sector, FLASH_CR_PROGRAM_X32); - // lock the flash - /* Wait for any write operation to complete. */ - flash_wait_for_last_operation(); - /* Disable writes to flash. */ - FLASH_CR &= ~FLASH_CR_PG; - /* lock flash register */ - FLASH_CR |= FLASH_CR_LOCK; - /* return flash status register */ - break; - } - ++s; + // lock the flash + /* Wait for any write operation to complete. */ + flash_wait_for_last_operation(); + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; + /* lock flash register */ + FLASH_CR |= FLASH_CR_LOCK; + /* return flash status register */ + break; } + ++s; + } #endif } /// Initialize Board -void bl_board_init(void) -{ +void bl_board_init(void) { #ifndef EMULATOR - // Enable Clock Security System - rcc_css_enable(); + // Enable Clock Security System + rcc_css_enable(); #endif } - diff --git a/tools/bootloader/main.c b/tools/bootloader/main.c index 8edfe7ce3..69a40cee4 100644 --- a/tools/bootloader/main.c +++ b/tools/bootloader/main.c @@ -61,283 +61,273 @@ #define BUTTON_IRQN NVIC_EXTI9_5_IRQ -#define APP_VERSIONS "VERSION" \ - VERSION_STR(BOOTLOADER_MAJOR_VERSION) "." \ - VERSION_STR(BOOTLOADER_MINOR_VERSION) "." \ - VERSION_STR(BOOTLOADER_PATCH_VERSION) +#define APP_VERSIONS \ + "VERSION" VERSION_STR(BOOTLOADER_MAJOR_VERSION) "." VERSION_STR( \ + BOOTLOADER_MINOR_VERSION) "." VERSION_STR(BOOTLOADER_PATCH_VERSION) /* These variables will be used by host application to read the version info */ static const char *const application_version -__attribute__((used, section("version"))) = APP_VERSIONS; + __attribute__((used, section("version"))) = APP_VERSIONS; void mmhisr(void); void bl_board_init(void); void memory_getDeviceLabel(char *str, size_t len) { - strlcpy(str, "KeepKey", len); + strlcpy(str, "KeepKey", len); } /// Dispatch into firmware -static inline void __attribute__((noreturn)) jump_to_firmware(int trust) -{ - extern char _confidential_start[]; - extern char _confidential_end[]; - memset_reg(_confidential_start, _confidential_end, 0); - - // Disable interrupts until new user vectors are set. - svc_disable_interrupts(); - -#ifdef DEBUG_ON - // For dev devices with JTAG disabled, firmware must always be trusted. - // Otherwise, a bootloader might be updated that locks out further - // bootloader updates. - trust = SIG_OK; - -# ifdef TEST_UNSIGNED - trust = SIG_FAIL; -# endif - +static inline void __attribute__((noreturn)) jump_to_firmware(int trust) { + extern char _confidential_start[]; + extern char _confidential_end[]; + memset_reg(_confidential_start, _confidential_end, 0); + + // Disable interrupts until new user vectors are set. + svc_disable_interrupts(); + +#ifdef DEBUG_ON + // For dev devices with JTAG disabled, firmware must always be trusted. + // Otherwise, a bootloader might be updated that locks out further + // bootloader updates. + trust = SIG_OK; + +#ifdef TEST_UNSIGNED + trust = SIG_FAIL; #endif - // Set up and turn on memory protection, if needed. - if (SIG_OK == fi_defense_delay(trust)) { - - // Trusted firmware is allowed to provide its own vtable. - const vector_table_t *new_vtable = (const vector_table_t*)(FLASH_APP_START); - - if (new_vtable->irq[NVIC_ETH_IRQ] != new_vtable->irq[NVIC_ETH_WKUP_IRQ]) { - // If these vectors are not equal, the blupdater is in the firmware - // space. Let it use its own vector table. msp will be used in - // thread and handler mode. The NVIC_ETH_IRQ vector is at - // 0x08060234, this should point to the blocking handler in the - // blupdater. blupdater will use its own mpu. +#endif - // New vector table. - SCB_VTOR = (uint32_t)new_vtable; + // Set up and turn on memory protection, if needed. + if (SIG_OK == fi_defense_delay(trust)) { + // Trusted firmware is allowed to provide its own vtable. + const vector_table_t *new_vtable = + (const vector_table_t *)(FLASH_APP_START); - // Jump to blupdater. - new_vtable->reset(); - } else { - // Trusted firmware, memory protect and run unprivileged in firmware image. + if (new_vtable->irq[NVIC_ETH_IRQ] != new_vtable->irq[NVIC_ETH_WKUP_IRQ]) { + // If these vectors are not equal, the blupdater is in the firmware + // space. Let it use its own vector table. msp will be used in + // thread and handler mode. The NVIC_ETH_IRQ vector is at + // 0x08060234, this should point to the blocking handler in the + // blupdater. blupdater will use its own mpu. - // Use fw vector table for intermediate releases. - SCB_VTOR = (uint32_t)new_vtable; + // New vector table. + SCB_VTOR = (uint32_t)new_vtable; - // Jump to firmware. - new_vtable->reset(); - } + // Jump to blupdater. + new_vtable->reset(); } else { - // Untrusted firmware must use the bootloader's vtable, and use - // supervisor calls to handle things like timer interrupts, and write - // flash. + // Trusted firmware, memory protect and run unprivileged in firmware + // image. - // Configure the MPU - mpu_config(trust); + // Use fw vector table for intermediate releases. + SCB_VTOR = (uint32_t)new_vtable; - // Drop privileges - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FIRMWARE_UNPRIV) : "memory"); + // Jump to firmware. + new_vtable->reset(); } - - // Prevent compiler from generating stack protector code (which causes CPU - // fault because the stack is moved) - for (;;); + } else { + // Untrusted firmware must use the bootloader's vtable, and use + // supervisor calls to handle things like timer interrupts, and write + // flash. + + // Configure the MPU + mpu_config(trust); + + // Drop privileges + __asm__ __volatile__("svc %0" ::"i"(SVC_FIRMWARE_UNPRIV) : "memory"); + } + + // Prevent compiler from generating stack protector code (which causes CPU + // fault because the stack is moved) + for (;;) + ; } /// Bootloader Board Initialization -static void bootloader_init(void) -{ - cm_enable_interrupts(); - reset_rng(); - drbg_init(); - timer_init(); - keepkey_button_init(); - svc_enable_interrupts(); - usart_init(); - keepkey_leds_init(); - storage_sectorInit(); - display_hw_init(); - layout_init(display_canvas_init()); +static void bootloader_init(void) { + cm_enable_interrupts(); + reset_rng(); + drbg_init(); + timer_init(); + keepkey_button_init(); + svc_enable_interrupts(); + usart_init(); + keepkey_leds_init(); + storage_sectorInit(); + display_hw_init(); + layout_init(display_canvas_init()); } /// Enable the timer interrupts -static void clock_init(void) -{ - struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; - rcc_clock_setup_hse_3v3(&clock); - - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_GPIOB); - rcc_periph_clock_enable(RCC_GPIOC); - rcc_periph_clock_enable(RCC_OTGFS); - rcc_periph_clock_enable(RCC_SYSCFG); - rcc_periph_clock_enable(RCC_TIM4); - rcc_periph_clock_enable(RCC_RNG); - rcc_periph_clock_enable(RCC_CRC); +static void clock_init(void) { + struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; + rcc_clock_setup_hse_3v3(&clock); + + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_OTGFS); + rcc_periph_clock_enable(RCC_SYSCFG); + rcc_periph_clock_enable(RCC_TIM4); + rcc_periph_clock_enable(RCC_RNG); + rcc_periph_clock_enable(RCC_CRC); } /// \returns true iff the device should enter firmware update mode. -static bool isFirmwareUpdateMode(void) -{ - // User asked for an update. - if (keepkey_button_down()) - return true; +static bool isFirmwareUpdateMode(void) { + // User asked for an update. + if (keepkey_button_down()) return true; - // Firmware isn't there? - if (!magic_ok()) - return true; + // Firmware isn't there? + if (!magic_ok()) return true; - // When debugging over jtag, these are triggering, sending us into update mode. + // When debugging over jtag, these are triggering, sending us into update + // mode. #ifndef DEBUG_ON - int signed_firmware = signatures_ok(); + int signed_firmware = signatures_ok(); - // Check if the firmware wants us to boot into firmware update mode. - // This is used to skip a hard reset after bootloader update, and drop the - // user right back into the firmware update flow. - if ((SIG_FLAG & 2) == 2) - return true; + // Check if the firmware wants us to boot into firmware update mode. + // This is used to skip a hard reset after bootloader update, and drop the + // user right back into the firmware update flow. + if ((FLASH_META_FLAGS & 1) == 1) return true; - // If the firmware was signed with old signing keys, we also need to update. - if (signed_firmware == KEY_EXPIRED) - return true; + // If the firmware was signed with old signing keys, we also need to update. + if (signed_firmware == KEY_EXPIRED) return true; #endif - // Attempt to boot. - return false; + // Attempt to boot. + return false; } -bool magic_ok(void) -{ +bool magic_ok(void) { #ifndef DEBUG_ON - app_meta_td *app_meta = (app_meta_td *)FLASH_META_MAGIC; + app_meta_td *app_meta = (app_meta_td *)FLASH_META_MAGIC; - return memcmp((void *)&app_meta->magic, META_MAGIC_STR, - META_MAGIC_SIZE) == 0; + return memcmp((void *)&app_meta->magic, META_MAGIC_STR, META_MAGIC_SIZE) == 0; #else - return true; + return true; #endif } const VariantInfo *variant_getInfo(void) { - // Override the weak defintion of variant_getInfo provided by libkkboard to - // disallow loading the VariantInfo provided by sector 4 of flash. We do - // this so that if there's ever a case where the upload of it got - // corrupted, then we want the bootloader to have its own fallback baked - // in. That way, we'll be able to use normal firmware upload mechanisms to - // fix the situation, rather than having completely bricked the device. - - const char *model = flash_getModel(); - if (!model) - return &variant_keepkey; - -#define MODEL_KK(NUMBER) \ - if (0 == strcmp(model, (NUMBER))) { \ - return &variant_keepkey; \ - } + // Override the weak defintion of variant_getInfo provided by libkkboard to + // disallow loading the VariantInfo provided by sector 4 of flash. We do + // this so that if there's ever a case where the upload of it got + // corrupted, then we want the bootloader to have its own fallback baked + // in. That way, we'll be able to use normal firmware upload mechanisms to + // fix the situation, rather than having completely bricked the device. + + const char *model = flash_getModel(); + if (!model) return &variant_keepkey; + +#define MODEL_KK(NUMBER) \ + if (0 == strcmp(model, (NUMBER))) { \ + return &variant_keepkey; \ + } #include "keepkey/board/models.def" - return &variant_poweredBy; + return &variant_poweredBy; } /// Runs through application firmware checking, and then boots. -static void boot(void) -{ - if (!magic_ok()) { - layout_simple_message("Please visit keepkey.com/get-started"); - return; +static void boot(void) { + if (!magic_ok()) { + layout_simple_message("Please visit keepkey.com/get-started"); + return; + } + + int signed_firmware = signatures_ok(); + + // Failure due to expired sig key. + if (signed_firmware == KEY_EXPIRED) { + layout_standard_notification( + "Firmware Update Required", + "Please disconnect and reconnect while holding the button.", + NOTIFICATION_UNPLUG); + display_refresh(); + return; + } + + // Signature check failed. + if (signed_firmware != SIG_OK) { + uint8_t flashed_firmware_hash[SHA256_DIGEST_LENGTH]; + memzero(flashed_firmware_hash, sizeof(flashed_firmware_hash)); + memory_firmware_hash(flashed_firmware_hash); + char hash_str[2 * 32 + 1]; + data2hex(flashed_firmware_hash, 32, hash_str); + kk_strlwr(hash_str); + if (!confirm_without_button_request( + "Unofficial Firmware", + "Are you willing to take the risk?\n" + "%.8s %.8s %.8s %.8s\n" + "%.8s %.8s %.8s %.8s", + hash_str, hash_str + 8, hash_str + 16, hash_str + 24, hash_str + 32, + hash_str + 40, hash_str + 48, hash_str + 56)) { + layout_simple_message("Boot Aborted"); + return; } + } - int signed_firmware = signatures_ok(); - - // Failure due to expired sig key. - if (signed_firmware == KEY_EXPIRED) { - layout_standard_notification("Firmware Update Required", - "Please disconnect and reconnect while holding the button.", - NOTIFICATION_UNPLUG); - display_refresh(); - return; - } - - // Signature check failed. - if (signed_firmware != SIG_OK) { - uint8_t flashed_firmware_hash[SHA256_DIGEST_LENGTH]; - memzero(flashed_firmware_hash, sizeof(flashed_firmware_hash)); - memory_firmware_hash(flashed_firmware_hash); - char hash_str[2 * 32 + 1]; - data2hex(flashed_firmware_hash, 32, hash_str); - kk_strlwr(hash_str); - if (!confirm_without_button_request("Unofficial Firmware", - "Are you willing to take the risk?\n" - "%.8s %.8s %.8s %.8s\n" - "%.8s %.8s %.8s %.8s", - hash_str, hash_str + 8, hash_str + 16, hash_str + 24, - hash_str + 32, hash_str + 40, hash_str + 48, hash_str + 56)) { - layout_simple_message("Boot Aborted"); - return; - } - } - - led_func(CLR_RED_LED); - jump_to_firmware(signed_firmware); + led_func(CLR_RED_LED); + jump_to_firmware(signed_firmware); } /// Firmware update mode. Resets the device on successful firmware upload. -static void update_fw(void) -{ - led_func(CLR_GREEN_LED); - - if (usb_flash_firmware()) { - layout_standard_notification("Firmware Update Complete", - "Your device will now restart", - NOTIFICATION_CONFIRMED); - display_refresh(); - delay_ms(3000); - board_reset(); - } else { - layout_standard_notification("Firmware Update Failure", - "There was a problem while uploading firmware. Please try again.", - NOTIFICATION_UNPLUG); - display_refresh(); - } +static void update_fw(void) { + led_func(CLR_GREEN_LED); + + if (usb_flash_firmware()) { + layout_standard_notification("Firmware Update Complete", + "Your device will now restart", + NOTIFICATION_CONFIRMED); + display_refresh(); + delay_ms(3000); + board_reset(); + } else { + layout_standard_notification( + "Firmware Update Failure", + "There was a problem while uploading firmware. Please try again.", + NOTIFICATION_UNPLUG); + display_refresh(); + } } -int main(void) -{ - _buttonusr_isr = (void *)&buttonisr_usr; - _timerusr_isr = (void *)&timerisr_usr; - _mmhusr_isr = (void *)&mmhisr; +int main(void) { + _buttonusr_isr = (void *)&buttonisr_usr; + _timerusr_isr = (void *)&timerisr_usr; + _mmhusr_isr = (void *)&mmhisr; - bl_board_init(); - clock_init(); - bootloader_init(); + bl_board_init(); + clock_init(); + bootloader_init(); #if !defined(DEBUG_ON) && (MEMORY_PROTECT == 0) #error "To compile release version, please set MEMORY_PROTECT flag" #elif !defined(DEBUG_ON) - /* Checks and sets memory protection */ - memory_protect(); + /* Checks and sets memory protection */ + memory_protect(); #elif (MEMORY_PROTECT == 1) #error "Can only compile release versions with MEMORY_PROTECT flag" #endif - /* Initialize stack guard with random value (-fstack_protector_all) */ - __stack_chk_guard = fi_defense_delay(random32()); + /* Initialize stack guard with random value (-fstack_protector_all) */ + __stack_chk_guard = fi_defense_delay(random32()); - led_func(SET_GREEN_LED); - led_func(SET_RED_LED); + led_func(SET_GREEN_LED); + led_func(SET_RED_LED); - dbg_print("\n\rKeepKey LLC, Copyright (C) 2018\n\r"); - dbg_print("BootLoader Version %d.%d.%d\n\r", BOOTLOADER_MAJOR_VERSION, - BOOTLOADER_MINOR_VERSION, BOOTLOADER_PATCH_VERSION); + dbg_print("\n\rKeepKey LLC, Copyright (C) 2018\n\r"); + dbg_print("BootLoader Version %d.%d.%d\n\r", BOOTLOADER_MAJOR_VERSION, + BOOTLOADER_MINOR_VERSION, BOOTLOADER_PATCH_VERSION); - storage_protect_wipe(fi_defense_delay(storage_protect_status())); + storage_protect_wipe(fi_defense_delay(storage_protect_status())); - if (isFirmwareUpdateMode()) { - update_fw(); - } else { - boot(); - } + if (isFirmwareUpdateMode()) { + update_fw(); + } else { + boot(); + } - shutdown(); - return 0; // Should never get here + shutdown(); + return 0; // Should never get here } - diff --git a/tools/bootloader/usb_flash.c b/tools/bootloader/usb_flash.c index 017fab85e..8ff3da112 100644 --- a/tools/bootloader/usb_flash.c +++ b/tools/bootloader/usb_flash.c @@ -1,4 +1,4 @@ - /* +/* * This file is part of the KeepKey project. * * Copyright (C) 2015 KeepKey LLC @@ -52,40 +52,47 @@ static uint8_t firmware_hash[SHA256_DIGEST_LENGTH]; static bool old_firmware_was_unsigned; extern bool reset_msg_stack; -static const MessagesMap_t MessagesMap[] = -{ +static const MessagesMap_t MessagesMap[] = { /* Normal Messages */ - MSG_IN(MessageType_MessageType_Initialize, Initialize, handler_initialize) - MSG_IN(MessageType_MessageType_GetFeatures, GetFeatures, handler_get_features) - MSG_IN(MessageType_MessageType_Ping, Ping, handler_ping) - MSG_IN(MessageType_MessageType_WipeDevice, WipeDevice, handler_wipe) - MSG_IN(MessageType_MessageType_FirmwareErase, FirmwareErase, handler_erase) - MSG_IN(MessageType_MessageType_ButtonAck, ButtonAck, NO_PROCESS_FUNC) - MSG_IN(MessageType_MessageType_Cancel, Cancel, NO_PROCESS_FUNC) + MSG_IN(MessageType_MessageType_Initialize, Initialize, + handler_initialize) MSG_IN(MessageType_MessageType_GetFeatures, + GetFeatures, handler_get_features) + MSG_IN(MessageType_MessageType_Ping, Ping, handler_ping) MSG_IN( + MessageType_MessageType_WipeDevice, WipeDevice, handler_wipe) + MSG_IN(MessageType_MessageType_FirmwareErase, FirmwareErase, + handler_erase) MSG_IN(MessageType_MessageType_ButtonAck, + ButtonAck, NO_PROCESS_FUNC) + MSG_IN(MessageType_MessageType_Cancel, Cancel, NO_PROCESS_FUNC) /* Normal Raw Messages */ - RAW_IN(MessageType_MessageType_FirmwareUpload, FirmwareUpload, raw_handler_upload) + RAW_IN(MessageType_MessageType_FirmwareUpload, FirmwareUpload, + raw_handler_upload) /* Normal Out Messages */ - MSG_OUT(MessageType_MessageType_Features, Features, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_Success, Success, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_Failure, Failure, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_ButtonRequest, ButtonRequest, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_Features, Features, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_Success, Success, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_Failure, Failure, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_ButtonRequest, ButtonRequest, + NO_PROCESS_FUNC) #if DEBUG_LINK /* Debug Messages */ - DEBUG_IN(MessageType_MessageType_DebugLinkDecision, DebugLinkDecision, NO_PROCESS_FUNC) - DEBUG_IN(MessageType_MessageType_DebugLinkGetState, DebugLinkGetState, handler_debug_link_get_state) - DEBUG_IN(MessageType_MessageType_DebugLinkStop, DebugLinkStop, handler_debug_link_stop) - DEBUG_IN(MessageType_MessageType_DebugLinkFillConfig, DebugLinkFillConfig, handler_debug_link_fill_config) + DEBUG_IN(MessageType_MessageType_DebugLinkDecision, DebugLinkDecision, + NO_PROCESS_FUNC) + DEBUG_IN(MessageType_MessageType_DebugLinkGetState, DebugLinkGetState, + handler_debug_link_get_state) + DEBUG_IN(MessageType_MessageType_DebugLinkStop, DebugLinkStop, + handler_debug_link_stop) + DEBUG_IN(MessageType_MessageType_DebugLinkFillConfig, + DebugLinkFillConfig, handler_debug_link_fill_config) /* Debug Out Messages */ - DEBUG_OUT(MessageType_MessageType_DebugLinkState, DebugLinkState, NO_PROCESS_FUNC) - DEBUG_OUT(MessageType_MessageType_DebugLinkLog, DebugLinkLog, NO_PROCESS_FUNC) + DEBUG_OUT(MessageType_MessageType_DebugLinkState, DebugLinkState, + NO_PROCESS_FUNC) DEBUG_OUT(MessageType_MessageType_DebugLinkLog, + DebugLinkLog, NO_PROCESS_FUNC) #endif }; - /* * check_firmware_hash - Checks flashed firmware's hash * @@ -95,13 +102,13 @@ static const MessagesMap_t MessagesMap[] = * OUTPUT * status of hash check */ -static bool check_firmware_hash(void) -{ - uint8_t flashed_firmware_hash[SHA256_DIGEST_LENGTH]; +static bool check_firmware_hash(void) { + uint8_t flashed_firmware_hash[SHA256_DIGEST_LENGTH]; - memory_firmware_hash(flashed_firmware_hash); + memory_firmware_hash(flashed_firmware_hash); - return memcmp(firmware_hash, flashed_firmware_hash, SHA256_DIGEST_LENGTH) == 0; + return memcmp(firmware_hash, flashed_firmware_hash, SHA256_DIGEST_LENGTH) == + 0; } /* @@ -113,57 +120,52 @@ static bool check_firmware_hash(void) * OUTPUT * update status */ -static void bootloader_fsm_init(void) -{ - msg_map_init(MessagesMap, sizeof(MessagesMap) / sizeof(MessagesMap_t)); - set_msg_failure_handler(&send_failure); +static void bootloader_fsm_init(void) { + msg_map_init(MessagesMap, sizeof(MessagesMap) / sizeof(MessagesMap_t)); + set_msg_failure_handler(&send_failure); #if DEBUG_LINK - set_msg_debug_link_get_state_handler(&handler_debug_link_get_state); + set_msg_debug_link_get_state_handler(&handler_debug_link_get_state); #endif - msg_init(); + msg_init(); } /// \return true iff storage should be restored after this firmware update. static bool should_restore(void) { - // If the firmware metadata requests a wipe, honor that. - if ((SIG_FLAG & 1) == 0) - return false; + // If the firmware metadata requests a wipe, honor that. + if (SIG_FLAG == 0) return false; #ifdef DEBUG_ON - return true; + return true; #else - // Don't restore if the old firmware was unsigned. - // - // This protects users of custom firmware from having their storage sectors - // dumped, but unfortunately means they'll have to re-load keys every time - // they update. Security >> conveniece. - // - // This also guarantees that when we read storage in an official firmware, - // it must have been written by an official firmware. - if (old_firmware_was_unsigned) - return false; - - // Check the signatures of the *new* firmware. - uint32_t sig_status = signatures_ok(); - - // Otherwise both the old and new must be signed by KeepKey in order to restore. - return sig_status == SIG_OK; + // Don't restore if the old firmware was unsigned. + // + // This protects users of custom firmware from having their storage sectors + // dumped, but unfortunately means they'll have to re-load keys every time + // they update. Security >> conveniece. + // + // This also guarantees that when we read storage in an official firmware, + // it must have been written by an official firmware. + if (old_firmware_was_unsigned) return false; + + // Check the signatures of the *new* firmware. + uint32_t sig_status = signatures_ok(); + + // Otherwise both the old and new must be signed by KeepKey in order to + // restore. + return sig_status == SIG_OK; #endif } static bool isUpdateRequired(int signed_firmware) { - if (!magic_ok()) - return true; + if (!magic_ok()) return true; - if ((SIG_FLAG & 2) == 2) - return true; + if ((META_FLAGS & 1) == 1) return true; - if (signed_firmware == KEY_EXPIRED) - return true; + if (signed_firmware == KEY_EXPIRED) return true; - return false; + return false; } /* @@ -175,471 +177,446 @@ static bool isUpdateRequired(int signed_firmware) { * OUTPUT * update status */ -bool usb_flash_firmware(void) -{ - int signed_firmware = signatures_ok(); - old_firmware_was_unsigned = signed_firmware != SIG_OK && signed_firmware != KEY_EXPIRED; +bool usb_flash_firmware(void) { + int signed_firmware = signatures_ok(); + old_firmware_was_unsigned = + signed_firmware != SIG_OK && signed_firmware != KEY_EXPIRED; - char serial[96 / 8 * 2 + 1]; - desig_get_unique_id_as_string(serial, sizeof(serial)); + char serial[96 / 8 * 2 + 1]; + desig_get_unique_id_as_string(serial, sizeof(serial)); - char body[256]; - snprintf(body, sizeof(body), + char body[256]; + snprintf(body, sizeof(body), "Bootloader Version: " VERSION_STR(BOOTLOADER_MAJOR_VERSION) "." VERSION_STR(BOOTLOADER_MINOR_VERSION) "." VERSION_STR(BOOTLOADER_PATCH_VERSION) "\nSerial: %s", serial); - layout_standard_notification(isUpdateRequired(signed_firmware) - ? "FIRMWARE UPDATE REQUIRED" - : "FIRMWARE UPDATE MODE", - body, NOTIFICATION_LOGO); + layout_standard_notification(isUpdateRequired(signed_firmware) + ? "FIRMWARE UPDATE REQUIRED" + : "FIRMWARE UPDATE MODE", + body, NOTIFICATION_LOGO); #if DEBUG_LINK - layout_debuglink_watermark(); + layout_debuglink_watermark(); #endif - usbInit("keepkey.com/update"); - bootloader_fsm_init(); - - while (1) - { - switch(upload_state) - { - case RAW_MESSAGE_COMPLETE: - { - // Only restore the storage sector / keys if the old firmware's - // signedness matches the new firmware's signedness. - // - // Also wipe if we failed to turn off storage_protect. - if (!fi_defense_delay(should_restore()) || - !storage_protect_off()) { - flash_unlock(); - bl_flash_erase_word(FLASH_STORAGE1); - bl_flash_erase_word(FLASH_STORAGE2); - bl_flash_erase_word(FLASH_STORAGE3); - flash_lock(); - } - - /* Check CRC of firmware that was flashed */ - if (check_firmware_hash()) { - /* Fingerprint has been verified. Install "KPKY" magic in meta header */ - if (flash_write(FLASH_APP, 0, META_MAGIC_SIZE, - (uint8_t *)META_MAGIC_STR) == true) { - flash_lock(); - send_success("Upload complete"); - return true; - } - } - - flash_lock(); - return false; - } - - case RAW_MESSAGE_ERROR: - { - flash_lock(); - dbg_print("Error: Firmware update error...\n\r"); - return false; - } - - case RAW_MESSAGE_NOT_STARTED: - case RAW_MESSAGE_STARTED: - default: - { - usbPoll(); - animate(); - display_refresh(); - } + usbInit("keepkey.com/update"); + bootloader_fsm_init(); + + while (1) { + switch (upload_state) { + case RAW_MESSAGE_COMPLETE: { + // Only restore the storage sector / keys if the old firmware's + // signedness matches the new firmware's signedness. + // + // Also wipe if we failed to turn off storage_protect. + if (!fi_defense_delay(should_restore()) || !storage_protect_off()) { + flash_unlock(); + bl_flash_erase_word(FLASH_STORAGE1); + bl_flash_erase_word(FLASH_STORAGE2); + bl_flash_erase_word(FLASH_STORAGE3); + flash_lock(); + } + + /* Check CRC of firmware that was flashed */ + if (check_firmware_hash()) { + /* Fingerprint has been verified. Install "KPKY" magic in meta header + */ + if (flash_write(FLASH_APP, 0, META_MAGIC_SIZE, + (uint8_t *)META_MAGIC_STR) == true) { + flash_lock(); + send_success("Upload complete"); + return true; + } } + + flash_lock(); + return false; + } + + case RAW_MESSAGE_ERROR: { + flash_lock(); + dbg_print("Error: Firmware update error...\n\r"); + return false; + } + + case RAW_MESSAGE_NOT_STARTED: + case RAW_MESSAGE_STARTED: + default: { + usbPoll(); + animate(); + display_refresh(); + } } + } - /* Clear the shadow before exiting */ - flash_lock(); - return false; + /* Clear the shadow before exiting */ + flash_lock(); + return false; } /// Find and initialize storage sector location. -void storage_sectorInit(void) -{ - if (!find_active_storage(&storage_location)) - { - /* Set to storage sector1 as default if no sector has been initialized */ - storage_location = STORAGE_SECT_DEFAULT; - } +void storage_sectorInit(void) { + if (!find_active_storage(&storage_location)) { + /* Set to storage sector1 as default if no sector has been initialized */ + storage_location = STORAGE_SECT_DEFAULT; + } } /// Send success message to host. -void send_success(const char *text) -{ - RESP_INIT(Success); - - if (text) - { - resp.has_message = true; - strlcpy(resp.message, text, sizeof(resp.message)); - } +void send_success(const char *text) { + RESP_INIT(Success); - msg_write(MessageType_MessageType_Success, &resp); + if (text) { + resp.has_message = true; + strlcpy(resp.message, text, sizeof(resp.message)); + } + + msg_write(MessageType_MessageType_Success, &resp); } /// Send failure message to host. -void send_failure(FailureType code, const char *text) -{ - if (reset_msg_stack) - { - handler_initialize((Initialize *)0); - reset_msg_stack = false; - return; - } +void send_failure(FailureType code, const char *text) { + if (reset_msg_stack) { + handler_initialize((Initialize *)0); + reset_msg_stack = false; + return; + } - RESP_INIT(Failure); + RESP_INIT(Failure); - resp.has_code = true; - resp.code = code; + resp.has_code = true; + resp.code = code; - if (text) - { - resp.has_message = true; - strlcpy(resp.message, text, sizeof(resp.message)); - } + if (text) { + resp.has_message = true; + strlcpy(resp.message, text, sizeof(resp.message)); + } - msg_write(MessageType_MessageType_Failure, &resp); + msg_write(MessageType_MessageType_Failure, &resp); } /// Handler to respond to ping messages. -void handler_ping(Ping *msg) -{ - RESP_INIT(Success); - - if (msg->has_message) - { - resp.has_message = true; - memcpy(resp.message, &(msg->message), sizeof(resp.message)); - } +void handler_ping(Ping *msg) { + RESP_INIT(Success); + + if (msg->has_message) { + resp.has_message = true; + memcpy(resp.message, &(msg->message), sizeof(resp.message)); + } - msg_write(MessageType_MessageType_Success, &resp); + msg_write(MessageType_MessageType_Success, &resp); } // Handler to respond to initialize message. -void handler_initialize(Initialize *msg) -{ - (void)msg; - RESP_INIT(Features); - - /* Vendor */ - resp.has_vendor = true; - strlcpy(resp.vendor, "keepkey.com", sizeof(resp.vendor)); - - /* Bootloader Mode */ - resp.has_bootloader_mode = true; - resp.bootloader_mode = true; - - /* Version */ - resp.has_major_version = true; - resp.has_minor_version = true; - resp.has_patch_version = true; - resp.major_version = BOOTLOADER_MAJOR_VERSION; - resp.minor_version = BOOTLOADER_MINOR_VERSION; - resp.patch_version = BOOTLOADER_PATCH_VERSION; - - /* Bootloader hash */ - resp.has_bootloader_hash = true; - resp.bootloader_hash.size = memory_bootloader_hash( - resp.bootloader_hash.bytes, - /*cached=*/false); - - /* Firmware hash */ - resp.has_firmware_hash = true; - resp.firmware_hash.size = memory_firmware_hash(resp.firmware_hash.bytes); - - resp.policies_count = 0; - - /* Smuggle debuglink state out via policies */ - _Static_assert(1 <= sizeof(resp.policies)/sizeof(resp.policies[0]), - "messages.options for policies not big enough?"); - const char bl_debug_link[] = "bl_debug_link"; - _Static_assert(sizeof(bl_debug_link) <= sizeof(resp.policies[0].policy_name), - "Policy.policy_name not big enough"); - memcpy(resp.policies[0].policy_name, bl_debug_link, sizeof(bl_debug_link)); - resp.policies[0].has_policy_name = true; - resp.policies[0].has_enabled = true; +void handler_initialize(Initialize *msg) { + (void)msg; + RESP_INIT(Features); + + /* Vendor */ + resp.has_vendor = true; + strlcpy(resp.vendor, "keepkey.com", sizeof(resp.vendor)); + + /* Bootloader Mode */ + resp.has_bootloader_mode = true; + resp.bootloader_mode = true; + + /* Version */ + resp.has_major_version = true; + resp.has_minor_version = true; + resp.has_patch_version = true; + resp.major_version = BOOTLOADER_MAJOR_VERSION; + resp.minor_version = BOOTLOADER_MINOR_VERSION; + resp.patch_version = BOOTLOADER_PATCH_VERSION; + + /* Bootloader hash */ + resp.has_bootloader_hash = true; + resp.bootloader_hash.size = memory_bootloader_hash(resp.bootloader_hash.bytes, + /*cached=*/false); + + /* Firmware hash */ + resp.has_firmware_hash = true; + resp.firmware_hash.size = memory_firmware_hash(resp.firmware_hash.bytes); + + resp.policies_count = 0; + + /* Smuggle debuglink state out via policies */ + _Static_assert(1 <= sizeof(resp.policies) / sizeof(resp.policies[0]), + "messages.options for policies not big enough?"); + const char bl_debug_link[] = "bl_debug_link"; + _Static_assert(sizeof(bl_debug_link) <= sizeof(resp.policies[0].policy_name), + "Policy.policy_name not big enough"); + memcpy(resp.policies[0].policy_name, bl_debug_link, sizeof(bl_debug_link)); + resp.policies[0].has_policy_name = true; + resp.policies[0].has_enabled = true; #if DEBUG_LINK - resp.policies[0].enabled = true; + resp.policies[0].enabled = true; #else - resp.policies[0].enabled = false; + resp.policies[0].enabled = false; #endif - resp.policies_count++; + resp.policies_count++; - /* Device model */ - const char *model = flash_getModel(); - if (model) { - resp.has_model = true; - strlcpy(resp.model, model, sizeof(resp.model)); - } + /* Device model */ + const char *model = flash_getModel(); + if (model) { + resp.has_model = true; + strlcpy(resp.model, model, sizeof(resp.model)); + } - msg_write(MessageType_MessageType_Features, &resp); + msg_write(MessageType_MessageType_Features, &resp); } /// Handler to respond to GetFeatures message. -void handler_get_features(GetFeatures *msg) -{ - (void)msg; - handler_initialize(0); +void handler_get_features(GetFeatures *msg) { + (void)msg; + handler_initialize(0); } /// Handler to wipe all application data and secret storage. -void handler_wipe(WipeDevice *msg) -{ - (void)msg; - if (!confirm(ButtonRequestType_ButtonRequest_WipeDevice, "Wipe Device", - "Do you want to erase your private keys, settings and firmware?")) - { - send_failure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); - layout_home(); - return; - } - - // Erase config data sectors. - for (uint32_t i = FLASH_STORAGE1; i <= FLASH_STORAGE3; i++) { - bl_flash_erase_word(i); - layoutProgress("Erasing Secrets", (i * 1000 / 8)); - } - - // Erase application section. - for (int i = 7; i <= 11; ++i) { - bl_flash_erase_sector(i); - layoutProgress("Erasing Firmware", ((i + 3 - 7 + 2) * 1000 / 8)); - } - - flash_lock(); - layoutProgress("Erasing Firmware", 1000); - +void handler_wipe(WipeDevice *msg) { + (void)msg; + if (!confirm( + ButtonRequestType_ButtonRequest_WipeDevice, "Wipe Device", + "Do you want to erase your private keys, settings and firmware?")) { + send_failure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); layout_home(); - send_success("Device wiped"); + return; + } + + // Erase config data sectors. + for (uint32_t i = FLASH_STORAGE1; i <= FLASH_STORAGE3; i++) { + bl_flash_erase_word(i); + layoutProgress("Erasing Secrets", (i * 1000 / 8)); + } + + // Erase application section. + for (int i = 7; i <= 11; ++i) { + bl_flash_erase_sector(i); + layoutProgress("Erasing Firmware", ((i + 3 - 7 + 2) * 1000 / 8)); + } + + flash_lock(); + layoutProgress("Erasing Firmware", 1000); + + layout_home(); + send_success("Device wiped"); } /// \returns true iff the storage has been initialized static bool is_initialized(void) { - Allocation storage_loc = FLASH_INVALID; - if (find_active_storage(&storage_loc) && storage_loc != FLASH_INVALID) - return true; - return false; + Allocation storage_loc = FLASH_INVALID; + if (find_active_storage(&storage_loc) && storage_loc != FLASH_INVALID) + return true; + return false; } /// \returns true iff the user has agreed to update their firmware static bool should_erase(void) { - if (is_initialized()) { - return confirm(ButtonRequestType_ButtonRequest_FirmwareErase, - "Verify Backup", - "Do you have your recovery sentence in case your private keys are erased?"); - } else { - return confirm(ButtonRequestType_ButtonRequest_FirmwareErase, - "Firmware Update", "Do you want to update your firmware?"); - } + if (is_initialized()) { + return confirm(ButtonRequestType_ButtonRequest_FirmwareErase, + "Verify Backup", + "Do you have your recovery sentence in case your private " + "keys are erased?"); + } else { + return confirm(ButtonRequestType_ButtonRequest_FirmwareErase, + "Firmware Update", "Do you want to update your firmware?"); + } } /// Handler to wipe application firmware -void handler_erase(FirmwareErase *msg) -{ - (void)msg; - - if (!should_erase()) { - upload_state = RAW_MESSAGE_ERROR; - send_failure(FailureType_Failure_ActionCancelled, "Firmware erase cancelled"); - return; - } +void handler_erase(FirmwareErase *msg) { + (void)msg; - layoutProgress("Preparing for upgrade", 0); + if (!should_erase()) { + upload_state = RAW_MESSAGE_ERROR; + send_failure(FailureType_Failure_ActionCancelled, + "Firmware erase cancelled"); + return; + } - if (!fi_defense_delay(storage_protect_on())) { - // Something went wrong during a prevous firmware upload, resulting in - // the storage protection magic getting wiped. To protect the user's - // secrets from malicious behavior, wipe them here: + layoutProgress("Preparing for upgrade", 0); - flash_unlock(); + if (!fi_defense_delay(storage_protect_on())) { + // Something went wrong during a prevous firmware upload, resulting in + // the storage protection magic getting wiped. To protect the user's + // secrets from malicious behavior, wipe them here: - bl_flash_erase_word(FLASH_STORAGE1); - layoutProgress("Preparing for upgrade", 1 * 1000 / 8); + flash_unlock(); - bl_flash_erase_word(FLASH_STORAGE2); - layoutProgress("Preparing for upgrade", 2 * 1000 / 8); + bl_flash_erase_word(FLASH_STORAGE1); + layoutProgress("Preparing for upgrade", 1 * 1000 / 8); - bl_flash_erase_word(FLASH_STORAGE3); - layoutProgress("Preparing for upgrade", 3 * 1000 / 8); + bl_flash_erase_word(FLASH_STORAGE2); + layoutProgress("Preparing for upgrade", 2 * 1000 / 8); - bl_flash_erase_sector(7); - layoutProgress("Preparing for upgrade", 4 * 1000 / 8); + bl_flash_erase_word(FLASH_STORAGE3); + layoutProgress("Preparing for upgrade", 3 * 1000 / 8); - bl_flash_erase_sector(8); - layoutProgress("Preparing for upgrade", 5 * 1000 / 8); + bl_flash_erase_sector(7); + layoutProgress("Preparing for upgrade", 4 * 1000 / 8); - bl_flash_erase_sector(9); - layoutProgress("Preparing for upgrade", 6 * 1000 / 8); + bl_flash_erase_sector(8); + layoutProgress("Preparing for upgrade", 5 * 1000 / 8); - bl_flash_erase_sector(10); - layoutProgress("Preparing for upgrade", 7 * 1000 / 8); + bl_flash_erase_sector(9); + layoutProgress("Preparing for upgrade", 6 * 1000 / 8); - bl_flash_erase_sector(11); - layoutProgress("Preparing for upgrade", 8 * 1000 / 8); + bl_flash_erase_sector(10); + layoutProgress("Preparing for upgrade", 7 * 1000 / 8); - flash_lock(); - } else { - flash_unlock(); + bl_flash_erase_sector(11); + layoutProgress("Preparing for upgrade", 8 * 1000 / 8); - bl_flash_erase_sector(7); - layoutProgress("Preparing for upgrade", 1 * 1000 / 5); + flash_lock(); + } else { + flash_unlock(); - bl_flash_erase_sector(8); - layoutProgress("Preparing for upgrade", 2 * 1000 / 5); + bl_flash_erase_sector(7); + layoutProgress("Preparing for upgrade", 1 * 1000 / 5); - bl_flash_erase_sector(9); - layoutProgress("Preparing for upgrade", 3 * 1000 / 5); + bl_flash_erase_sector(8); + layoutProgress("Preparing for upgrade", 2 * 1000 / 5); - bl_flash_erase_sector(10); - layoutProgress("Preparing for upgrade", 4 * 1000 / 5); + bl_flash_erase_sector(9); + layoutProgress("Preparing for upgrade", 3 * 1000 / 5); - bl_flash_erase_sector(11); - layoutProgress("Preparing for upgrade", 5 * 1000 / 5); + bl_flash_erase_sector(10); + layoutProgress("Preparing for upgrade", 4 * 1000 / 5); - flash_lock(); - } + bl_flash_erase_sector(11); + layoutProgress("Preparing for upgrade", 5 * 1000 / 5); - layoutProgress("Preparing for upgrade", 1000); - send_success("Firmware erased"); + flash_lock(); + } + + layoutProgress("Preparing for upgrade", 1000); + send_success("Firmware erased"); } /// Main firmware upload handler that parses USB message -void raw_handler_upload(RawMessage *msg, uint32_t frame_length) -{ - static uint32_t flash_offset; - - /* Check file size is within allocated space */ - if (frame_length >= (FLASH_APP_LEN + FLASH_META_DESC_LEN)) { - send_failure(FailureType_Failure_FirmwareError, "Firmware too large"); - dbg_print("Error: image too large to fit in the allocated space : 0x%" PRIx32 " ...\n\r", - frame_length); - upload_state = RAW_MESSAGE_ERROR; - return; - } - - /* Start firmware load */ - if (upload_state == RAW_MESSAGE_NOT_STARTED) - { - layoutProgress("Uploading Firmware", 0); - - upload_state = RAW_MESSAGE_STARTED; - flash_offset = 0; - - /* - * Parse firmware hash - */ - memcpy(firmware_hash, msg->buffer + PROTOBUF_FIRMWARE_HASH_START, SHA256_DIGEST_LENGTH); - - /* - * Parse application start - */ - msg->length -= PROTOBUF_FIRMWARE_START; - msg->buffer = (uint8_t *)(msg->buffer + PROTOBUF_FIRMWARE_START); - } - - /* Process firmware upload */ - if (upload_state != RAW_MESSAGE_STARTED) - return; - - /* Check if the image is bigger than allocated space */ - if ((flash_offset + msg->length) >= (FLASH_APP_LEN + FLASH_META_DESC_LEN)) { - /* Error: frame overrun detected during the image update */ - flash_lock(); - send_failure(FailureType_Failure_FirmwareError, "Firmware too large"); - upload_state = RAW_MESSAGE_ERROR; - dbg_print("Error: frame overrun detected during the image update... \n\r"); - return; - } - - if (flash_offset == 0) - { - /* Check that image is prepared with KeepKey magic */ - if (memcmp(msg->buffer, META_MAGIC_STR, META_MAGIC_SIZE) != 0) { - /* Invalid KeepKey magic detected */ - send_failure(FailureType_Failure_FirmwareError, "Not valid firmware"); - upload_state = RAW_MESSAGE_ERROR; - dbg_print("Error: invalid Magic Key detected... \n\r"); - return; - } - - msg->length -= META_MAGIC_SIZE; - msg->buffer = (uint8_t *)(msg->buffer + META_MAGIC_SIZE); - flash_offset = META_MAGIC_SIZE; - /* Unlock the flash for writing */ - flash_unlock(); - } - - static int update_ctr = 60; - if (update_ctr++ == 60) { - layoutProgress("Uploading Firmware\n", flash_offset * 1000 / frame_length); - update_ctr = 0; +void raw_handler_upload(RawMessage *msg, uint32_t frame_length) { + static uint32_t flash_offset; + + /* Check file size is within allocated space */ + if (frame_length >= (FLASH_APP_LEN + FLASH_META_DESC_LEN)) { + send_failure(FailureType_Failure_FirmwareError, "Firmware too large"); + dbg_print( + "Error: image too large to fit in the allocated space : 0x%" PRIx32 + " ...\n\r", + frame_length); + upload_state = RAW_MESSAGE_ERROR; + return; + } + + /* Start firmware load */ + if (upload_state == RAW_MESSAGE_NOT_STARTED) { + layoutProgress("Uploading Firmware", 0); + + upload_state = RAW_MESSAGE_STARTED; + flash_offset = 0; + + /* + * Parse firmware hash + */ + memcpy(firmware_hash, msg->buffer + PROTOBUF_FIRMWARE_HASH_START, + SHA256_DIGEST_LENGTH); + + /* + * Parse application start + */ + msg->length -= PROTOBUF_FIRMWARE_START; + msg->buffer = (uint8_t *)(msg->buffer + PROTOBUF_FIRMWARE_START); + } + + /* Process firmware upload */ + if (upload_state != RAW_MESSAGE_STARTED) return; + + /* Check if the image is bigger than allocated space */ + if ((flash_offset + msg->length) >= (FLASH_APP_LEN + FLASH_META_DESC_LEN)) { + /* Error: frame overrun detected during the image update */ + flash_lock(); + send_failure(FailureType_Failure_FirmwareError, "Firmware too large"); + upload_state = RAW_MESSAGE_ERROR; + dbg_print("Error: frame overrun detected during the image update... \n\r"); + return; + } + + if (flash_offset == 0) { + /* Check that image is prepared with KeepKey magic */ + if (memcmp(msg->buffer, META_MAGIC_STR, META_MAGIC_SIZE) != 0) { + /* Invalid KeepKey magic detected */ + send_failure(FailureType_Failure_FirmwareError, "Not valid firmware"); + upload_state = RAW_MESSAGE_ERROR; + dbg_print("Error: invalid Magic Key detected... \n\r"); + return; } - /* Begin writing to flash */ - if (!flash_write(FLASH_APP, flash_offset, msg->length, msg->buffer)) - { - /* Error: flash write error */ - flash_lock(); - send_failure(FailureType_Failure_FirmwareError, - "Encountered error while writing to flash"); - upload_state = RAW_MESSAGE_ERROR; - dbg_print("Error: flash write error... \n\r"); - return; - } + msg->length -= META_MAGIC_SIZE; + msg->buffer = (uint8_t *)(msg->buffer + META_MAGIC_SIZE); + flash_offset = META_MAGIC_SIZE; + /* Unlock the flash for writing */ + flash_unlock(); + } + + static int update_ctr = 60; + if (update_ctr++ == 60) { + layoutProgress("Uploading Firmware\n", flash_offset * 1000 / frame_length); + update_ctr = 0; + } + + /* Begin writing to flash */ + if (!flash_write(FLASH_APP, flash_offset, msg->length, msg->buffer)) { + /* Error: flash write error */ + flash_lock(); + send_failure(FailureType_Failure_FirmwareError, + "Encountered error while writing to flash"); + upload_state = RAW_MESSAGE_ERROR; + dbg_print("Error: flash write error... \n\r"); + return; + } - flash_offset += msg->length; + flash_offset += msg->length; - /* Finish firmware update */ - if (flash_offset >= frame_length - PROTOBUF_FIRMWARE_START) - { - flash_lock(); - upload_state = RAW_MESSAGE_COMPLETE; - } + /* Finish firmware update */ + if (flash_offset >= frame_length - PROTOBUF_FIRMWARE_START) { + flash_lock(); + upload_state = RAW_MESSAGE_COMPLETE; + } } #if DEBUG_LINK -void handler_debug_link_get_state(DebugLinkGetState *msg) -{ - (void)msg; - RESP_INIT(DebugLinkState); - - /* App fingerprint */ - if ((resp.firmware_hash.size = memory_firmware_hash(resp.firmware_hash.bytes)) != 0) - { - resp.has_firmware_hash = true; - } +void handler_debug_link_get_state(DebugLinkGetState *msg) { + (void)msg; + RESP_INIT(DebugLinkState); - /* Storage fingerprint */ - resp.has_storage_hash = true; - resp.storage_hash.size = memory_storage_hash(resp.storage_hash.bytes, storage_location); + /* App fingerprint */ + if ((resp.firmware_hash.size = + memory_firmware_hash(resp.firmware_hash.bytes)) != 0) { + resp.has_firmware_hash = true; + } - msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); -} + /* Storage fingerprint */ + resp.has_storage_hash = true; + resp.storage_hash.size = + memory_storage_hash(resp.storage_hash.bytes, storage_location); -void handler_debug_link_stop(DebugLinkStop *msg) -{ - (void)msg; + msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } +void handler_debug_link_stop(DebugLinkStop *msg) { (void)msg; } + /// Fills config area with sample data (used for testing firmware upload) -void handler_debug_link_fill_config(DebugLinkFillConfig *msg) -{ - (void)msg; - uint8_t fill_storage_shadow[STOR_FLASH_SECT_LEN]; - - memset(fill_storage_shadow, FILL_CONFIG_DATA, STOR_FLASH_SECT_LEN); - - /* Fill storage sector with test data */ - if (storage_location >= FLASH_STORAGE1 && storage_location <= FLASH_STORAGE3) - { - bl_flash_erase_word(storage_location); - flash_write(storage_location, 0, STOR_FLASH_SECT_LEN, - fill_storage_shadow); - } +void handler_debug_link_fill_config(DebugLinkFillConfig *msg) { + (void)msg; + uint8_t fill_storage_shadow[STOR_FLASH_SECT_LEN]; + + memset(fill_storage_shadow, FILL_CONFIG_DATA, STOR_FLASH_SECT_LEN); + + /* Fill storage sector with test data */ + if (storage_location >= FLASH_STORAGE1 && + storage_location <= FLASH_STORAGE3) { + bl_flash_erase_word(storage_location); + flash_write(storage_location, 0, STOR_FLASH_SECT_LEN, fill_storage_shadow); + } } #endif diff --git a/tools/bootstrap/main.c b/tools/bootstrap/main.c index c8a716f00..05a96b666 100644 --- a/tools/bootstrap/main.c +++ b/tools/bootstrap/main.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ - #include "keepkey/bootstrap/bootstrap.h" #include "keepkey/board/memory.h" @@ -26,10 +25,7 @@ #include #include - -static uint32_t * const SCB_VTOR = (uint32_t*)0xe000ed08; - - +static uint32_t* const SCB_VTOR = (uint32_t*)0xe000ed08; /* * zero_out_sram() - Fill entire SRAM sector with 0 @@ -40,12 +36,7 @@ static uint32_t * const SCB_VTOR = (uint32_t*)0xe000ed08; * none * */ -static void zero_out_sram(void) -{ - memset_reg(_ram_start, _ram_end, 0); -} - - +static void zero_out_sram(void) { memset_reg(_ram_start, _ram_end, 0); } /* * set_vector_table_bootloader() - Resets the vector table to point to the @@ -57,11 +48,11 @@ static void zero_out_sram(void) * none * */ -static void set_vector_table_bootloader(void) -{ - static const uint32_t NVIC_OFFSET_FLASH = ((uint32_t)FLASH_ORIGIN); +static void set_vector_table_bootloader(void) { + static const uint32_t NVIC_OFFSET_FLASH = ((uint32_t)FLASH_ORIGIN); - *SCB_VTOR = NVIC_OFFSET_FLASH | ((FLASH_BOOT_START - FLASH_ORIGIN) & (uint32_t)0x1FFFFF80); + *SCB_VTOR = NVIC_OFFSET_FLASH | + ((FLASH_BOOT_START - FLASH_ORIGIN) & (uint32_t)0x1FFFFF80); } /* @@ -72,9 +63,9 @@ static void set_vector_table_bootloader(void) * OUTPUT * none */ -static void __attribute__((noreturn)) bootstrap_halt(void) -{ - for(;;); /* Loops forever */ +static void __attribute__((noreturn)) bootstrap_halt(void) { + for (;;) + ; /* Loops forever */ } /* @@ -86,15 +77,14 @@ static void __attribute__((noreturn)) bootstrap_halt(void) * none * */ -static void bootloader_jump(void) -{ - uint32_t entry_address = FLASH_BOOT_START + 4; - uint32_t bootloader_entry_address = (uint32_t)(*(uint32_t*)(entry_address)); - bootloader_entry_t bootloader_entry = (bootloader_entry_t)bootloader_entry_address; - bootloader_entry(); +static void bootloader_jump(void) { + uint32_t entry_address = FLASH_BOOT_START + 4; + uint32_t bootloader_entry_address = (uint32_t)(*(uint32_t*)(entry_address)); + bootloader_entry_t bootloader_entry = + (bootloader_entry_t)bootloader_entry_address; + bootloader_entry(); } - /* * main - Bootstrap main entry function * @@ -104,17 +94,16 @@ static void bootloader_jump(void) * OUTPUT * 0 when complete */ -int main(int argc, char* argv[]) -{ - (void)argc; - (void)argv; - - /* Main loop for bootloader to transition to next step */ - cm_disable_interrupts(); - zero_out_sram(); - set_vector_table_bootloader(); - bootloader_jump(); - bootstrap_halt(); - - return(0); /* Should never get here */ +int main(int argc, char* argv[]) { + (void)argc; + (void)argv; + + /* Main loop for bootloader to transition to next step */ + cm_disable_interrupts(); + zero_out_sram(); + set_vector_table_bootloader(); + bootloader_jump(); + bootstrap_halt(); + + return (0); /* Should never get here */ } diff --git a/tools/display_test/main.c b/tools/display_test/main.c index 79d1f55d9..7051c478a 100644 --- a/tools/display_test/main.c +++ b/tools/display_test/main.c @@ -17,12 +17,11 @@ * along with this library. If not, see . */ - #include #include #ifndef EMULATOR -# include +#include #endif #include "keepkey/board/keepkey_board.h" @@ -31,10 +30,8 @@ #include "keepkey/firmware/app_layout.h" - void mmhisr(void); - /* * main() - Application main entry * @@ -43,22 +40,22 @@ void mmhisr(void); * OUTPUT * 0 when complete */ -int main(void) -{ - _buttonusr_isr = (void *)&buttonisr_usr; - _timerusr_isr = (void *)&timerisr_usr; - _mmhusr_isr = (void *)&mmhisr; +int main(void) { + _buttonusr_isr = (void *)&buttonisr_usr; + _timerusr_isr = (void *)&timerisr_usr; + _mmhusr_isr = (void *)&mmhisr; - /* Init board */ - kk_board_init(); + /* Init board */ + kk_board_init(); - led_func(SET_RED_LED); + led_func(SET_RED_LED); - /* Draw box to consume screen with pixels */ - layout_screen_test(); - display_refresh(); + /* Draw box to consume screen with pixels */ + layout_screen_test(); + display_refresh(); - for(;;); /* Loops forever */ + for (;;) + ; /* Loops forever */ - return(0); + return (0); } diff --git a/tools/emulator/display.h b/tools/emulator/display.h index 8f14df3bd..f0348d108 100644 --- a/tools/emulator/display.h +++ b/tools/emulator/display.h @@ -5,10 +5,10 @@ #include struct KKDisplay { - virtual void setPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) = 0; - virtual void swapOnVSync() = 0; + virtual void setPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b) = 0; + virtual void swapOnVSync() = 0; - static KKDisplay *CreateMatrix(); + static KKDisplay *CreateMatrix(); }; #endif diff --git a/tools/emulator/main.cpp b/tools/emulator/main.cpp index b907dbf2b..7f028c748 100644 --- a/tools/emulator/main.cpp +++ b/tools/emulator/main.cpp @@ -20,37 +20,35 @@ #include "display.h" extern "C" { - #include "keepkey/board/common.h" - #include "keepkey/board/keepkey_board.h" - #include "keepkey/board/keepkey_flash.h" - #include "keepkey/board/layout.h" - #include "keepkey/board/usb.h" - #include "keepkey/board/resources.h" - #include "keepkey/board/keepkey_usart.h" - #include "keepkey/emulator/setup.h" - #include "keepkey/firmware/app_layout.h" - #include "keepkey/firmware/home_sm.h" - #include "keepkey/firmware/storage.h" - #include "keepkey/rand/rng.h" +#include "keepkey/board/common.h" +#include "keepkey/board/keepkey_board.h" +#include "keepkey/board/keepkey_flash.h" +#include "keepkey/board/layout.h" +#include "keepkey/board/usb.h" +#include "keepkey/board/resources.h" +#include "keepkey/board/keepkey_usart.h" +#include "keepkey/emulator/setup.h" +#include "keepkey/firmware/app_layout.h" +#include "keepkey/firmware/home_sm.h" +#include "keepkey/firmware/storage.h" +#include "keepkey/rand/rng.h" } #include #include #include -#define APP_VERSIONS "VERSION" \ - VERSION_STR(MAJOR_VERSION) "." \ - VERSION_STR(MINOR_VERSION) "." \ - VERSION_STR(PATCH_VERSION) +#define APP_VERSIONS \ + "VERSION" VERSION_STR(MAJOR_VERSION) "." VERSION_STR( \ + MINOR_VERSION) "." VERSION_STR(PATCH_VERSION) /* These variables will be used by host application to read the version info */ const char *const application_version = APP_VERSIONS; -static void exec(void) -{ - usbPoll(); - animate(); - display_refresh(); +static void exec(void) { + usbPoll(); + animate(); + display_refresh(); } extern "C" { @@ -60,44 +58,43 @@ void fsm_init(void); extern "C" { static volatile bool interrupted = false; static void sigintHandler(int sig_num) { - signal(SIGINT, sigintHandler); - printf("Quitting...\n"); - fflush(stdout); - exit(0); + signal(SIGINT, sigintHandler); + printf("Quitting...\n"); + fflush(stdout); + exit(0); } } -int main(void) -{ - setup(); - flash_collectHWEntropy(false); - kk_board_init(); - drbg_init(); +int main(void) { + setup(); + flash_collectHWEntropy(false); + kk_board_init(); + drbg_init(); - led_func(SET_RED_LED); - dbg_print("Application Version %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, - PATCH_VERSION); + led_func(SET_RED_LED); + dbg_print("Application Version %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, + PATCH_VERSION); - storage_init(); + storage_init(); - fsm_init(); + fsm_init(); - led_func(SET_GREEN_LED); + led_func(SET_GREEN_LED); - usbInit("keepkey.com/get-started"); - led_func(CLR_RED_LED); + usbInit("keepkey.com/get-started"); + led_func(CLR_RED_LED); - reset_idle_time(); + reset_idle_time(); - layoutHomeForced(); + layoutHomeForced(); - signal(SIGINT, sigintHandler); + signal(SIGINT, sigintHandler); - while (1) { - delay_ms_with_callback(ONE_SEC, &exec, 1); - increment_idle_time(ONE_SEC); - toggle_screensaver(); - } + while (1) { + delay_ms_with_callback(ONE_SEC, &exec, 1); + increment_idle_time(ONE_SEC); + toggle_screensaver(); + } - return 0; + return 0; } diff --git a/tools/firmware/header.s b/tools/firmware/header.s index dd5c476a9..4a91b68b1 100644 --- a/tools/firmware/header.s +++ b/tools/firmware/header.s @@ -11,8 +11,9 @@ g_header: .byte 0 // sigindex1 .byte 0 // sigindex2 .byte 0 // sigindex3 - .byte 1 // flags: Preserve - . = . + 52 // reserved + .byte 1 // sig_flag: Preserve + .word 0 // meta_flags: no update after + . = . + 48 // reserved . = . + 64 // sig1 . = . + 64 // sig2 . = . + 64 // sig3 diff --git a/tools/firmware/keepkey_main.c b/tools/firmware/keepkey_main.c index b25117a41..4f5a4fa63 100644 --- a/tools/firmware/keepkey_main.c +++ b/tools/firmware/keepkey_main.c @@ -18,10 +18,10 @@ */ #ifndef EMULATOR -# include -# include -# include -# include +#include +#include +#include +#include #endif #include "keepkey/board/common.h" @@ -52,28 +52,26 @@ void mmhisr(void); void u2fInit(void); -#define APP_VERSIONS "VERSION" \ - VERSION_STR(MAJOR_VERSION) "." \ - VERSION_STR(MINOR_VERSION) "." \ - VERSION_STR(PATCH_VERSION) +#define APP_VERSIONS \ + "VERSION" VERSION_STR(MAJOR_VERSION) "." VERSION_STR( \ + MINOR_VERSION) "." VERSION_STR(PATCH_VERSION) /* These variables will be used by host application to read the version info */ static const char *const application_version -__attribute__((used, section("version"))) = APP_VERSIONS; + __attribute__((used, section("version"))) = APP_VERSIONS; void memory_getDeviceLabel(char *str, size_t len) { - const char *label = storage_getLabel(); + const char *label = storage_getLabel(); - if (label && is_valid_ascii((const uint8_t*)label, strlen(label))) { - snprintf(str, len, "KeepKey - %s", label); - } else { - strlcpy(str, "KeepKey", len); - } + if (label && is_valid_ascii((const uint8_t *)label, strlen(label))) { + snprintf(str, len, "KeepKey - %s", label); + } else { + strlcpy(str, "KeepKey", len); + } } -static bool canDropPrivs(void) -{ - switch (get_bootloaderKind()) { +static bool canDropPrivs(void) { + switch (get_bootloaderKind()) { case BLK_v1_0_0: case BLK_v1_0_1: case BLK_v1_0_2: @@ -82,52 +80,52 @@ static bool canDropPrivs(void) case BLK_v1_0_3_sig: case BLK_v1_0_4: case BLK_UNKNOWN: - return true; + return true; case BLK_v1_1_0: - return true; + return true; case BLK_v2_0_0: - return SIG_OK == signatures_ok(); - } - __builtin_unreachable(); + case BLK_v2_1_0: + return SIG_OK == signatures_ok(); + } + __builtin_unreachable(); } -static void drop_privs(void) -{ - if (!canDropPrivs()) - return; +static void drop_privs(void) { + if (!canDropPrivs()) return; - // Legacy bootloader code will have interrupts disabled at this point. - // To maintain compatibility, the timer and button interrupts need to - // be enabled and then global interrupts enabled. This is a nop in the - // modern scheme. - cm_enable_interrupts(); + // Legacy bootloader code will have interrupts disabled at this point. + // To maintain compatibility, the timer and button interrupts need to + // be enabled and then global interrupts enabled. This is a nop in the + // modern scheme. + cm_enable_interrupts(); - // Turn on memory protection for good signature. KK firmware is signed - mpu_config(SIG_OK); + // Turn on memory protection for good signature. KK firmware is signed + mpu_config(SIG_OK); - // set thread mode to unprivileged here. This will help protect against 0days - __asm__ volatile("msr control, %0" :: "r" (0x3)); // unpriv thread mode using psp stack + // set thread mode to unprivileged here. This will help protect against 0days + __asm__ volatile( + "msr control, %0" ::"r"(0x3)); // unpriv thread mode using psp stack } #ifndef DEBUG_ON static void unknown_bootloader(void) { - layout_warning_static("Unknown bootloader. Contact support."); - shutdown(); + layout_warning_static("Unknown bootloader. Contact support."); + shutdown(); } static void update_bootloader(void) { - review_without_button_request( - "Update Recommended", - "This device's bootloader has a known security issue. " - "https://bit.ly/2jUTbnk " - "Please update your bootloader."); + review_without_button_request( + "Update Recommended", + "This device's bootloader has a known security issue. " + "https://bit.ly/2jUTbnk " + "Please update your bootloader."); } #endif static void check_bootloader(void) { - BootloaderKind kind = get_bootloaderKind(); + BootloaderKind kind = get_bootloaderKind(); - switch (kind) { + switch (kind) { case BLK_v1_0_0: case BLK_v1_0_1: case BLK_v1_0_2: @@ -136,93 +134,93 @@ static void check_bootloader(void) { case BLK_v1_0_3_sig: case BLK_v1_0_4: #ifndef DEBUG_ON - update_bootloader(); + update_bootloader(); #endif - return; + return; case BLK_UNKNOWN: #ifndef DEBUG_ON - unknown_bootloader(); + unknown_bootloader(); #endif - return; + return; + case BLK_v2_1_0: case BLK_v2_0_0: case BLK_v1_1_0: - return; - } + return; + } #ifdef DEBUG_ON - __builtin_unreachable(); + __builtin_unreachable(); #else - unknown_bootloader(); + unknown_bootloader(); #endif } -static void exec(void) -{ - usbPoll(); +static void exec(void) { + usbPoll(); - /* Attempt to animate should a screensaver be present */ - animate(); - display_refresh(); + /* Attempt to animate should a screensaver be present */ + animate(); + display_refresh(); } -int main(void) -{ - _buttonusr_isr = (void *)&buttonisr_usr; - _timerusr_isr = (void *)&timerisr_usr; - _mmhusr_isr = (void *)&mmhisr; +int main(void) { + _buttonusr_isr = (void *)&buttonisr_usr; + _timerusr_isr = (void *)&timerisr_usr; + _mmhusr_isr = (void *)&mmhisr; - flash_collectHWEntropy(SIG_OK == signatures_ok()); + flash_collectHWEntropy(SIG_OK == signatures_ok()); - /* Drop privileges */ - drop_privs(); + /* Drop privileges */ + drop_privs(); - /* Init board */ - kk_board_init(); + /* Init board */ + kk_board_init(); - /* Program the model into OTP, if we're not in screen-test mode, and it's - * not already there - */ - (void)flash_programModel(); + /* Program the model into OTP, if we're not in screen-test mode, and it's + * not already there + */ + (void)flash_programModel(); - /* Init for safeguard against stack overflow (-fstack-protector-all) */ - __stack_chk_guard = (uintptr_t)random32(); + /* Init for safeguard against stack overflow (-fstack-protector-all) */ + __stack_chk_guard = (uintptr_t)random32(); - drbg_init(); + drbg_init(); - /* Bootloader Verification */ - check_bootloader(); + /* Bootloader Verification */ + check_bootloader(); - led_func(SET_RED_LED); - dbg_print("Application Version %d.%d.%d\n\r", MAJOR_VERSION, MINOR_VERSION, - PATCH_VERSION); + led_func(SET_RED_LED); + dbg_print("Application Version %d.%d.%d\n\r", MAJOR_VERSION, MINOR_VERSION, + PATCH_VERSION); - /* Init storage */ - storage_init(); + /* Init storage */ + storage_init(); - /* Init protcol buffer message map and usb msg callback */ - fsm_init(); + /* Init protcol buffer message map and usb msg callback */ + fsm_init(); - led_func(SET_GREEN_LED); + led_func(SET_GREEN_LED); - usbInit(storage_isInitialized() ? "keepkey.com/wallet" : "keepkey.com/get-started"); - u2fInit(); - led_func(CLR_RED_LED); + usbInit(storage_isInitialized() ? "keepkey.com/wallet" + : "keepkey.com/get-started"); + u2fInit(); + led_func(CLR_RED_LED); - reset_idle_time(); + reset_idle_time(); - if (is_mfg_mode()) - layout_screen_test(); - else if (!storage_isInitialized()) - layout_standard_notification("Welcome", "keepkey.com/get-started", - NOTIFICATION_LOGO); - else - layoutHomeForced(); + if (is_mfg_mode()) + layout_screen_test(); + else if (!storage_isInitialized()) + layout_standard_notification("Welcome", "keepkey.com/get-started", + NOTIFICATION_LOGO); + else + layoutHomeForced(); - while (1) { - delay_ms_with_callback(ONE_SEC, &exec, 1); - increment_idle_time(ONE_SEC); - toggle_screensaver(); - } + while (1) { + delay_ms_with_callback(ONE_SEC, &exec, 1); + increment_idle_time(ONE_SEC); + toggle_screensaver(); + } - return 0; + return 0; } diff --git a/tools/rle-dump/main.cpp b/tools/rle-dump/main.cpp index 036569312..1ab0c2dc6 100644 --- a/tools/rle-dump/main.cpp +++ b/tools/rle-dump/main.cpp @@ -9,54 +9,68 @@ extern "C" { #include static const uint8_t confirm_icon_1_data[240] = { - 0x08, 0x00, 0xfc, 0x02, 0x11, 0x1e, 0x29, 0x02, 0x2f, 0xfc, 0x29, 0x1e, 0x11, 0x02, 0x0b, 0x00, 0xfe, 0x0d, 0x22, 0x08, 0x33, 0xfe, 0x22, 0x0d, 0x09, 0x00, 0xfe, 0x11, 0x2b, 0x0a, 0x33, 0xfe, 0x2b, 0x11, 0x07, 0x00, 0xfe, 0x0d, 0x2b, 0x05, 0x33, 0x02, 0x31, 0x05, 0x33, 0xfe, 0x2b, 0x0d, 0x05, 0x00, 0xfe, 0x02, 0x22, 0x06, 0x33, 0x02, 0x15, 0x06, 0x33, 0xfe, 0x22, 0x02, 0x04, 0x00, 0xff, 0x11, 0x06, 0x33, 0xff, 0x2b, 0x02, 0x01, 0xff, 0x2b, 0x06, 0x33, 0xff, 0x11, 0x04, 0x00, 0xff, 0x1e, 0x06, 0x33, 0xff, 0x0d, 0x02, 0x00, 0xff, 0x0d, 0x06, 0x33, 0xff, 0x1e, 0x04, 0x00, 0xff, 0x29, 0x05, 0x33, 0xff, 0x1f, 0x04, 0x00, 0xff, 0x1f, 0x05, 0x33, 0xff, 0x29, 0x04, 0x00, 0xff, 0x2f, 0x04, 0x33, 0xfe, 0x2f, 0x02, 0x04, 0x00, 0xfe, 0x02, 0x2f, 0x04, 0x33, 0xff, 0x2f, 0x04, 0x00, 0xff, 0x2f, 0x04, 0x33, 0xff, 0x11, 0x06, 0x00, 0xff, 0x15, 0x04, 0x33, 0xff, 0x2f, 0x04, 0x00, 0xff, 0x29, 0x03, 0x33, 0xff, 0x26, 0x08, 0x00, 0xff, 0x26, 0x03, 0x33, 0xff, 0x29, 0x04, 0x00, 0xff, 0x1e, 0x03, 0x33, 0xff, 0x11, 0x08, 0x07, 0xff, 0x15, 0x03, 0x33, 0xff, 0x1e, 0x04, 0x00, 0xff, 0x11, 0x10, 0x33, 0xff, 0x11, 0x04, 0x00, 0xfe, 0x02, 0x22, 0x0e, 0x33, 0xfe, 0x22, 0x02, 0x05, 0x00, 0xfe, 0x0d, 0x2b, 0x0c, 0x33, 0xfe, 0x2b, 0x0d, 0x07, 0x00, 0xfe, 0x11, 0x2b, 0x0a, 0x33, 0xfe, 0x2b, 0x11, 0x09, 0x00, 0xfe, 0x0d, 0x22, 0x08, 0x33, 0xfe, 0x22, 0x0d, 0x0b, 0x00, 0xfc, 0x02, 0x11, 0x1e, 0x29, 0x02, 0x2f, 0xfc, 0x29, 0x1e, 0x11, 0x02, 0x04, 0x00 -}; + 0x08, 0x00, 0xfc, 0x02, 0x11, 0x1e, 0x29, 0x02, 0x2f, 0xfc, 0x29, 0x1e, + 0x11, 0x02, 0x0b, 0x00, 0xfe, 0x0d, 0x22, 0x08, 0x33, 0xfe, 0x22, 0x0d, + 0x09, 0x00, 0xfe, 0x11, 0x2b, 0x0a, 0x33, 0xfe, 0x2b, 0x11, 0x07, 0x00, + 0xfe, 0x0d, 0x2b, 0x05, 0x33, 0x02, 0x31, 0x05, 0x33, 0xfe, 0x2b, 0x0d, + 0x05, 0x00, 0xfe, 0x02, 0x22, 0x06, 0x33, 0x02, 0x15, 0x06, 0x33, 0xfe, + 0x22, 0x02, 0x04, 0x00, 0xff, 0x11, 0x06, 0x33, 0xff, 0x2b, 0x02, 0x01, + 0xff, 0x2b, 0x06, 0x33, 0xff, 0x11, 0x04, 0x00, 0xff, 0x1e, 0x06, 0x33, + 0xff, 0x0d, 0x02, 0x00, 0xff, 0x0d, 0x06, 0x33, 0xff, 0x1e, 0x04, 0x00, + 0xff, 0x29, 0x05, 0x33, 0xff, 0x1f, 0x04, 0x00, 0xff, 0x1f, 0x05, 0x33, + 0xff, 0x29, 0x04, 0x00, 0xff, 0x2f, 0x04, 0x33, 0xfe, 0x2f, 0x02, 0x04, + 0x00, 0xfe, 0x02, 0x2f, 0x04, 0x33, 0xff, 0x2f, 0x04, 0x00, 0xff, 0x2f, + 0x04, 0x33, 0xff, 0x11, 0x06, 0x00, 0xff, 0x15, 0x04, 0x33, 0xff, 0x2f, + 0x04, 0x00, 0xff, 0x29, 0x03, 0x33, 0xff, 0x26, 0x08, 0x00, 0xff, 0x26, + 0x03, 0x33, 0xff, 0x29, 0x04, 0x00, 0xff, 0x1e, 0x03, 0x33, 0xff, 0x11, + 0x08, 0x07, 0xff, 0x15, 0x03, 0x33, 0xff, 0x1e, 0x04, 0x00, 0xff, 0x11, + 0x10, 0x33, 0xff, 0x11, 0x04, 0x00, 0xfe, 0x02, 0x22, 0x0e, 0x33, 0xfe, + 0x22, 0x02, 0x05, 0x00, 0xfe, 0x0d, 0x2b, 0x0c, 0x33, 0xfe, 0x2b, 0x0d, + 0x07, 0x00, 0xfe, 0x11, 0x2b, 0x0a, 0x33, 0xfe, 0x2b, 0x11, 0x09, 0x00, + 0xfe, 0x0d, 0x22, 0x08, 0x33, 0xfe, 0x22, 0x0d, 0x0b, 0x00, 0xfc, 0x02, + 0x11, 0x1e, 0x29, 0x02, 0x2f, 0xfc, 0x29, 0x1e, 0x11, 0x02, 0x04, 0x00}; static const Image confirm_icon_1_image = { - .w = 22, - .h = 18, - .length = sizeof(confirm_icon_1_data), - .data = &confirm_icon_1_data[0] -}; + .w = 22, + .h = 18, + .length = sizeof(confirm_icon_1_data), + .data = &confirm_icon_1_data[0]}; static const AnimationFrame confirm_icon_1_frame = { .x = 233, .y = 4, .duration = 1, .color = 100, - .image = &confirm_icon_1_image -}; + .image = &confirm_icon_1_image}; void to_ppm(Canvas *canvas) { - std::cout << "P2\n" - << canvas->width << " " << canvas->height << "\n" - << "255\n"; - - for (uint16_t y = 0; y < canvas->height; y++) { - for (uint16_t x = 0; x < canvas->width; x++) { - int color = canvas->buffer[y * canvas->width + x]; - std::cout << std::setw(4) << color; - if (x + 1 == canvas->width) - std::cout << "\n"; - } + std::cout << "P2\n" + << canvas->width << " " << canvas->height << "\n" + << "255\n"; + + for (uint16_t y = 0; y < canvas->height; y++) { + for (uint16_t x = 0; x < canvas->width; x++) { + int color = canvas->buffer[y * canvas->width + x]; + std::cout << std::setw(4) << color; + if (x + 1 == canvas->width) std::cout << "\n"; } + } } int main(int argc, char *argv[]) { - Canvas canvas; - canvas.height = 64; - canvas.width = 256; - canvas.buffer = new uint8_t[64 * 255]; + Canvas canvas; + canvas.height = 64; + canvas.width = 256; + canvas.buffer = new uint8_t[64 * 255]; - memset(canvas.buffer, 0, 64 * 255); + memset(canvas.buffer, 0, 64 * 255); - if (!canvas.buffer) - return 1; + if (!canvas.buffer) return 1; - if (draw_bitmap_mono_rle(&canvas, &confirm_icon_1_frame, false)) { - to_ppm(&canvas); - return 0; - } + if (draw_bitmap_mono_rle(&canvas, &confirm_icon_1_frame, false)) { + to_ppm(&canvas); + return 0; + } - return 2; + return 2; } diff --git a/tools/variant/blockpit.c b/tools/variant/blockpit.c index 1b4d4251f..0888d58f3 100644 --- a/tools/variant/blockpit.c +++ b/tools/variant/blockpit.c @@ -21,10 +21,471 @@ #include "keepkey/board/timer.h" -const uint8_t blockpit_logo_data[5567] = -{ - 0x7f, 0x0, 0x7f, 0x0, 0x1d, 0x0, 0xfa, 0x19, 0x94, 0xe2, 0xd0, 0x5e, 0x2, 0x7f, 0x0, 0x79, 0x0, 0xf7, 0x8, 0x6f, 0xdb, 0xe4, 0xe5, 0xe6, 0xe7, 0xbb, 0x34, 0x7f, 0x0, 0x77, 0x0, 0xf4, 0x49, 0xc5, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x95, 0x17, 0x7f, 0x0, 0x73, 0x0, 0xf0, 0x28, 0xa7, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xdf, 0x6b, 0x5, 0x7f, 0x0, 0x6f, 0x0, 0xed, 0x10, 0x81, 0xda, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xc8, 0x40, 0x7f, 0x0, 0x6c, 0x0, 0xe9, 0x3, 0x5c, 0xcc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xa3, 0x1e, 0x7f, 0x0, 0x69, 0x0, 0xe6, 0x39, 0xb4, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xe8, 0x78, 0x9, 0x7f, 0x0, 0x65, 0x0, 0xe3, 0x1c, 0x94, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xd4, 0x4d, 0x7f, 0x0, 0x62, 0x0, 0xdf, 0x9, 0x70, 0xd0, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xb2, 0x26, 0x7f, 0x0, 0x5e, 0x0, 0xdb, 0x1, 0x4c, 0xbe, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf1, 0x86, 0xe, 0x7f, 0x0, 0x5b, 0x0, 0xd8, 0x2b, 0xa3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xe0, 0x5a, 0x1, 0x7f, 0x0, 0x57, 0x0, 0xd5, 0x13, 0x81, 0xd0, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xc1, 0x30, 0x7f, 0x0, 0x54, 0x0, 0xd1, 0x5, 0x5f, 0xc4, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xf9, 0x96, 0x13, 0x18, 0x0, 0xff, 0x1, 0x1e, 0x0, 0xff, 0x1, 0x42, 0x0, 0xff, 0x1, 0x45, 0x0, 0xff, 0x1, 0xf, 0x0, 0xcf, 0x1e, 0xaf, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xec, 0x69, 0x15, 0x0, 0xfd, 0x1, 0x57, 0xc6, 0x1c, 0x0, 0xfd, 0x20, 0xa0, 0x5c, 0x40, 0x0, 0xfd, 0x31, 0xb5, 0x30, 0x43, 0x0, 0xfd, 0x1, 0x54, 0xc6, 0xf, 0x0, 0xce, 0x3b, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xa, 0x13, 0x0, 0xfc, 0x4f, 0xcf, 0xff, 0xf0, 0x1a, 0x0, 0xfb, 0x1a, 0x98, 0xfa, 0xff, 0x60, 0x3e, 0x0, 0xfe, 0x2a, 0xad, 0x2, 0xff, 0xff, 0x30, 0x32, 0x0, 0xfa, 0x6b, 0xdc, 0xf9, 0xf2, 0xc9, 0x34, 0xa, 0x0, 0xfc, 0x4d, 0xcf, 0xff, 0xf0, 0x10, 0x0, 0xd0, 0x30, 0xa7, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xd6, 0x49, 0x12, 0x0, 0xfe, 0x46, 0xc8, 0x3, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xfd, 0x16, 0x90, 0xf7, 0x3, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xfd, 0x23, 0xa3, 0xfe, 0x3, 0xff, 0xff, 0x30, 0x31, 0x0, 0xfe, 0x1d, 0xfe, 0x4, 0xff, 0xff, 0xbf, 0x8, 0x0, 0xfe, 0x46, 0xc8, 0x3, 0xff, 0xff, 0xf0, 0x11, 0x0, 0xd2, 0x2, 0x55, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xed, 0x71, 0x5, 0x13, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xff, 0x3e, 0x5, 0xff, 0xff, 0xe0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x13, 0x0, 0xda, 0xf, 0x7d, 0xd1, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xd9, 0x6e, 0x20, 0x3c, 0xb6, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0x2, 0xf7, 0xfe, 0x98, 0x16, 0x15, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xff, 0x3d, 0x5, 0xff, 0xff, 0xdf, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x15, 0x0, 0xef, 0x28, 0xa3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0x90, 0x18, 0x3, 0x0, 0xee, 0x2, 0x59, 0xd6, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xbe, 0x31, 0x17, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xfe, 0x17, 0xfc, 0x4, 0xff, 0xff, 0xb5, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xfd, 0xc7, 0x96, 0x22, 0x7, 0x0, 0xf2, 0x1, 0x4d, 0xc1, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xb1, 0x31, 0x7, 0x0, 0xf1, 0xe, 0x85, 0xe8, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xdb, 0x56, 0x1, 0x7, 0x0, 0xfd, 0x3a, 0xc9, 0x61, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x32, 0x0, 0xfa, 0x56, 0xbb, 0xd8, 0xcc, 0xa5, 0x22, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xfb, 0xcc, 0xce, 0xcd, 0x76, 0xc, 0x7, 0x0, 0xf5, 0xc, 0x75, 0xd4, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xc9, 0x54, 0x2, 0xa, 0x0, 0xf5, 0x29, 0xb1, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xeb, 0x7d, 0xa, 0x7, 0x0, 0xfb, 0x1b, 0xa2, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x40, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf9, 0xcc, 0xce, 0xd0, 0xd2, 0xc3, 0x53, 0x2, 0x7, 0x0, 0xf9, 0x22, 0x9d, 0xd9, 0xda, 0xd7, 0x76, 0xb, 0xe, 0x0, 0xf9, 0x51, 0xd4, 0xef, 0xf0, 0xf1, 0xa3, 0x1e, 0x7, 0x0, 0xf9, 0x9, 0x77, 0xeb, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x40, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf8, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xac, 0x31, 0x8, 0x0, 0xfd, 0x1a, 0x29, 0xe, 0x11, 0x0, 0xfc, 0x5, 0x33, 0x40, 0x1b, 0x8, 0x0, 0xf8, 0x4f, 0xd4, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x4, 0x0, 0xf9, 0xd, 0x4c, 0x75, 0x80, 0x73, 0x52, 0x19, 0xd, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0xd, 0x0, 0xf8, 0xb, 0x3c, 0x69, 0x7a, 0x80, 0x72, 0x52, 0x20, 0x15, 0x0, 0xf7, 0x5, 0x34, 0x63, 0x76, 0x80, 0x78, 0x69, 0x45, 0x15, 0x9, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x1e, 0x0, 0xf9, 0x6, 0x41, 0x6e, 0x80, 0x75, 0x5b, 0x25, 0x1b, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf6, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0x8b, 0x16, 0x24, 0x0, 0xf6, 0x2a, 0xb2, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x2, 0x0, 0xfd, 0x1f, 0x9d, 0xf9, 0x6, 0xff, 0xfe, 0xc2, 0x52, 0xb, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0xb, 0x0, 0xfd, 0x40, 0xad, 0xf7, 0x7, 0xff, 0xfd, 0xd3, 0x75, 0xc, 0x10, 0x0, 0xfd, 0x2a, 0x9c, 0xee, 0x8, 0xff, 0xfd, 0xd0, 0x6c, 0x8, 0x6, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x9, 0x0, 0xfb, 0x33, 0xcc, 0xff, 0xd2, 0x30, 0x6, 0x0, 0xfa, 0x1, 0x81, 0xf1, 0xfd, 0xb7, 0x17, 0x2, 0x0, 0xfd, 0x10, 0x87, 0xef, 0x6, 0xff, 0xfd, 0xd4, 0x6a, 0x4, 0xa, 0x0, 0xfb, 0x19, 0xb9, 0xfe, 0xf0, 0x7e, 0x5, 0x0, 0xfe, 0x2f, 0x7f, 0x2, 0x90, 0xff, 0xf9, 0x4, 0xff, 0xff, 0xf9, 0x3, 0x90, 0xfe, 0x86, 0x44, 0x7, 0x0, 0xf4, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xd4, 0x68, 0x5, 0x20, 0x0, 0xf4, 0x11, 0x8a, 0xe9, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfc, 0xf0, 0x0, 0x6c, 0xf7, 0xa, 0xff, 0xfe, 0xbe, 0x1a, 0x9, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x9, 0x0, 0xfe, 0x20, 0xbb, 0xc, 0xff, 0xfe, 0xec, 0x60, 0xd, 0x0, 0xfd, 0xa, 0x93, 0xfe, 0xc, 0xff, 0xfe, 0xda, 0x2d, 0x5, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, 0xfe, 0x3a, 0xf1, 0x3, 0xff, 0xfe, 0xe7, 0xf, 0x5, 0x0, 0xff, 0x62, 0x4, 0xff, 0xfc, 0xba, 0x0, 0x4a, 0xe9, 0xa, 0xff, 0xfe, 0xd8, 0x30, 0x9, 0x0, 0xff, 0xbd, 0x4, 0xff, 0xff, 0x5d, 0x3, 0x0, 0xfe, 0x48, 0xfb, 0xe, 0xff, 0xff, 0x73, 0x6, 0x0, 0xf3, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xc1, 0x42, 0x1d, 0x0, 0xf2, 0x4, 0x63, 0xd9, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfe, 0xf0, 0x8e, 0xd, 0xff, 0xfe, 0xea, 0x2d, 0x8, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x8, 0x0, 0xfe, 0x47, 0xf2, 0xf, 0xff, 0xfe, 0xa7, 0x6, 0xa, 0x0, 0xfe, 0x1c, 0xd3, 0xf, 0xff, 0xfe, 0xe7, 0xc, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xfe, 0x42, 0xf6, 0x5, 0xff, 0xff, 0x52, 0x5, 0x0, 0xff, 0xb3, 0x5, 0xff, 0xfe, 0x6e, 0xfd, 0xc, 0xff, 0xfe, 0xf8, 0x4e, 0x7, 0x0, 0xff, 0xf, 0x5, 0xff, 0xff, 0xad, 0x3, 0x0, 0xff, 0xbc, 0xf, 0xff, 0xff, 0xef, 0x6, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0x9e, 0x6, 0x1a, 0x0, 0xf1, 0x22, 0xbe, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x66, 0xe, 0x0, 0xff, 0xf0, 0x14, 0xff, 0xfe, 0xeb, 0x21, 0x7, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x7, 0x0, 0xfe, 0x4e, 0xfa, 0x11, 0xff, 0xfe, 0xb9, 0x5, 0x8, 0x0, 0xfe, 0x15, 0xdc, 0x11, 0xff, 0xff, 0x5b, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x42, 0xf6, 0x6, 0xff, 0xff, 0x36, 0x5, 0x0, 0xff, 0xc0, 0x14, 0xff, 0xfe, 0xfa, 0x40, 0x6, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x3, 0x0, 0xff, 0xc9, 0xf, 0xff, 0xff, 0xfd, 0x6, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x66, 0x1a, 0x0, 0xf1, 0xa9, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0xb, 0xff, 0xfe, 0xf3, 0xfd, 0x8, 0xff, 0xfe, 0xcc, 0x4, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x6, 0x0, 0xfe, 0x2c, 0xf4, 0x8, 0xff, 0xfd, 0xf6, 0xf0, 0xfe, 0x8, 0xff, 0xff, 0x96, 0x7, 0x0, 0xfe, 0x2, 0xbe, 0x9, 0xff, 0xfe, 0xf9, 0xf8, 0x7, 0xff, 0xff, 0x6d, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x42, 0xf6, 0x6, 0xff, 0xff, 0x9f, 0x6, 0x0, 0xff, 0xc0, 0xb, 0xff, 0xfe, 0xf6, 0xfa, 0x8, 0xff, 0xfe, 0xe8, 0x16, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x3, 0x0, 0xff, 0x7a, 0xf, 0xff, 0xff, 0xb3, 0x6, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x90, 0x1a, 0x0, 0xf1, 0xd2, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x8, 0xff, 0xf8, 0xb6, 0x4d, 0xb, 0x0, 0x2, 0x2d, 0x84, 0xf3, 0x6, 0xff, 0xff, 0x6e, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0x3, 0xcb, 0x6, 0xff, 0xfd, 0xed, 0x7c, 0x24, 0x2, 0x0, 0xfd, 0xd, 0x4d, 0xbc, 0x7, 0xff, 0xff, 0x46, 0x6, 0x0, 0xff, 0x65, 0x7, 0xff, 0xfd, 0xb7, 0x56, 0x15, 0x2, 0x0, 0xfd, 0x1b, 0x59, 0xd4, 0x4, 0xff, 0xff, 0x33, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0x4e, 0xf9, 0x6, 0xff, 0xfe, 0xa0, 0x3, 0x6, 0x0, 0xff, 0xc0, 0x8, 0xff, 0xfd, 0xcd, 0x5d, 0x13, 0x2, 0x0, 0xfd, 0x21, 0x71, 0xe6, 0x6, 0xff, 0xff, 0x9a, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x3, 0x0, 0xfd, 0x3, 0x82, 0xd9, 0x2, 0xe0, 0xff, 0xfe, 0x4, 0xff, 0xff, 0xfe, 0x3, 0xe0, 0xfd, 0xde, 0xa1, 0x12, 0x6, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x6, 0xff, 0xfe, 0xfd, 0x65, 0x7, 0x0, 0xfe, 0x23, 0xdc, 0x5, 0xff, 0xfe, 0xea, 0x7, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0x5f, 0x6, 0xff, 0xfe, 0xc0, 0x16, 0x7, 0x0, 0xfe, 0x66, 0xfd, 0x5, 0xff, 0xfe, 0xd6, 0x1, 0x4, 0x0, 0xfe, 0x6, 0xe6, 0x5, 0xff, 0xfe, 0xf6, 0x53, 0x7, 0x0, 0xfb, 0x7, 0x7f, 0xe5, 0xe9, 0x79, 0x5, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x4e, 0xfa, 0x6, 0xff, 0xfe, 0x90, 0x1, 0x7, 0x0, 0xff, 0xc0, 0x7, 0xff, 0xfe, 0x8e, 0x3, 0x6, 0x0, 0xfe, 0x11, 0xbe, 0x5, 0xff, 0xfe, 0xfe, 0x21, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x6, 0xff, 0xff, 0x74, 0x9, 0x0, 0xfe, 0x20, 0xf1, 0x5, 0xff, 0xff, 0x5c, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0xd5, 0x5, 0xff, 0xfe, 0xcd, 0xa, 0x9, 0x0, 0xff, 0x60, 0x6, 0xff, 0xff, 0x4c, 0x4, 0x0, 0xff, 0x5c, 0x6, 0xff, 0xff, 0x4b, 0x12, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xfe, 0x4e, 0xfa, 0x6, 0xff, 0xff, 0x7f, 0x9, 0x0, 0xff, 0xc0, 0x6, 0xff, 0xff, 0xa3, 0x9, 0x0, 0xfe, 0xa, 0xd8, 0x5, 0xff, 0xff, 0x8a, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xfe, 0xc7, 0x2, 0xa, 0x0, 0xff, 0x68, 0x5, 0xff, 0xff, 0xae, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x2f, 0x5, 0xff, 0xfe, 0xfc, 0x2a, 0xb, 0x0, 0xff, 0xaf, 0x5, 0xff, 0xff, 0xa7, 0x4, 0x0, 0xff, 0xb0, 0x5, 0xff, 0xff, 0x9e, 0x13, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x5a, 0xfa, 0x6, 0xff, 0xff, 0x6e, 0xa, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfe, 0xea, 0xe, 0xa, 0x0, 0xff, 0x38, 0x5, 0xff, 0xff, 0xda, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xff, 0x50, 0xb, 0x0, 0xfe, 0x7, 0xe9, 0x4, 0xff, 0xff, 0xef, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x79, 0x5, 0xff, 0xff, 0xa6, 0xc, 0x0, 0xff, 0x2f, 0x5, 0xff, 0xff, 0xef, 0x3, 0x0, 0xfe, 0x1, 0xf2, 0x5, 0xff, 0xff, 0x27, 0x13, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfd, 0x30, 0x5b, 0xfd, 0x5, 0xff, 0xfe, 0xfd, 0x5e, 0xb, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x80, 0xc, 0x0, 0xff, 0xc2, 0x5, 0xff, 0xff, 0x1c, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfe, 0xf8, 0x8, 0xc, 0x0, 0xff, 0xa1, 0x5, 0xff, 0xff, 0x1b, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xa9, 0x5, 0xff, 0xff, 0x4f, 0xd, 0x0, 0xff, 0xd7, 0x5, 0xff, 0xff, 0x20, 0x2, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xd6, 0x14, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfe, 0x8b, 0xfd, 0x5, 0xff, 0xfe, 0xf9, 0x4f, 0xc, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x30, 0xc, 0x0, 0xff, 0x73, 0x5, 0xff, 0xff, 0x48, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xca, 0xd, 0x0, 0xff, 0x6c, 0x5, 0xff, 0xff, 0x39, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xcc, 0x5, 0xff, 0xff, 0x18, 0xd, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x43, 0x2, 0x0, 0xff, 0x3f, 0x5, 0xff, 0xff, 0xa0, 0x14, 0x0, 0xff, 0xa0, 0xc, 0xff, 0xff, 0x48, 0xd, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xfe, 0xf7, 0x2, 0xc, 0x0, 0xff, 0x3d, 0x5, 0xff, 0xff, 0x65, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xb5, 0xd, 0x0, 0xff, 0x57, 0x5, 0xff, 0xff, 0x46, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xdb, 0x4, 0xff, 0xff, 0xfd, 0xe, 0x0, 0xff, 0x84, 0x5, 0xff, 0xff, 0x52, 0x2, 0x0, 0xff, 0x4e, 0x5, 0xff, 0xff, 0x8a, 0x14, 0x0, 0xff, 0xa0, 0xc, 0xff, 0xfe, 0xab, 0x3, 0xc, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xff, 0xe4, 0xd, 0x0, 0xff, 0x28, 0x5, 0xff, 0xff, 0x72, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xb4, 0xd, 0x0, 0xff, 0x56, 0x5, 0xff, 0xff, 0x47, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xdd, 0x4, 0xff, 0xff, 0xfb, 0xe, 0x0, 0xff, 0x81, 0x5, 0xff, 0xff, 0x54, 0x2, 0x0, 0xff, 0x50, 0x5, 0xff, 0xff, 0x87, 0x14, 0x0, 0xff, 0xa0, 0xd, 0xff, 0xff, 0x95, 0xc, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xff, 0xe3, 0xd, 0x0, 0xff, 0x27, 0x5, 0xff, 0xff, 0x73, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xc8, 0xd, 0x0, 0xff, 0x6a, 0x5, 0xff, 0xff, 0x3b, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xcf, 0x5, 0xff, 0xff, 0x10, 0xd, 0x0, 0xff, 0x9a, 0x5, 0xff, 0xff, 0x46, 0x2, 0x0, 0xff, 0x40, 0x5, 0xff, 0xff, 0x9c, 0x14, 0x0, 0xff, 0xa0, 0xe, 0xff, 0xff, 0x7f, 0xb, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xfe, 0xf6, 0x1, 0xc, 0x0, 0xff, 0x3b, 0x5, 0xff, 0xff, 0x67, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xa2, 0x19, 0x0, 0xf0, 0x15, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfe, 0xf6, 0x6, 0xc, 0x0, 0xff, 0x9e, 0x5, 0xff, 0xff, 0x1f, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xb0, 0x5, 0xff, 0xff, 0x44, 0xd, 0x0, 0xff, 0xcc, 0x5, 0xff, 0xff, 0x27, 0x2, 0x0, 0xff, 0x25, 0x5, 0xff, 0xff, 0xd0, 0x14, 0x0, 0xff, 0xa0, 0x7, 0xff, 0xff, 0xfc, 0x7, 0xff, 0xff, 0x65, 0xa, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x2b, 0xc, 0x0, 0xff, 0x70, 0x5, 0xff, 0xff, 0x4b, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf0, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe5, 0x3b, 0x17, 0x0, 0xef, 0xc, 0x9c, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xff, 0x49, 0xb, 0x0, 0xfe, 0x6, 0xe6, 0x4, 0xff, 0xfe, 0xf4, 0x1, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x99, 0xc, 0x0, 0xff, 0x21, 0x5, 0xff, 0xfe, 0xf7, 0x3, 0x2, 0x0, 0xfe, 0x3, 0xf7, 0x4, 0xff, 0xfe, 0xfe, 0x22, 0x13, 0x0, 0xff, 0xa0, 0x6, 0xff, 0xfd, 0xc9, 0x26, 0xd3, 0x6, 0xff, 0xfe, 0xfd, 0x52, 0x9, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x78, 0xc, 0x0, 0xff, 0xbd, 0x5, 0xff, 0xff, 0x22, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf2, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x2, 0xe9, 0xfe, 0x8d, 0x13, 0x13, 0x0, 0xed, 0x2, 0x53, 0xc9, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x63, 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xff, 0xbe, 0xb, 0x0, 0xff, 0x60, 0x5, 0xff, 0xff, 0xb4, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x3c, 0x5, 0xff, 0xfe, 0xf7, 0x1d, 0xb, 0x0, 0xff, 0x9d, 0x5, 0xff, 0xff, 0xb3, 0x4, 0x0, 0xff, 0xba, 0x5, 0xff, 0xff, 0x9a, 0x13, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfb, 0xbd, 0xc, 0x0, 0x1b, 0xdc, 0x6, 0xff, 0xfe, 0xf8, 0x3f, 0x8, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfe, 0xe4, 0xa, 0xa, 0x0, 0xff, 0x32, 0x5, 0xff, 0xff, 0xe2, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xec, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xe0, 0x66, 0x4, 0x10, 0x0, 0xec, 0x31, 0xad, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x6, 0xff, 0xff, 0x65, 0x9, 0x0, 0xfe, 0x19, 0xed, 0x5, 0xff, 0xff, 0x69, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xfe, 0x2, 0xe4, 0x5, 0xff, 0xfe, 0xbd, 0x3, 0x9, 0x0, 0xfe, 0x4a, 0xfe, 0x5, 0xff, 0xff, 0x5d, 0x4, 0x0, 0xff, 0x6b, 0x6, 0xff, 0xff, 0x48, 0x12, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x24, 0xe5, 0x6, 0xff, 0xfe, 0xf1, 0x2f, 0x7, 0x0, 0xff, 0xc0, 0x6, 0xff, 0xff, 0x94, 0x9, 0x0, 0xfe, 0x7, 0xd0, 0x5, 0xff, 0xff, 0x94, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xeb, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xc9, 0x3e, 0xd, 0x0, 0xea, 0x16, 0x8a, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x6, 0xff, 0xfe, 0xfa, 0x4e, 0x7, 0x0, 0xfe, 0x18, 0xd3, 0x5, 0xff, 0xfe, 0xf3, 0xd, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0x72, 0x6, 0xff, 0xfe, 0xab, 0xc, 0x7, 0x0, 0xfe, 0x4a, 0xf6, 0x5, 0xff, 0xfe, 0xe2, 0x6, 0x4, 0x0, 0xfe, 0xe, 0xf4, 0x5, 0xff, 0xfe, 0xf1, 0x43, 0x8, 0x0, 0xfc, 0x28, 0x92, 0x9c, 0x4a, 0x5, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0x2d, 0xec, 0x6, 0xff, 0xfe, 0xe7, 0x22, 0x6, 0x0, 0xff, 0xc0, 0x7, 0xff, 0xff, 0x75, 0x7, 0x0, 0xfe, 0x9, 0xb2, 0x6, 0xff, 0xff, 0x2d, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xe7, 0x4, 0xff, 0xfe, 0xfa, 0x3, 0xb, 0x0, 0xe9, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xa6, 0x1e, 0x9, 0x0, 0xe8, 0x7, 0x66, 0xcb, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x8, 0xff, 0xfe, 0x9a, 0x30, 0x3, 0x0, 0xfd, 0x14, 0x6b, 0xea, 0x6, 0xff, 0xff, 0x82, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0xa, 0xde, 0x6, 0xff, 0xfd, 0xde, 0x61, 0xd, 0x3, 0x0, 0xfe, 0x33, 0xa1, 0x7, 0xff, 0xff, 0x5f, 0x6, 0x0, 0xff, 0x83, 0x6, 0xff, 0xfd, 0xfe, 0x9f, 0x32, 0x4, 0x0, 0xfd, 0x1a, 0x84, 0xfa, 0x3, 0xff, 0xff, 0x50, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x37, 0xf3, 0x6, 0xff, 0xfe, 0xdc, 0x15, 0x5, 0x0, 0xff, 0xc0, 0x8, 0xff, 0xfd, 0xb5, 0x3f, 0x3, 0x2, 0x0, 0xfd, 0xc, 0x59, 0xd8, 0x6, 0xff, 0xff, 0xb0, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xd6, 0x5, 0xff, 0xfa, 0x82, 0xf, 0x21, 0x5c, 0x4f, 0x1, 0x6, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf1, 0x7e, 0x6, 0x6, 0x0, 0xe7, 0x3f, 0xb5, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0xa, 0xff, 0xfc, 0xed, 0xd4, 0xe2, 0xfd, 0x7, 0xff, 0xfe, 0xdf, 0xb, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x6, 0x0, 0xfe, 0x40, 0xfd, 0x7, 0xff, 0xfc, 0xfd, 0xdd, 0xd4, 0xef, 0x8, 0xff, 0xff, 0xb4, 0x7, 0x0, 0xfe, 0xb, 0xde, 0x8, 0xff, 0xfc, 0xef, 0xd6, 0xd9, 0xec, 0x6, 0xff, 0xff, 0xb1, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x42, 0xf9, 0x6, 0xff, 0xff, 0xbf, 0x5, 0x0, 0xff, 0xc0, 0xa, 0xff, 0xfc, 0xf3, 0xd7, 0xdc, 0xfa, 0x7, 0xff, 0xfe, 0xf4, 0x22, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xbb, 0xa, 0xff, 0xff, 0x74, 0x6, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9d, 0x5, 0x0, 0xe6, 0x12, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x14, 0xff, 0xfe, 0xfa, 0x36, 0x7, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x7, 0x0, 0xff, 0x6b, 0x12, 0xff, 0xfe, 0xd2, 0xf, 0x8, 0x0, 0xfe, 0x31, 0xf6, 0x11, 0xff, 0xff, 0xb4, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xfe, 0x4f, 0xfd, 0x6, 0xff, 0xff, 0x2e, 0x4, 0x0, 0xff, 0xc0, 0x15, 0xff, 0xff, 0x5a, 0x6, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0x7b, 0xa, 0xff, 0xff, 0xc5, 0x6, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xf6, 0x5, 0x0, 0xe6, 0x2b, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x58, 0xe, 0x0, 0xff, 0xed, 0x4, 0xff, 0xfe, 0xf3, 0xdc, 0xd, 0xff, 0xfe, 0xfa, 0x4e, 0x8, 0x0, 0xff, 0x70, 0x5, 0xff, 0xff, 0x55, 0x8, 0x0, 0xfe, 0x69, 0xfd, 0xf, 0xff, 0xfe, 0xc5, 0x14, 0xa, 0x0, 0xfe, 0x42, 0xf1, 0xf, 0xff, 0xfe, 0xfd, 0x48, 0x4, 0x0, 0xff, 0x9b, 0x5, 0xff, 0xff, 0x29, 0x8, 0x0, 0xff, 0x5e, 0x6, 0xff, 0xff, 0x3c, 0x4, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0xcc, 0xe, 0xff, 0xff, 0x69, 0x7, 0x0, 0xff, 0x13, 0x5, 0xff, 0xff, 0xb1, 0x8, 0x0, 0xfe, 0x1e, 0xf6, 0x9, 0xff, 0xff, 0xc1, 0x6, 0x0, 0xe7, 0xa3, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x34, 0xe, 0x0, 0xff, 0xcd, 0x4, 0xff, 0xfd, 0xca, 0x14, 0xb2, 0xb, 0xff, 0xfe, 0xdf, 0x36, 0x9, 0x0, 0xfe, 0x2e, 0xfd, 0x3, 0xff, 0xfe, 0xf5, 0x17, 0x9, 0x0, 0xfe, 0x38, 0xd7, 0xc, 0xff, 0xfd, 0xfa, 0x82, 0x7, 0xc, 0x0, 0xfe, 0x27, 0xcd, 0xd, 0xff, 0xfe, 0xea, 0x4e, 0x5, 0x0, 0xff, 0x54, 0x4, 0xff, 0xfe, 0xe1, 0x3, 0x9, 0x0, 0xff, 0x6e, 0x4, 0xff, 0xfe, 0xe4, 0x9, 0x4, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfd, 0x17, 0x91, 0xfe, 0xa, 0xff, 0xfe, 0xef, 0x51, 0x9, 0x0, 0xff, 0xcc, 0x4, 0xff, 0xff, 0x6c, 0x9, 0x0, 0xfe, 0x52, 0xf3, 0x7, 0xff, 0xfe, 0xf9, 0x43, 0x6, 0x0, 0xe7, 0x1c, 0xa1, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe7, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xed, 0x6f, 0xf, 0x0, 0xfe, 0x55, 0xfe, 0x2, 0xff, 0xfe, 0xfd, 0x4d, 0x2, 0x0, 0xfe, 0x4a, 0xc6, 0x7, 0xff, 0xfd, 0xe7, 0x7a, 0x9, 0xb, 0x0, 0xfb, 0x66, 0xf4, 0xff, 0xe9, 0x4b, 0xb, 0x0, 0xfd, 0x4, 0x60, 0xcd, 0x8, 0xff, 0xfd, 0xee, 0x95, 0x1e, 0xf, 0x0, 0xfd, 0x2, 0x60, 0xd0, 0x9, 0xff, 0xfd, 0xcb, 0x6e, 0xc, 0x7, 0x0, 0xfb, 0x8b, 0xfc, 0xff, 0xe0, 0x35, 0xb, 0x0, 0xfb, 0x6d, 0xf3, 0xff, 0xce, 0x2a, 0x5, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfb, 0x10, 0x0, 0x35, 0xb4, 0xfe, 0x6, 0xff, 0xfd, 0xf1, 0x90, 0x14, 0xa, 0x0, 0xfa, 0x26, 0xd5, 0xff, 0xfe, 0x9a, 0x3, 0xa, 0x0, 0xfc, 0x16, 0x82, 0xd2, 0xfc, 0x2, 0xff, 0xfd, 0xf9, 0xb1, 0x2e, 0x8, 0x0, 0xe8, 0x1, 0x4c, 0xbd, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe8, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf4, 0x99, 0x17, 0x11, 0x0, 0xfc, 0x3c, 0x95, 0x94, 0x3b, 0x5, 0x0, 0xf8, 0x26, 0x69, 0x8f, 0xa0, 0x93, 0x75, 0x3f, 0x3, 0xe, 0x0, 0xfd, 0x8, 0x1f, 0x3, 0xf, 0x0, 0xf7, 0x21, 0x59, 0x84, 0x96, 0x9d, 0x8e, 0x6f, 0x3d, 0x5, 0x14, 0x0, 0xf7, 0x25, 0x5e, 0x8a, 0x99, 0x9c, 0x8c, 0x79, 0x4b, 0x18, 0xb, 0x0, 0xfd, 0xf, 0x1f, 0x2, 0xd, 0x0, 0xfe, 0x6, 0x11, 0x7, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x3, 0x0, 0xf8, 0x1a, 0x5e, 0x8a, 0x9e, 0x95, 0x7d, 0x49, 0x9, 0xe, 0x0, 0xfe, 0x1c, 0x10, 0xf, 0x0, 0xfc, 0x7, 0x1a, 0x1f, 0x5, 0xc, 0x0, 0xea, 0xb, 0x72, 0xd2, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xea, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xbd, 0x32, 0x7f, 0x0, 0xf, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x3c, 0x0, 0xec, 0x1f, 0x99, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xeb, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xd7, 0x55, 0x1, 0x7f, 0x0, 0x10, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x3e, 0x0, 0xee, 0x3f, 0xbc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xed, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xe4, 0x7b, 0xa, 0x7f, 0x0, 0x12, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x3f, 0x0, 0xef, 0x5, 0x68, 0xd5, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xef, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0x9d, 0x1e, 0x7f, 0x0, 0x14, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x41, 0x0, 0xf1, 0x16, 0x90, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf1, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xbd, 0x3b, 0x7f, 0x0, 0x16, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x43, 0x0, 0xf3, 0x33, 0xb8, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf2, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xd1, 0x5d, 0x4, 0x7f, 0x0, 0x17, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x44, 0x0, 0xf4, 0x2, 0x5b, 0xd8, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf4, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xda, 0x81, 0x10, 0x7f, 0x0, 0x19, 0x0, 0xff, 0xae, 0x4, 0xff, 0xfe, 0xfd, 0x9, 0x46, 0x0, 0xf6, 0xe, 0x85, 0xec, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xa1, 0x25, 0x7f, 0x0, 0x1b, 0x0, 0xff, 0x53, 0x4, 0xff, 0xff, 0xa7, 0x49, 0x0, 0xf8, 0x27, 0xb0, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf8, 0x31, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xbb, 0x44, 0x7f, 0x0, 0x1e, 0x0, 0xfb, 0x63, 0xd2, 0xdd, 0x95, 0xb, 0x4b, 0x0, 0xfa, 0x4d, 0xd6, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf9, 0x32, 0xcd, 0xcf, 0xd1, 0xc9, 0x65, 0x6, 0x7f, 0x0, 0x70, 0x0, 0xfb, 0x8, 0x78, 0xf0, 0xfb, 0xfd, 0x5, 0x0, 0xfb, 0x32, 0xcd, 0xcf, 0x85, 0x16, 0x7f, 0x0, 0x74, 0x0, 0xfd, 0x1c, 0xa5, 0xe7, 0x5, 0x0, 0xfd, 0x26, 0x9d, 0x2d, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x60, 0x0 -}; +const uint8_t blockpit_logo_data[5567] = { + 0x7f, 0x0, 0x7f, 0x0, 0x1d, 0x0, 0xfa, 0x19, 0x94, 0xe2, 0xd0, 0x5e, + 0x2, 0x7f, 0x0, 0x79, 0x0, 0xf7, 0x8, 0x6f, 0xdb, 0xe4, 0xe5, 0xe6, + 0xe7, 0xbb, 0x34, 0x7f, 0x0, 0x77, 0x0, 0xf4, 0x49, 0xc5, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x95, 0x17, 0x7f, 0x0, 0x73, 0x0, + 0xf0, 0x28, 0xa7, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xdf, 0x6b, 0x5, 0x7f, 0x0, 0x6f, 0x0, 0xed, 0x10, 0x81, + 0xda, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xc8, 0x40, 0x7f, 0x0, 0x6c, 0x0, 0xe9, 0x3, 0x5c, + 0xcc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xa3, 0x1e, 0x7f, 0x0, 0x69, + 0x0, 0xe6, 0x39, 0xb4, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, + 0xef, 0xe8, 0x78, 0x9, 0x7f, 0x0, 0x65, 0x0, 0xe3, 0x1c, 0x94, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, + 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xd4, 0x4d, 0x7f, 0x0, 0x62, 0x0, 0xdf, 0x9, 0x70, 0xd0, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, + 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xb2, 0x26, 0x7f, 0x0, 0x5e, 0x0, 0xdb, 0x1, 0x4c, 0xbe, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, + 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf1, 0x86, 0xe, 0x7f, 0x0, + 0x5b, 0x0, 0xd8, 0x2b, 0xa3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xe0, 0x5a, 0x1, 0x7f, 0x0, 0x57, 0x0, 0xd5, + 0x13, 0x81, 0xd0, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xc1, 0x30, 0x7f, 0x0, 0x54, 0x0, 0xd1, + 0x5, 0x5f, 0xc4, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, + 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xf9, 0x96, 0x13, 0x18, + 0x0, 0xff, 0x1, 0x1e, 0x0, 0xff, 0x1, 0x42, 0x0, 0xff, 0x1, 0x45, + 0x0, 0xff, 0x1, 0xf, 0x0, 0xcf, 0x1e, 0xaf, 0xce, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, + 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xec, 0x69, 0x15, 0x0, 0xfd, 0x1, 0x57, + 0xc6, 0x1c, 0x0, 0xfd, 0x20, 0xa0, 0x5c, 0x40, 0x0, 0xfd, 0x31, 0xb5, + 0x30, 0x43, 0x0, 0xfd, 0x1, 0x54, 0xc6, 0xf, 0x0, 0xce, 0x3b, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xa, + 0x13, 0x0, 0xfc, 0x4f, 0xcf, 0xff, 0xf0, 0x1a, 0x0, 0xfb, 0x1a, 0x98, + 0xfa, 0xff, 0x60, 0x3e, 0x0, 0xfe, 0x2a, 0xad, 0x2, 0xff, 0xff, 0x30, + 0x32, 0x0, 0xfa, 0x6b, 0xdc, 0xf9, 0xf2, 0xc9, 0x34, 0xa, 0x0, 0xfc, + 0x4d, 0xcf, 0xff, 0xf0, 0x10, 0x0, 0xd0, 0x30, 0xa7, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, + 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xd6, 0x49, 0x12, 0x0, 0xfe, 0x46, 0xc8, + 0x3, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xfd, 0x16, 0x90, 0xf7, 0x3, 0xff, + 0xff, 0x60, 0x3c, 0x0, 0xfd, 0x23, 0xa3, 0xfe, 0x3, 0xff, 0xff, 0x30, + 0x31, 0x0, 0xfe, 0x1d, 0xfe, 0x4, 0xff, 0xff, 0xbf, 0x8, 0x0, 0xfe, + 0x46, 0xc8, 0x3, 0xff, 0xff, 0xf0, 0x11, 0x0, 0xd2, 0x2, 0x55, 0xc2, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, + 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xfa, 0xed, 0x71, 0x5, 0x13, 0x0, 0xff, 0xf0, 0x4, + 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, + 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xff, 0x3e, 0x5, + 0xff, 0xff, 0xe0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x13, + 0x0, 0xda, 0xf, 0x7d, 0xd1, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xd9, 0x6e, 0x20, 0x3c, + 0xb6, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0x2, 0xf7, 0xfe, 0x98, 0x16, 0x15, 0x0, 0xff, + 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, + 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xff, + 0x3d, 0x5, 0xff, 0xff, 0xdf, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, + 0xf0, 0x15, 0x0, 0xef, 0x28, 0xa3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0x90, 0x18, 0x3, 0x0, 0xee, + 0x2, 0x59, 0xd6, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xbe, 0x31, 0x17, 0x0, 0xff, 0xf0, 0x4, 0xff, + 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x3c, 0x0, + 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x31, 0x0, 0xfe, 0x17, 0xfc, 0x4, + 0xff, 0xff, 0xb5, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, + 0x0, 0xfd, 0xc7, 0x96, 0x22, 0x7, 0x0, 0xf2, 0x1, 0x4d, 0xc1, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xb1, 0x31, 0x7, 0x0, + 0xf1, 0xe, 0x85, 0xe8, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xdb, 0x56, 0x1, 0x7, 0x0, 0xfd, 0x3a, 0xc9, 0x61, 0xe, 0x0, + 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, 0xff, + 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x32, 0x0, + 0xfa, 0x56, 0xbb, 0xd8, 0xcc, 0xa5, 0x22, 0x8, 0x0, 0xff, 0xf0, 0x4, + 0xff, 0xff, 0xf0, 0xc, 0x0, 0xfb, 0xcc, 0xce, 0xcd, 0x76, 0xc, 0x7, + 0x0, 0xf5, 0xc, 0x75, 0xd4, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xc9, 0x54, + 0x2, 0xa, 0x0, 0xf5, 0x29, 0xb1, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xeb, 0x7d, 0xa, 0x7, 0x0, 0xfb, 0x1b, 0xa2, 0xfa, 0xfc, 0x6d, 0xe, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, + 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x40, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf9, 0xcc, 0xce, + 0xd0, 0xd2, 0xc3, 0x53, 0x2, 0x7, 0x0, 0xf9, 0x22, 0x9d, 0xd9, 0xda, + 0xd7, 0x76, 0xb, 0xe, 0x0, 0xf9, 0x51, 0xd4, 0xef, 0xf0, 0xf1, 0xa3, + 0x1e, 0x7, 0x0, 0xf9, 0x9, 0x77, 0xeb, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x18, 0x0, 0xff, 0x80, 0x5, + 0xff, 0xff, 0x60, 0x3c, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x40, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf8, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xac, 0x31, 0x8, 0x0, 0xfd, 0x1a, 0x29, 0xe, + 0x11, 0x0, 0xfc, 0x5, 0x33, 0x40, 0x1b, 0x8, 0x0, 0xf8, 0x4f, 0xd4, + 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, + 0xff, 0xf0, 0x4, 0x0, 0xf9, 0xd, 0x4c, 0x75, 0x80, 0x73, 0x52, 0x19, + 0xd, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0xd, 0x0, 0xf8, 0xb, + 0x3c, 0x69, 0x7a, 0x80, 0x72, 0x52, 0x20, 0x15, 0x0, 0xf7, 0x5, 0x34, + 0x63, 0x76, 0x80, 0x78, 0x69, 0x45, 0x15, 0x9, 0x0, 0xff, 0xa0, 0x5, + 0xff, 0xff, 0x30, 0x1e, 0x0, 0xf9, 0x6, 0x41, 0x6e, 0x80, 0x75, 0x5b, + 0x25, 0x1b, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf6, + 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0x8b, 0x16, 0x24, 0x0, + 0xf6, 0x2a, 0xb2, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0x2, 0x0, 0xfd, 0x1f, 0x9d, + 0xf9, 0x6, 0xff, 0xfe, 0xc2, 0x52, 0xb, 0x0, 0xff, 0x80, 0x5, 0xff, + 0xff, 0x60, 0xb, 0x0, 0xfd, 0x40, 0xad, 0xf7, 0x7, 0xff, 0xfd, 0xd3, + 0x75, 0xc, 0x10, 0x0, 0xfd, 0x2a, 0x9c, 0xee, 0x8, 0xff, 0xfd, 0xd0, + 0x6c, 0x8, 0x6, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x9, 0x0, + 0xfb, 0x33, 0xcc, 0xff, 0xd2, 0x30, 0x6, 0x0, 0xfa, 0x1, 0x81, 0xf1, + 0xfd, 0xb7, 0x17, 0x2, 0x0, 0xfd, 0x10, 0x87, 0xef, 0x6, 0xff, 0xfd, + 0xd4, 0x6a, 0x4, 0xa, 0x0, 0xfb, 0x19, 0xb9, 0xfe, 0xf0, 0x7e, 0x5, + 0x0, 0xfe, 0x2f, 0x7f, 0x2, 0x90, 0xff, 0xf9, 0x4, 0xff, 0xff, 0xf9, + 0x3, 0x90, 0xfe, 0x86, 0x44, 0x7, 0x0, 0xf4, 0xcc, 0xce, 0xd0, 0xd2, + 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xd4, 0x68, 0x5, 0x20, 0x0, 0xf4, 0x11, + 0x8a, 0xe9, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfc, 0xf0, 0x0, 0x6c, 0xf7, 0xa, 0xff, + 0xfe, 0xbe, 0x1a, 0x9, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x9, + 0x0, 0xfe, 0x20, 0xbb, 0xc, 0xff, 0xfe, 0xec, 0x60, 0xd, 0x0, 0xfd, + 0xa, 0x93, 0xfe, 0xc, 0xff, 0xfe, 0xda, 0x2d, 0x5, 0x0, 0xff, 0xa0, + 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, 0xfe, 0x3a, 0xf1, 0x3, 0xff, 0xfe, + 0xe7, 0xf, 0x5, 0x0, 0xff, 0x62, 0x4, 0xff, 0xfc, 0xba, 0x0, 0x4a, + 0xe9, 0xa, 0xff, 0xfe, 0xd8, 0x30, 0x9, 0x0, 0xff, 0xbd, 0x4, 0xff, + 0xff, 0x5d, 0x3, 0x0, 0xfe, 0x48, 0xfb, 0xe, 0xff, 0xff, 0x73, 0x6, + 0x0, 0xf3, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xc1, 0x42, 0x1d, 0x0, 0xf2, 0x4, 0x63, 0xd9, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0xe, 0x0, 0xff, 0xf0, + 0x4, 0xff, 0xfe, 0xf0, 0x8e, 0xd, 0xff, 0xfe, 0xea, 0x2d, 0x8, 0x0, + 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x8, 0x0, 0xfe, 0x47, 0xf2, 0xf, + 0xff, 0xfe, 0xa7, 0x6, 0xa, 0x0, 0xfe, 0x1c, 0xd3, 0xf, 0xff, 0xfe, + 0xe7, 0xc, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, + 0xfe, 0x42, 0xf6, 0x5, 0xff, 0xff, 0x52, 0x5, 0x0, 0xff, 0xb3, 0x5, + 0xff, 0xfe, 0x6e, 0xfd, 0xc, 0xff, 0xfe, 0xf8, 0x4e, 0x7, 0x0, 0xff, + 0xf, 0x5, 0xff, 0xff, 0xad, 0x3, 0x0, 0xff, 0xbc, 0xf, 0xff, 0xff, + 0xef, 0x6, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, + 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0x9e, 0x6, 0x1a, 0x0, 0xf1, 0x22, 0xbe, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, + 0x66, 0xe, 0x0, 0xff, 0xf0, 0x14, 0xff, 0xfe, 0xeb, 0x21, 0x7, 0x0, + 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x7, 0x0, 0xfe, 0x4e, 0xfa, 0x11, + 0xff, 0xfe, 0xb9, 0x5, 0x8, 0x0, 0xfe, 0x15, 0xdc, 0x11, 0xff, 0xff, + 0x5b, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, + 0x42, 0xf6, 0x6, 0xff, 0xff, 0x36, 0x5, 0x0, 0xff, 0xc0, 0x14, 0xff, + 0xfe, 0xfa, 0x40, 0x6, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x3, + 0x0, 0xff, 0xc9, 0xf, 0xff, 0xff, 0xfd, 0x6, 0x0, 0xf1, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, + 0x66, 0x1a, 0x0, 0xf1, 0xa9, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, + 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0xb, + 0xff, 0xfe, 0xf3, 0xfd, 0x8, 0xff, 0xfe, 0xcc, 0x4, 0x6, 0x0, 0xff, + 0x80, 0x5, 0xff, 0xff, 0x60, 0x6, 0x0, 0xfe, 0x2c, 0xf4, 0x8, 0xff, + 0xfd, 0xf6, 0xf0, 0xfe, 0x8, 0xff, 0xff, 0x96, 0x7, 0x0, 0xfe, 0x2, + 0xbe, 0x9, 0xff, 0xfe, 0xf9, 0xf8, 0x7, 0xff, 0xff, 0x6d, 0x4, 0x0, + 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x42, 0xf6, 0x6, + 0xff, 0xff, 0x9f, 0x6, 0x0, 0xff, 0xc0, 0xb, 0xff, 0xfe, 0xf6, 0xfa, + 0x8, 0xff, 0xfe, 0xe8, 0x16, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, + 0xc0, 0x3, 0x0, 0xff, 0x7a, 0xf, 0xff, 0xff, 0xb3, 0x6, 0x0, 0xf1, + 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, + 0xe5, 0xe7, 0x90, 0x1a, 0x0, 0xf1, 0xd2, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, + 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, + 0xf0, 0x8, 0xff, 0xf8, 0xb6, 0x4d, 0xb, 0x0, 0x2, 0x2d, 0x84, 0xf3, + 0x6, 0xff, 0xff, 0x6e, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, + 0x5, 0x0, 0xfe, 0x3, 0xcb, 0x6, 0xff, 0xfd, 0xed, 0x7c, 0x24, 0x2, + 0x0, 0xfd, 0xd, 0x4d, 0xbc, 0x7, 0xff, 0xff, 0x46, 0x6, 0x0, 0xff, + 0x65, 0x7, 0xff, 0xfd, 0xb7, 0x56, 0x15, 0x2, 0x0, 0xfd, 0x1b, 0x59, + 0xd4, 0x4, 0xff, 0xff, 0x33, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, + 0x30, 0x4, 0x0, 0xfe, 0x4e, 0xf9, 0x6, 0xff, 0xfe, 0xa0, 0x3, 0x6, + 0x0, 0xff, 0xc0, 0x8, 0xff, 0xfd, 0xcd, 0x5d, 0x13, 0x2, 0x0, 0xfd, + 0x21, 0x71, 0xe6, 0x6, 0xff, 0xff, 0x9a, 0x5, 0x0, 0xff, 0x20, 0x5, + 0xff, 0xff, 0xc0, 0x3, 0x0, 0xfd, 0x3, 0x82, 0xd9, 0x2, 0xe0, 0xff, + 0xfe, 0x4, 0xff, 0xff, 0xfe, 0x3, 0xe0, 0xfd, 0xde, 0xa1, 0x12, 0x6, + 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, + 0x0, 0xff, 0xf0, 0x6, 0xff, 0xfe, 0xfd, 0x65, 0x7, 0x0, 0xfe, 0x23, + 0xdc, 0x5, 0xff, 0xfe, 0xea, 0x7, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, + 0xff, 0x60, 0x5, 0x0, 0xff, 0x5f, 0x6, 0xff, 0xfe, 0xc0, 0x16, 0x7, + 0x0, 0xfe, 0x66, 0xfd, 0x5, 0xff, 0xfe, 0xd6, 0x1, 0x4, 0x0, 0xfe, + 0x6, 0xe6, 0x5, 0xff, 0xfe, 0xf6, 0x53, 0x7, 0x0, 0xfb, 0x7, 0x7f, + 0xe5, 0xe9, 0x79, 0x5, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x3, + 0x0, 0xfe, 0x4e, 0xfa, 0x6, 0xff, 0xfe, 0x90, 0x1, 0x7, 0x0, 0xff, + 0xc0, 0x7, 0xff, 0xfe, 0x8e, 0x3, 0x6, 0x0, 0xfe, 0x11, 0xbe, 0x5, + 0xff, 0xfe, 0xfe, 0x21, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, + 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, + 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, + 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, + 0x6, 0xff, 0xff, 0x74, 0x9, 0x0, 0xfe, 0x20, 0xf1, 0x5, 0xff, 0xff, + 0x5c, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, + 0xd5, 0x5, 0xff, 0xfe, 0xcd, 0xa, 0x9, 0x0, 0xff, 0x60, 0x6, 0xff, + 0xff, 0x4c, 0x4, 0x0, 0xff, 0x5c, 0x6, 0xff, 0xff, 0x4b, 0x12, 0x0, + 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xfe, 0x4e, 0xfa, 0x6, + 0xff, 0xff, 0x7f, 0x9, 0x0, 0xff, 0xc0, 0x6, 0xff, 0xff, 0xa3, 0x9, + 0x0, 0xfe, 0xa, 0xd8, 0x5, 0xff, 0xff, 0x8a, 0x4, 0x0, 0xff, 0x20, + 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, + 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, + 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, + 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xfe, 0xc7, 0x2, 0xa, 0x0, 0xff, + 0x68, 0x5, 0xff, 0xff, 0xae, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, + 0x60, 0x4, 0x0, 0xff, 0x2f, 0x5, 0xff, 0xfe, 0xfc, 0x2a, 0xb, 0x0, + 0xff, 0xaf, 0x5, 0xff, 0xff, 0xa7, 0x4, 0x0, 0xff, 0xb0, 0x5, 0xff, + 0xff, 0x9e, 0x13, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x5a, + 0xfa, 0x6, 0xff, 0xff, 0x6e, 0xa, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfe, + 0xea, 0xe, 0xa, 0x0, 0xff, 0x38, 0x5, 0xff, 0xff, 0xda, 0x4, 0x0, + 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, + 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x5, 0xff, 0xff, 0x50, 0xb, 0x0, + 0xfe, 0x7, 0xe9, 0x4, 0xff, 0xff, 0xef, 0x5, 0x0, 0xff, 0x80, 0x5, + 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x79, 0x5, 0xff, 0xff, 0xa6, 0xc, + 0x0, 0xff, 0x2f, 0x5, 0xff, 0xff, 0xef, 0x3, 0x0, 0xfe, 0x1, 0xf2, + 0x5, 0xff, 0xff, 0x27, 0x13, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfd, 0x30, + 0x5b, 0xfd, 0x5, 0xff, 0xfe, 0xfd, 0x5e, 0xb, 0x0, 0xff, 0xc0, 0x5, + 0xff, 0xff, 0x80, 0xc, 0x0, 0xff, 0xc2, 0x5, 0xff, 0xff, 0x1c, 0x3, + 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, + 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, + 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, + 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xfe, 0xf8, 0x8, + 0xc, 0x0, 0xff, 0xa1, 0x5, 0xff, 0xff, 0x1b, 0x4, 0x0, 0xff, 0x80, + 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xa9, 0x5, 0xff, 0xff, 0x4f, + 0xd, 0x0, 0xff, 0xd7, 0x5, 0xff, 0xff, 0x20, 0x2, 0x0, 0xff, 0x20, + 0x5, 0xff, 0xff, 0xd6, 0x14, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfe, 0x8b, + 0xfd, 0x5, 0xff, 0xfe, 0xf9, 0x4f, 0xc, 0x0, 0xff, 0xc0, 0x5, 0xff, + 0xff, 0x30, 0xc, 0x0, 0xff, 0x73, 0x5, 0xff, 0xff, 0x48, 0x3, 0x0, + 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, + 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xca, 0xd, 0x0, + 0xff, 0x6c, 0x5, 0xff, 0xff, 0x39, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, + 0xff, 0x60, 0x4, 0x0, 0xff, 0xcc, 0x5, 0xff, 0xff, 0x18, 0xd, 0x0, + 0xff, 0xa0, 0x5, 0xff, 0xff, 0x43, 0x2, 0x0, 0xff, 0x3f, 0x5, 0xff, + 0xff, 0xa0, 0x14, 0x0, 0xff, 0xa0, 0xc, 0xff, 0xff, 0x48, 0xd, 0x0, + 0xff, 0xc0, 0x4, 0xff, 0xfe, 0xf7, 0x2, 0xc, 0x0, 0xff, 0x3d, 0x5, + 0xff, 0xff, 0x65, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, + 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, + 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, + 0xff, 0xff, 0xb5, 0xd, 0x0, 0xff, 0x57, 0x5, 0xff, 0xff, 0x46, 0x4, + 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xdb, 0x4, + 0xff, 0xff, 0xfd, 0xe, 0x0, 0xff, 0x84, 0x5, 0xff, 0xff, 0x52, 0x2, + 0x0, 0xff, 0x4e, 0x5, 0xff, 0xff, 0x8a, 0x14, 0x0, 0xff, 0xa0, 0xc, + 0xff, 0xfe, 0xab, 0x3, 0xc, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xff, 0xe4, + 0xd, 0x0, 0xff, 0x28, 0x5, 0xff, 0xff, 0x72, 0x3, 0x0, 0xff, 0x20, + 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, + 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, + 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, + 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xb4, 0xd, 0x0, 0xff, 0x56, + 0x5, 0xff, 0xff, 0x47, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, + 0x4, 0x0, 0xff, 0xdd, 0x4, 0xff, 0xff, 0xfb, 0xe, 0x0, 0xff, 0x81, + 0x5, 0xff, 0xff, 0x54, 0x2, 0x0, 0xff, 0x50, 0x5, 0xff, 0xff, 0x87, + 0x14, 0x0, 0xff, 0xa0, 0xd, 0xff, 0xff, 0x95, 0xc, 0x0, 0xff, 0xc0, + 0x4, 0xff, 0xff, 0xe3, 0xd, 0x0, 0xff, 0x27, 0x5, 0xff, 0xff, 0x73, + 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, + 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, + 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, + 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, + 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xc8, + 0xd, 0x0, 0xff, 0x6a, 0x5, 0xff, 0xff, 0x3b, 0x4, 0x0, 0xff, 0x80, + 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0xcf, 0x5, 0xff, 0xff, 0x10, + 0xd, 0x0, 0xff, 0x9a, 0x5, 0xff, 0xff, 0x46, 0x2, 0x0, 0xff, 0x40, + 0x5, 0xff, 0xff, 0x9c, 0x14, 0x0, 0xff, 0xa0, 0xe, 0xff, 0xff, 0x7f, + 0xb, 0x0, 0xff, 0xc0, 0x4, 0xff, 0xfe, 0xf6, 0x1, 0xc, 0x0, 0xff, + 0x3b, 0x5, 0xff, 0xff, 0x67, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, + 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf1, + 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, + 0xe5, 0xe7, 0xa2, 0x19, 0x0, 0xf0, 0x15, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, + 0xff, 0xf0, 0x4, 0xff, 0xfe, 0xf6, 0x6, 0xc, 0x0, 0xff, 0x9e, 0x5, + 0xff, 0xff, 0x1f, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, + 0x0, 0xff, 0xb0, 0x5, 0xff, 0xff, 0x44, 0xd, 0x0, 0xff, 0xcc, 0x5, + 0xff, 0xff, 0x27, 0x2, 0x0, 0xff, 0x25, 0x5, 0xff, 0xff, 0xd0, 0x14, + 0x0, 0xff, 0xa0, 0x7, 0xff, 0xff, 0xfc, 0x7, 0xff, 0xff, 0x65, 0xa, + 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x2b, 0xc, 0x0, 0xff, 0x70, 0x5, + 0xff, 0xff, 0x4b, 0x3, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, + 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xf0, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, + 0xe5, 0x3b, 0x17, 0x0, 0xef, 0xc, 0x9c, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0xe, 0x0, + 0xff, 0xf0, 0x5, 0xff, 0xff, 0x49, 0xb, 0x0, 0xfe, 0x6, 0xe6, 0x4, + 0xff, 0xfe, 0xf4, 0x1, 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, + 0x4, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x99, 0xc, 0x0, 0xff, 0x21, + 0x5, 0xff, 0xfe, 0xf7, 0x3, 0x2, 0x0, 0xfe, 0x3, 0xf7, 0x4, 0xff, + 0xfe, 0xfe, 0x22, 0x13, 0x0, 0xff, 0xa0, 0x6, 0xff, 0xfd, 0xc9, 0x26, + 0xd3, 0x6, 0xff, 0xfe, 0xfd, 0x52, 0x9, 0x0, 0xff, 0xc0, 0x5, 0xff, + 0xff, 0x78, 0xc, 0x0, 0xff, 0xbd, 0x5, 0xff, 0xff, 0x22, 0x3, 0x0, + 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, + 0xff, 0xf0, 0xc, 0x0, 0xf2, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x2, 0xe9, 0xfe, 0x8d, 0x13, + 0x13, 0x0, 0xed, 0x2, 0x53, 0xc9, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x63, 0xe, 0x0, + 0xff, 0xf0, 0x5, 0xff, 0xff, 0xbe, 0xb, 0x0, 0xff, 0x60, 0x5, 0xff, + 0xff, 0xb4, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x4, 0x0, + 0xff, 0x3c, 0x5, 0xff, 0xfe, 0xf7, 0x1d, 0xb, 0x0, 0xff, 0x9d, 0x5, + 0xff, 0xff, 0xb3, 0x4, 0x0, 0xff, 0xba, 0x5, 0xff, 0xff, 0x9a, 0x13, + 0x0, 0xff, 0xa0, 0x5, 0xff, 0xfb, 0xbd, 0xc, 0x0, 0x1b, 0xdc, 0x6, + 0xff, 0xfe, 0xf8, 0x3f, 0x8, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xfe, 0xe4, + 0xa, 0xa, 0x0, 0xff, 0x32, 0x5, 0xff, 0xff, 0xe2, 0x4, 0x0, 0xff, + 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xf0, 0x4, 0xff, 0xff, + 0xf0, 0xc, 0x0, 0xec, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, + 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xe0, 0x66, 0x4, + 0x10, 0x0, 0xec, 0x31, 0xad, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, + 0x0, 0xff, 0xf0, 0x6, 0xff, 0xff, 0x65, 0x9, 0x0, 0xfe, 0x19, 0xed, + 0x5, 0xff, 0xff, 0x69, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, + 0x4, 0x0, 0xfe, 0x2, 0xe4, 0x5, 0xff, 0xfe, 0xbd, 0x3, 0x9, 0x0, + 0xfe, 0x4a, 0xfe, 0x5, 0xff, 0xff, 0x5d, 0x4, 0x0, 0xff, 0x6b, 0x6, + 0xff, 0xff, 0x48, 0x12, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x3, + 0x0, 0xfe, 0x24, 0xe5, 0x6, 0xff, 0xfe, 0xf1, 0x2f, 0x7, 0x0, 0xff, + 0xc0, 0x6, 0xff, 0xff, 0x94, 0x9, 0x0, 0xfe, 0x7, 0xd0, 0x5, 0xff, + 0xff, 0x94, 0x4, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, + 0xff, 0xf0, 0x4, 0xff, 0xff, 0xf0, 0xc, 0x0, 0xeb, 0xcc, 0xce, 0xd0, + 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xc9, 0x3e, 0xd, 0x0, 0xea, 0x16, 0x8a, 0xd7, + 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, + 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x6, + 0xff, 0xfe, 0xfa, 0x4e, 0x7, 0x0, 0xfe, 0x18, 0xd3, 0x5, 0xff, 0xfe, + 0xf3, 0xd, 0x5, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, + 0xff, 0x72, 0x6, 0xff, 0xfe, 0xab, 0xc, 0x7, 0x0, 0xfe, 0x4a, 0xf6, + 0x5, 0xff, 0xfe, 0xe2, 0x6, 0x4, 0x0, 0xfe, 0xe, 0xf4, 0x5, 0xff, + 0xfe, 0xf1, 0x43, 0x8, 0x0, 0xfc, 0x28, 0x92, 0x9c, 0x4a, 0x5, 0x0, + 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0x2d, 0xec, 0x6, + 0xff, 0xfe, 0xe7, 0x22, 0x6, 0x0, 0xff, 0xc0, 0x7, 0xff, 0xff, 0x75, + 0x7, 0x0, 0xfe, 0x9, 0xb2, 0x6, 0xff, 0xff, 0x2d, 0x4, 0x0, 0xff, + 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, 0xff, 0xe7, 0x4, 0xff, 0xfe, + 0xfa, 0x3, 0xb, 0x0, 0xe9, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, + 0xf3, 0xf5, 0xa6, 0x1e, 0x9, 0x0, 0xe8, 0x7, 0x66, 0xcb, 0xd5, 0xd7, + 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, + 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x8, + 0xff, 0xfe, 0x9a, 0x30, 0x3, 0x0, 0xfd, 0x14, 0x6b, 0xea, 0x6, 0xff, + 0xff, 0x82, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x5, 0x0, + 0xfe, 0xa, 0xde, 0x6, 0xff, 0xfd, 0xde, 0x61, 0xd, 0x3, 0x0, 0xfe, + 0x33, 0xa1, 0x7, 0xff, 0xff, 0x5f, 0x6, 0x0, 0xff, 0x83, 0x6, 0xff, + 0xfd, 0xfe, 0x9f, 0x32, 0x4, 0x0, 0xfd, 0x1a, 0x84, 0xfa, 0x3, 0xff, + 0xff, 0x50, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, + 0xfe, 0x37, 0xf3, 0x6, 0xff, 0xfe, 0xdc, 0x15, 0x5, 0x0, 0xff, 0xc0, + 0x8, 0xff, 0xfd, 0xb5, 0x3f, 0x3, 0x2, 0x0, 0xfd, 0xc, 0x59, 0xd8, + 0x6, 0xff, 0xff, 0xb0, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, + 0x8, 0x0, 0xff, 0xd6, 0x5, 0xff, 0xfa, 0x82, 0xf, 0x21, 0x5c, 0x4f, + 0x1, 0x6, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, + 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xf7, 0xf1, 0x7e, 0x6, 0x6, 0x0, 0xe7, 0x3f, 0xb5, 0xd1, 0xd3, + 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, + 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, + 0xf0, 0xa, 0xff, 0xfc, 0xed, 0xd4, 0xe2, 0xfd, 0x7, 0xff, 0xfe, 0xdf, + 0xb, 0x6, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x6, 0x0, 0xfe, + 0x40, 0xfd, 0x7, 0xff, 0xfc, 0xfd, 0xdd, 0xd4, 0xef, 0x8, 0xff, 0xff, + 0xb4, 0x7, 0x0, 0xfe, 0xb, 0xde, 0x8, 0xff, 0xfc, 0xef, 0xd6, 0xd9, + 0xec, 0x6, 0xff, 0xff, 0xb1, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, + 0x30, 0x6, 0x0, 0xfe, 0x42, 0xf9, 0x6, 0xff, 0xff, 0xbf, 0x5, 0x0, + 0xff, 0xc0, 0xa, 0xff, 0xfc, 0xf3, 0xd7, 0xdc, 0xfa, 0x7, 0xff, 0xfe, + 0xf4, 0x22, 0x5, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, 0x0, + 0xff, 0xbb, 0xa, 0xff, 0xff, 0x74, 0x6, 0x0, 0xe7, 0xcc, 0xce, 0xd0, + 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9d, 0x5, 0x0, + 0xe6, 0x12, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, + 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, + 0xfa, 0xfc, 0x5a, 0xe, 0x0, 0xff, 0xf0, 0x14, 0xff, 0xfe, 0xfa, 0x36, + 0x7, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x60, 0x7, 0x0, 0xff, 0x6b, + 0x12, 0xff, 0xfe, 0xd2, 0xf, 0x8, 0x0, 0xfe, 0x31, 0xf6, 0x11, 0xff, + 0xff, 0xb4, 0x4, 0x0, 0xff, 0xa0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, + 0xfe, 0x4f, 0xfd, 0x6, 0xff, 0xff, 0x2e, 0x4, 0x0, 0xff, 0xc0, 0x15, + 0xff, 0xff, 0x5a, 0x6, 0x0, 0xff, 0x20, 0x5, 0xff, 0xff, 0xc0, 0x8, + 0x0, 0xff, 0x7b, 0xa, 0xff, 0xff, 0xc5, 0x6, 0x0, 0xe7, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xf6, 0x5, + 0x0, 0xe6, 0x2b, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, + 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, + 0xf8, 0xfa, 0xfc, 0x58, 0xe, 0x0, 0xff, 0xed, 0x4, 0xff, 0xfe, 0xf3, + 0xdc, 0xd, 0xff, 0xfe, 0xfa, 0x4e, 0x8, 0x0, 0xff, 0x70, 0x5, 0xff, + 0xff, 0x55, 0x8, 0x0, 0xfe, 0x69, 0xfd, 0xf, 0xff, 0xfe, 0xc5, 0x14, + 0xa, 0x0, 0xfe, 0x42, 0xf1, 0xf, 0xff, 0xfe, 0xfd, 0x48, 0x4, 0x0, + 0xff, 0x9b, 0x5, 0xff, 0xff, 0x29, 0x8, 0x0, 0xff, 0x5e, 0x6, 0xff, + 0xff, 0x3c, 0x4, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0xcc, 0xe, 0xff, + 0xff, 0x69, 0x7, 0x0, 0xff, 0x13, 0x5, 0xff, 0xff, 0xb1, 0x8, 0x0, + 0xfe, 0x1e, 0xf6, 0x9, 0xff, 0xff, 0xc1, 0x6, 0x0, 0xe7, 0xa3, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, + 0x0, 0xe6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, + 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, + 0xf8, 0xfa, 0xfc, 0x34, 0xe, 0x0, 0xff, 0xcd, 0x4, 0xff, 0xfd, 0xca, + 0x14, 0xb2, 0xb, 0xff, 0xfe, 0xdf, 0x36, 0x9, 0x0, 0xfe, 0x2e, 0xfd, + 0x3, 0xff, 0xfe, 0xf5, 0x17, 0x9, 0x0, 0xfe, 0x38, 0xd7, 0xc, 0xff, + 0xfd, 0xfa, 0x82, 0x7, 0xc, 0x0, 0xfe, 0x27, 0xcd, 0xd, 0xff, 0xfe, + 0xea, 0x4e, 0x5, 0x0, 0xff, 0x54, 0x4, 0xff, 0xfe, 0xe1, 0x3, 0x9, + 0x0, 0xff, 0x6e, 0x4, 0xff, 0xfe, 0xe4, 0x9, 0x4, 0x0, 0xff, 0xc0, + 0x5, 0xff, 0xfd, 0x17, 0x91, 0xfe, 0xa, 0xff, 0xfe, 0xef, 0x51, 0x9, + 0x0, 0xff, 0xcc, 0x4, 0xff, 0xff, 0x6c, 0x9, 0x0, 0xfe, 0x52, 0xf3, + 0x7, 0xff, 0xfe, 0xf9, 0x43, 0x6, 0x0, 0xe7, 0x1c, 0xa1, 0xd0, 0xd2, + 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, + 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe7, + 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xed, + 0x6f, 0xf, 0x0, 0xfe, 0x55, 0xfe, 0x2, 0xff, 0xfe, 0xfd, 0x4d, 0x2, + 0x0, 0xfe, 0x4a, 0xc6, 0x7, 0xff, 0xfd, 0xe7, 0x7a, 0x9, 0xb, 0x0, + 0xfb, 0x66, 0xf4, 0xff, 0xe9, 0x4b, 0xb, 0x0, 0xfd, 0x4, 0x60, 0xcd, + 0x8, 0xff, 0xfd, 0xee, 0x95, 0x1e, 0xf, 0x0, 0xfd, 0x2, 0x60, 0xd0, + 0x9, 0xff, 0xfd, 0xcb, 0x6e, 0xc, 0x7, 0x0, 0xfb, 0x8b, 0xfc, 0xff, + 0xe0, 0x35, 0xb, 0x0, 0xfb, 0x6d, 0xf3, 0xff, 0xce, 0x2a, 0x5, 0x0, + 0xff, 0xc0, 0x5, 0xff, 0xfb, 0x10, 0x0, 0x35, 0xb4, 0xfe, 0x6, 0xff, + 0xfd, 0xf1, 0x90, 0x14, 0xa, 0x0, 0xfa, 0x26, 0xd5, 0xff, 0xfe, 0x9a, + 0x3, 0xa, 0x0, 0xfc, 0x16, 0x82, 0xd2, 0xfc, 0x2, 0xff, 0xfd, 0xf9, + 0xb1, 0x2e, 0x8, 0x0, 0xe8, 0x1, 0x4c, 0xbd, 0xd4, 0xd6, 0xd8, 0xda, + 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe8, 0x2d, 0xcd, 0xcf, 0xd1, + 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf4, 0x99, 0x17, 0x11, 0x0, 0xfc, 0x3c, + 0x95, 0x94, 0x3b, 0x5, 0x0, 0xf8, 0x26, 0x69, 0x8f, 0xa0, 0x93, 0x75, + 0x3f, 0x3, 0xe, 0x0, 0xfd, 0x8, 0x1f, 0x3, 0xf, 0x0, 0xf7, 0x21, + 0x59, 0x84, 0x96, 0x9d, 0x8e, 0x6f, 0x3d, 0x5, 0x14, 0x0, 0xf7, 0x25, + 0x5e, 0x8a, 0x99, 0x9c, 0x8c, 0x79, 0x4b, 0x18, 0xb, 0x0, 0xfd, 0xf, + 0x1f, 0x2, 0xd, 0x0, 0xfe, 0x6, 0x11, 0x7, 0x0, 0xff, 0xc0, 0x5, + 0xff, 0xff, 0x10, 0x3, 0x0, 0xf8, 0x1a, 0x5e, 0x8a, 0x9e, 0x95, 0x7d, + 0x49, 0x9, 0xe, 0x0, 0xfe, 0x1c, 0x10, 0xf, 0x0, 0xfc, 0x7, 0x1a, + 0x1f, 0x5, 0xc, 0x0, 0xea, 0xb, 0x72, 0xd2, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, + 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xea, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, + 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xbd, 0x32, 0x7f, 0x0, 0xf, 0x0, 0xff, 0xc0, 0x5, 0xff, + 0xff, 0x10, 0x3c, 0x0, 0xec, 0x1f, 0x99, 0xda, 0xdc, 0xde, 0xe0, 0xe2, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, + 0xfd, 0x5, 0x0, 0xeb, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, + 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xd7, 0x55, + 0x1, 0x7f, 0x0, 0x10, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x3e, + 0x0, 0xee, 0x3f, 0xbc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xed, 0x2d, + 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, + 0xe5, 0xe7, 0xe9, 0xe4, 0x7b, 0xa, 0x7f, 0x0, 0x12, 0x0, 0xff, 0xc0, + 0x5, 0xff, 0xff, 0x10, 0x3f, 0x0, 0xef, 0x5, 0x68, 0xd5, 0xe2, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, + 0x5, 0x0, 0xef, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, + 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0x9d, 0x1e, 0x7f, 0x0, 0x14, 0x0, + 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x41, 0x0, 0xf1, 0x16, 0x90, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, + 0x5, 0x0, 0xf1, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, + 0xdd, 0xdf, 0xe1, 0xe3, 0xbd, 0x3b, 0x7f, 0x0, 0x16, 0x0, 0xff, 0xc0, + 0x5, 0xff, 0xff, 0x10, 0x43, 0x0, 0xf3, 0x33, 0xb8, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf2, 0x2d, + 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xd1, 0x5d, + 0x4, 0x7f, 0x0, 0x17, 0x0, 0xff, 0xc0, 0x5, 0xff, 0xff, 0x10, 0x44, + 0x0, 0xf4, 0x2, 0x5b, 0xd8, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, + 0xfb, 0xfd, 0x5, 0x0, 0xf4, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, + 0xd9, 0xdb, 0xda, 0x81, 0x10, 0x7f, 0x0, 0x19, 0x0, 0xff, 0xae, 0x4, + 0xff, 0xfe, 0xfd, 0x9, 0x46, 0x0, 0xf6, 0xe, 0x85, 0xec, 0xf1, 0xf3, + 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf6, 0x2d, 0xcd, 0xcf, 0xd1, + 0xd3, 0xd5, 0xd7, 0xd9, 0xa1, 0x25, 0x7f, 0x0, 0x1b, 0x0, 0xff, 0x53, + 0x4, 0xff, 0xff, 0xa7, 0x49, 0x0, 0xf8, 0x27, 0xb0, 0xf3, 0xf5, 0xf7, + 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf8, 0x31, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, + 0xbb, 0x44, 0x7f, 0x0, 0x1e, 0x0, 0xfb, 0x63, 0xd2, 0xdd, 0x95, 0xb, + 0x4b, 0x0, 0xfa, 0x4d, 0xd6, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf9, + 0x32, 0xcd, 0xcf, 0xd1, 0xc9, 0x65, 0x6, 0x7f, 0x0, 0x70, 0x0, 0xfb, + 0x8, 0x78, 0xf0, 0xfb, 0xfd, 0x5, 0x0, 0xfb, 0x32, 0xcd, 0xcf, 0x85, + 0x16, 0x7f, 0x0, 0x74, 0x0, 0xfd, 0x1c, 0xa5, 0xe7, 0x5, 0x0, 0xfd, + 0x26, 0x9d, 0x2d, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x60, 0x0}; static const Image blockpit_logo_image = {256, 64, 5567, blockpit_logo_data}; const VariantAnimation blockpit_logo = { @@ -51,8 +512,7 @@ const VariantAnimation blockpit_logo = { {0, 0, 25, 90, &blockpit_logo_image}, {0, 0, 25, 95, &blockpit_logo_image}, {0, 0, 25, 100, &blockpit_logo_image}, - } -}; + }}; const VariantAnimation blockpit_logo_reversed = { 21, { @@ -77,14 +537,206 @@ const VariantAnimation blockpit_logo_reversed = { {0, 0, 25, 10, &blockpit_logo_image}, {0, 0, 25, 5, &blockpit_logo_image}, {0, 0, 25, 0, &blockpit_logo_image}, - } -}; + }}; -const uint8_t blockpit_screensaver_data[2339] = -{ - 0x57, 0x0, 0xfa, 0x19, 0x94, 0xe2, 0xd0, 0x5e, 0x2, 0x34, 0x0, 0xf7, 0x8, 0x6f, 0xdb, 0xe4, 0xe5, 0xe6, 0xe7, 0xbb, 0x34, 0x32, 0x0, 0xf4, 0x49, 0xc5, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x95, 0x17, 0x2e, 0x0, 0xf0, 0x28, 0xa7, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xdf, 0x6b, 0x5, 0x2a, 0x0, 0xed, 0x10, 0x81, 0xda, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xc8, 0x40, 0x27, 0x0, 0xe9, 0x3, 0x5c, 0xcc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xa3, 0x1e, 0x24, 0x0, 0xe6, 0x39, 0xb4, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xe8, 0x78, 0x9, 0x20, 0x0, 0xe3, 0x1c, 0x94, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xd4, 0x4d, 0x1d, 0x0, 0xdf, 0x9, 0x70, 0xd0, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xb2, 0x26, 0x19, 0x0, 0xdb, 0x1, 0x4c, 0xbe, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf1, 0x86, 0xe, 0x16, 0x0, 0xd8, 0x2b, 0xa3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xe0, 0x5a, 0x1, 0x12, 0x0, 0xd5, 0x13, 0x81, 0xd0, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xc1, 0x30, 0xf, 0x0, 0xd1, 0x5, 0x5f, 0xc4, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xf9, 0x96, 0x13, 0xc, 0x0, 0xcf, 0x1e, 0xaf, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xec, 0x69, 0xb, 0x0, 0xce, 0x3b, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xa, 0xb, 0x0, 0xd0, 0x30, 0xa7, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xd6, 0x49, 0xd, 0x0, 0xd2, 0x2, 0x55, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xed, 0x71, 0x5, 0x10, 0x0, 0xda, 0xf, 0x7d, 0xd1, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xd9, 0x6e, 0x20, 0x3c, 0xb6, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0x2, 0xf7, 0xfe, 0x98, 0x16, 0x14, 0x0, 0xef, 0x28, 0xa3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0x90, 0x18, 0x3, 0x0, 0xee, 0x2, 0x59, 0xd6, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xbe, 0x31, 0xd, 0x0, 0xfd, 0xc7, 0x96, 0x22, 0x7, 0x0, 0xf2, 0x1, 0x4d, 0xc1, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xb1, 0x31, 0x7, 0x0, 0xf1, 0xe, 0x85, 0xe8, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xdb, 0x56, 0x1, 0x7, 0x0, 0xfd, 0x3a, 0xc9, 0x61, 0x4, 0x0, 0xfb, 0xcc, 0xce, 0xcd, 0x76, 0xc, 0x7, 0x0, 0xf5, 0xc, 0x75, 0xd4, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xc9, 0x54, 0x2, 0xa, 0x0, 0xf5, 0x29, 0xb1, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xeb, 0x7d, 0xa, 0x7, 0x0, 0xfb, 0x1b, 0xa2, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf9, 0xcc, 0xce, 0xd0, 0xd2, 0xc3, 0x53, 0x2, 0x7, 0x0, 0xf9, 0x22, 0x9d, 0xd9, 0xda, 0xd7, 0x76, 0xb, 0xe, 0x0, 0xf9, 0x51, 0xd4, 0xef, 0xf0, 0xf1, 0xa3, 0x1e, 0x7, 0x0, 0xf9, 0x9, 0x77, 0xeb, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf8, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xac, 0x31, 0x8, 0x0, 0xfd, 0x1a, 0x29, 0xe, 0x11, 0x0, 0xfc, 0x5, 0x33, 0x40, 0x1b, 0x8, 0x0, 0xf8, 0x4f, 0xd4, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf6, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0x8b, 0x16, 0x24, 0x0, 0xf6, 0x2a, 0xb2, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf4, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xd4, 0x68, 0x5, 0x20, 0x0, 0xf4, 0x11, 0x8a, 0xe9, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf3, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xc1, 0x42, 0x1d, 0x0, 0xf2, 0x4, 0x63, 0xd9, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0x9e, 0x6, 0x1a, 0x0, 0xf1, 0x22, 0xbe, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x66, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x66, 0x1a, 0x0, 0xf1, 0xa9, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x90, 0x1a, 0x0, 0xf1, 0xd2, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xa2, 0x19, 0x0, 0xf0, 0x15, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf0, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe5, 0x3b, 0x17, 0x0, 0xef, 0xc, 0x9c, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf2, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x2, 0xe9, 0xfe, 0x8d, 0x13, 0x13, 0x0, 0xed, 0x2, 0x53, 0xc9, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x63, 0x4, 0x0, 0xec, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xe0, 0x66, 0x4, 0x10, 0x0, 0xec, 0x31, 0xad, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xeb, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xc9, 0x3e, 0xd, 0x0, 0xea, 0x16, 0x8a, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xe9, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xa6, 0x1e, 0x9, 0x0, 0xe8, 0x7, 0x66, 0xcb, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf1, 0x7e, 0x6, 0x6, 0x0, 0xe7, 0x3f, 0xb5, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9d, 0x5, 0x0, 0xe6, 0x12, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xf6, 0x5, 0x0, 0xe6, 0x2b, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x58, 0x4, 0x0, 0xe7, 0xa3, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x34, 0x4, 0x0, 0xe7, 0x1c, 0xa1, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe7, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xed, 0x6f, 0x6, 0x0, 0xe8, 0x1, 0x4c, 0xbd, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe8, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf4, 0x99, 0x17, 0x9, 0x0, 0xea, 0xb, 0x72, 0xd2, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xea, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xbd, 0x32, 0xd, 0x0, 0xec, 0x1f, 0x99, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xeb, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xd7, 0x55, 0x1, 0x10, 0x0, 0xee, 0x3f, 0xbc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xed, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xe4, 0x7b, 0xa, 0x13, 0x0, 0xef, 0x5, 0x68, 0xd5, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xef, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0x9d, 0x1e, 0x17, 0x0, 0xf1, 0x16, 0x90, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf1, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xbd, 0x3b, 0x1b, 0x0, 0xf3, 0x33, 0xb8, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf2, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xd1, 0x5d, 0x4, 0x1d, 0x0, 0xf4, 0x2, 0x5b, 0xd8, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf4, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xda, 0x81, 0x10, 0x21, 0x0, 0xf6, 0xe, 0x85, 0xec, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xa1, 0x25, 0x25, 0x0, 0xf8, 0x27, 0xb0, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf8, 0x31, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xbb, 0x44, 0x29, 0x0, 0xfa, 0x4d, 0xd6, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf9, 0x32, 0xcd, 0xcf, 0xd1, 0xc9, 0x65, 0x6, 0x2b, 0x0, 0xfb, 0x8, 0x78, 0xf0, 0xfb, 0xfd, 0x5, 0x0, 0xfb, 0x32, 0xcd, 0xcf, 0x85, 0x16, 0x2f, 0x0, 0xfd, 0x1c, 0xa5, 0xe7, 0x5, 0x0, 0xfd, 0x26, 0x9d, 0x2d, 0x55, 0x0 -}; -static const Image blockpit_screensaver_image = {60, 64, 2339, blockpit_screensaver_data}; +const uint8_t blockpit_screensaver_data[2339] = { + 0x57, 0x0, 0xfa, 0x19, 0x94, 0xe2, 0xd0, 0x5e, 0x2, 0x34, 0x0, 0xf7, + 0x8, 0x6f, 0xdb, 0xe4, 0xe5, 0xe6, 0xe7, 0xbb, 0x34, 0x32, 0x0, 0xf4, + 0x49, 0xc5, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x95, 0x17, + 0x2e, 0x0, 0xf0, 0x28, 0xa7, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xdf, 0x6b, 0x5, 0x2a, 0x0, 0xed, 0x10, 0x81, + 0xda, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xc8, 0x40, 0x27, 0x0, 0xe9, 0x3, 0x5c, 0xcc, 0xdc, + 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xa3, 0x1e, 0x24, 0x0, 0xe6, 0x39, 0xb4, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xe8, 0x78, 0x9, + 0x20, 0x0, 0xe3, 0x1c, 0x94, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xd4, 0x4d, 0x1d, 0x0, 0xdf, 0x9, + 0x70, 0xd0, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, + 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xb2, 0x26, 0x19, 0x0, 0xdb, 0x1, + 0x4c, 0xbe, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf1, 0x86, 0xe, + 0x16, 0x0, 0xd8, 0x2b, 0xa3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xe0, 0x5a, 0x1, 0x12, 0x0, 0xd5, 0x13, 0x81, + 0xd0, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, + 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xc1, 0x30, 0xf, 0x0, 0xd1, 0x5, 0x5f, 0xc4, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, + 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xfa, 0xf9, 0x96, 0x13, 0xc, 0x0, 0xcf, 0x1e, 0xaf, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xec, 0x69, 0xb, + 0x0, 0xce, 0x3b, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, + 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xa, 0xb, 0x0, 0xd0, 0x30, 0xa7, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, + 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xd6, 0x49, 0xd, 0x0, 0xd2, 0x2, 0x55, + 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, 0xfa, 0xed, 0x71, 0x5, 0x10, 0x0, 0xda, 0xf, + 0x7d, 0xd1, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, + 0xdd, 0xde, 0xdf, 0xe0, 0xe2, 0xd9, 0x6e, 0x20, 0x3c, 0xb6, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0x2, 0xf7, 0xfe, 0x98, 0x16, 0x14, 0x0, 0xef, 0x28, 0xa3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0x90, 0x18, 0x3, 0x0, 0xee, 0x2, 0x59, 0xd6, 0xea, 0xeb, 0xec, 0xed, + 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xbe, 0x31, 0xd, + 0x0, 0xfd, 0xc7, 0x96, 0x22, 0x7, 0x0, 0xf2, 0x1, 0x4d, 0xc1, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xb1, 0x31, 0x7, 0x0, + 0xf1, 0xe, 0x85, 0xe8, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xdb, 0x56, 0x1, 0x7, 0x0, 0xfd, 0x3a, 0xc9, 0x61, 0x4, 0x0, + 0xfb, 0xcc, 0xce, 0xcd, 0x76, 0xc, 0x7, 0x0, 0xf5, 0xc, 0x75, 0xd4, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xc9, 0x54, 0x2, 0xa, 0x0, 0xf5, 0x29, + 0xb1, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xeb, 0x7d, 0xa, 0x7, 0x0, + 0xfb, 0x1b, 0xa2, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf9, 0xcc, 0xce, 0xd0, + 0xd2, 0xc3, 0x53, 0x2, 0x7, 0x0, 0xf9, 0x22, 0x9d, 0xd9, 0xda, 0xd7, + 0x76, 0xb, 0xe, 0x0, 0xf9, 0x51, 0xd4, 0xef, 0xf0, 0xf1, 0xa3, 0x1e, + 0x7, 0x0, 0xf9, 0x9, 0x77, 0xeb, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, + 0xf8, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xac, 0x31, 0x8, 0x0, 0xfd, + 0x1a, 0x29, 0xe, 0x11, 0x0, 0xfc, 0x5, 0x33, 0x40, 0x1b, 0x8, 0x0, + 0xf8, 0x4f, 0xd4, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf6, + 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0x8b, 0x16, 0x24, 0x0, + 0xf6, 0x2a, 0xb2, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, + 0x0, 0xf4, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xd4, + 0x68, 0x5, 0x20, 0x0, 0xf4, 0x11, 0x8a, 0xe9, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xf8, 0xfa, 0xfc, 0x6d, 0x4, 0x0, 0xf3, 0xcc, 0xce, 0xd0, 0xd2, + 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xc1, 0x42, 0x1d, 0x0, 0xf2, + 0x4, 0x63, 0xd9, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x6d, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0x9e, 0x6, 0x1a, 0x0, 0xf1, 0x22, + 0xbe, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x66, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x66, 0x1a, 0x0, 0xf1, 0xa9, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x90, 0x1a, 0x0, 0xf1, 0xd2, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x92, 0x1a, 0x0, 0xf1, 0xd4, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x64, 0x4, 0x0, 0xf1, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xa2, 0x19, 0x0, 0xf0, 0x15, + 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, + 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf0, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe5, 0x3b, 0x17, 0x0, + 0xef, 0xc, 0x9c, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, + 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x64, 0x4, 0x0, 0xf2, 0xcc, 0xce, 0xd0, + 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0x2, + 0xe9, 0xfe, 0x8d, 0x13, 0x13, 0x0, 0xed, 0x2, 0x53, 0xc9, 0xdf, 0xe1, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x63, 0x4, 0x0, 0xec, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xe0, 0x66, + 0x4, 0x10, 0x0, 0xec, 0x31, 0xad, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, + 0x4, 0x0, 0xeb, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, + 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xc9, 0x3e, + 0xd, 0x0, 0xea, 0x16, 0x8a, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, + 0x5a, 0x4, 0x0, 0xe9, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, + 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xa6, 0x1e, 0x9, 0x0, 0xe8, 0x7, 0x66, 0xcb, 0xd5, 0xd7, 0xd9, + 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, + 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, 0x0, 0xe7, 0xcc, 0xce, 0xd0, + 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, + 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf1, 0x7e, 0x6, 0x6, 0x0, + 0xe7, 0x3f, 0xb5, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, + 0xfc, 0x5a, 0x4, 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, + 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0x9d, 0x5, 0x0, 0xe6, 0x12, 0xcd, 0xcf, + 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x5a, 0x4, + 0x0, 0xe7, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, + 0xf9, 0xfb, 0xf6, 0x5, 0x0, 0xe6, 0x2b, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, + 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xfa, 0xfc, 0x58, 0x4, 0x0, 0xe7, 0xa3, + 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, + 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, + 0x5, 0x0, 0xe6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, + 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xf8, 0xfa, 0xfc, 0x34, 0x4, 0x0, 0xe7, 0x1c, 0xa1, 0xd0, 0xd2, + 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, + 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe7, + 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, + 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf8, 0xed, + 0x6f, 0x6, 0x0, 0xe8, 0x1, 0x4c, 0xbd, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, + 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, + 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xe8, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, + 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, + 0xed, 0xef, 0xf1, 0xf3, 0xf4, 0x99, 0x17, 0x9, 0x0, 0xea, 0xb, 0x72, + 0xd2, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xea, 0x2d, + 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xbd, 0x32, 0xd, 0x0, 0xec, + 0x1f, 0x99, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, + 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xeb, 0x2d, + 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xd7, 0x55, 0x1, 0x10, 0x0, 0xee, 0x3f, + 0xbc, 0xde, 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, + 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xed, 0x2d, 0xcd, 0xcf, 0xd1, + 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, + 0xe4, 0x7b, 0xa, 0x13, 0x0, 0xef, 0x5, 0x68, 0xd5, 0xe2, 0xe5, 0xe7, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, + 0x0, 0xef, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, + 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0x9d, 0x1e, 0x17, 0x0, 0xf1, 0x16, 0x90, + 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, + 0xfd, 0x5, 0x0, 0xf1, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, + 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xbd, 0x3b, 0x1b, 0x0, 0xf3, 0x33, 0xb8, + 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, + 0x0, 0xf2, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, + 0xdf, 0xd1, 0x5d, 0x4, 0x1d, 0x0, 0xf4, 0x2, 0x5b, 0xd8, 0xed, 0xef, + 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf4, 0x2d, 0xcd, + 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xda, 0x81, 0x10, 0x21, 0x0, + 0xf6, 0xe, 0x85, 0xec, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, + 0x0, 0xf6, 0x2d, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xa1, 0x25, + 0x25, 0x0, 0xf8, 0x27, 0xb0, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, + 0x0, 0xf8, 0x31, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xbb, 0x44, 0x29, 0x0, + 0xfa, 0x4d, 0xd6, 0xf7, 0xf9, 0xfb, 0xfd, 0x5, 0x0, 0xf9, 0x32, 0xcd, + 0xcf, 0xd1, 0xc9, 0x65, 0x6, 0x2b, 0x0, 0xfb, 0x8, 0x78, 0xf0, 0xfb, + 0xfd, 0x5, 0x0, 0xfb, 0x32, 0xcd, 0xcf, 0x85, 0x16, 0x2f, 0x0, 0xfd, + 0x1c, 0xa5, 0xe7, 0x5, 0x0, 0xfd, 0x26, 0x9d, 0x2d, 0x55, 0x0}; +static const Image blockpit_screensaver_image = {60, 64, 2339, + blockpit_screensaver_data}; const VariantAnimation blockpit_screensaver = { 392, @@ -481,8 +1133,7 @@ const VariantAnimation blockpit_screensaver = { {96, 0, 125, 100, &blockpit_screensaver_image}, {97, 0, 125, 100, &blockpit_screensaver_image}, {98, 0, 125, 100, &blockpit_screensaver_image}, - } -}; + }}; VariantInfo blockpit_svi __attribute__((section("variant_info"))) = { .version = 1, @@ -490,5 +1141,4 @@ VariantInfo blockpit_svi __attribute__((section("variant_info"))) = { .logo = &blockpit_logo, .logo_reversed = &blockpit_logo_reversed, .screensaver_timeout = ONE_SEC * 60 * 10, - .screensaver = &blockpit_screensaver -}; + .screensaver = &blockpit_screensaver}; diff --git a/tools/variant/dash.c b/tools/variant/dash.c index 79f4d677c..a28ef2e69 100644 --- a/tools/variant/dash.c +++ b/tools/variant/dash.c @@ -21,71 +21,519 @@ #include "keepkey/board/timer.h" - -const uint8_t dash_logo_data[2863] = -{ - 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x3b, 0x0, 0xfd, 0x27, 0xba, 0xf1, 0x16, 0xe6, 0xf5, 0xe3, 0xde, 0xd4, 0xc7, 0xad, 0x8a, 0x64, 0x39, 0x18, 0x9, 0x1, 0x6c, 0x0, 0xfd, 0x5, 0x96, 0xed, 0x8, 0xe6, 0xfc, 0xe7, 0xf2, 0xb7, 0x1f, 0x61, 0x0, 0xfe, 0x49, 0xe0, 0x1e, 0xff, 0xfa, 0xfb, 0xd9, 0x9e, 0x58, 0x1b, 0x4, 0x6a, 0x0, 0xfe, 0x8, 0xcc, 0xb, 0xff, 0xfe, 0xbd, 0x18, 0x61, 0x0, 0xfe, 0x67, 0xf3, 0x21, 0xff, 0xfb, 0xfd, 0xd2, 0x7d, 0x23, 0x5, 0x68, 0x0, 0xfe, 0x1b, 0xec, 0xa, 0xff, 0xfd, 0xfe, 0x9d, 0x8, 0x61, 0x0, 0xff, 0x8c, 0x25, 0xff, 0xfc, 0xdf, 0x7c, 0x19, 0x1, 0x65, 0x0, 0xfd, 0x1, 0x46, 0xfd, 0xa, 0xff, 0xfe, 0xf4, 0x78, 0x61, 0x0, 0xfe, 0xa, 0xaa, 0x27, 0xff, 0xfe, 0xb1, 0x25, 0x65, 0x0, 0xfe, 0x2, 0x6f, 0xb, 0xff, 0xfe, 0xe9, 0x5b, 0x61, 0x0, 0xfe, 0x23, 0xc1, 0x28, 0xff, 0xfd, 0xb1, 0x23, 0x1, 0x63, 0x0, 0xfe, 0x3, 0x98, 0xb, 0xff, 0xfe, 0xda, 0x3e, 0x61, 0x0, 0xfe, 0x37, 0xd1, 0x29, 0xff, 0xfe, 0xae, 0x20, 0x63, 0x0, 0xfe, 0x6, 0xc2, 0xb, 0xff, 0xfe, 0xc1, 0x20, 0x61, 0x0, 0xfe, 0x47, 0xde, 0x2a, 0xff, 0xfe, 0x8e, 0x9, 0x62, 0x0, 0xfe, 0x1c, 0xe0, 0xb, 0xff, 0xfe, 0xa3, 0x5, 0x61, 0x0, 0xfe, 0x5e, 0xf0, 0x2a, 0xff, 0xfe, 0xd7, 0x37, 0x62, 0x0, 0xfe, 0x3f, 0xed, 0xa, 0xff, 0xfe, 0xfb, 0x89, 0x61, 0x0, 0xfe, 0x1, 0x83, 0x2c, 0xff, 0xfe, 0x84, 0x7, 0x61, 0x0, 0xfe, 0x66, 0xf9, 0xa, 0xff, 0xfe, 0xef, 0x69, 0x61, 0x0, 0xfc, 0x8, 0x78, 0xc6, 0xc4, 0x4, 0xc2, 0x6, 0xc3, 0x7, 0xc4, 0x2, 0xc5, 0xfa, 0xc9, 0xd0, 0xda, 0xe8, 0xf0, 0xfa, 0x11, 0xff, 0xfe, 0xd8, 0x31, 0x60, 0x0, 0xfe, 0x1, 0x83, 0xb, 0xff, 0xfe, 0xdf, 0x46, 0x61, 0x0, 0xfc, 0x3, 0x10, 0x17, 0x16, 0x3, 0x15, 0xff, 0x16, 0x7, 0x17, 0x6, 0x18, 0x2, 0x1a, 0xf8, 0x20, 0x28, 0x37, 0x4e, 0x6d, 0x99, 0xcb, 0xec, 0x10, 0xff, 0xfe, 0x63, 0x1, 0x60, 0x0, 0xff, 0x93, 0xb, 0xff, 0xfe, 0xcb, 0x24, 0x7e, 0x0, 0xfc, 0x22, 0x5d, 0xb9, 0xf0, 0xe, 0xff, 0xfe, 0x9a, 0x11, 0x5f, 0x0, 0xfe, 0x3, 0xae, 0xb, 0xff, 0xff, 0xae, 0x7f, 0x0, 0x2, 0x0, 0xfd, 0xf, 0x75, 0xea, 0xd, 0xff, 0xfe, 0xcb, 0x28, 0x13, 0x0, 0xfa, 0x6, 0x14, 0x20, 0x28, 0x2f, 0x35, 0x14, 0x39, 0xfd, 0x3a, 0x3b, 0x11, 0xd, 0x0, 0xfb, 0x6, 0x19, 0x25, 0x2e, 0x35, 0x14, 0x37, 0xfd, 0x3e, 0x21, 0x3, 0x6, 0x0, 0xfe, 0x17, 0xcb, 0xb, 0xff, 0xfd, 0xac, 0x2f, 0x37, 0x7, 0x39, 0xfa, 0x38, 0x32, 0x2c, 0x26, 0x1b, 0xc, 0x74, 0x0, 0xfe, 0x6d, 0xf2, 0xc, 0xff, 0xfe, 0xe9, 0x36, 0x10, 0x0, 0xf7, 0xa, 0x26, 0x4b, 0x76, 0xa0, 0xc3, 0xdb, 0xeb, 0xf3, 0x14, 0xf6, 0xfc, 0xfa, 0xf5, 0x42, 0x1, 0xa, 0x0, 0xf9, 0x12, 0x3d, 0x76, 0xad, 0xd1, 0xea, 0xf4, 0x13, 0xf5, 0xfc, 0xf4, 0xff, 0x81, 0xa, 0x6, 0x0, 0xfe, 0x34, 0xe3, 0xa, 0xff, 0xfd, 0xfe, 0xf7, 0xf2, 0x8, 0xf6, 0xf7, 0xf5, 0xf1, 0xe6, 0xd5, 0xb5, 0x88, 0x5a, 0x29, 0x7, 0x71, 0x0, 0xfe, 0x10, 0xa8, 0xc, 0xff, 0xfe, 0xfa, 0x45, 0xe, 0x0, 0xfc, 0x1b, 0x45, 0x84, 0xc6, 0x1c, 0xff, 0xfe, 0xe2, 0x30, 0x9, 0x0, 0xfc, 0xb, 0x43, 0x99, 0xe8, 0x1a, 0xff, 0xfe, 0x66, 0x5, 0x6, 0x0, 0xfe, 0x51, 0xf8, 0x1c, 0xff, 0xfc, 0xcd, 0x76, 0x2d, 0x2, 0x70, 0x0, 0xfe, 0x5d, 0xf5, 0xc, 0xff, 0xff, 0x59, 0xc, 0x0, 0xfc, 0x15, 0x59, 0xad, 0xe7, 0x1e, 0xff, 0xfe, 0xb4, 0x18, 0x8, 0x0, 0xfd, 0x1d, 0x84, 0xe5, 0x1b, 0xff, 0xfe, 0xf7, 0x40, 0x7, 0x0, 0xff, 0x77, 0x1f, 0xff, 0xfd, 0xd1, 0x5a, 0x4, 0x6f, 0x0, 0xfe, 0x29, 0xcb, 0xc, 0xff, 0xff, 0x61, 0xb, 0x0, 0xfd, 0x27, 0x9c, 0xf5, 0x20, 0xff, 0xfe, 0x9e, 0xf, 0x7, 0x0, 0xfe, 0x19, 0xa9, 0x1d, 0xff, 0xfe, 0xd1, 0x2a, 0x6, 0x0, 0xfd, 0x3, 0x9c, 0xfe, 0x1f, 0xff, 0xfd, 0xec, 0x50, 0x1, 0x6e, 0x0, 0xfe, 0x1a, 0xad, 0xc, 0xff, 0xff, 0x61, 0xa, 0x0, 0xfe, 0x36, 0xc1, 0x22, 0xff, 0xfe, 0x8d, 0xd, 0x6, 0x0, 0xfe, 0x7, 0x92, 0x1e, 0xff, 0xfe, 0xaf, 0x18, 0x6, 0x0, 0xfd, 0x12, 0xbb, 0xfe, 0x20, 0xff, 0xfd, 0xd6, 0x2b, 0x1, 0x6d, 0x0, 0xfe, 0x11, 0x9a, 0xc, 0xff, 0xff, 0x5f, 0x9, 0x0, 0xfe, 0x55, 0xd6, 0x23, 0xff, 0xfe, 0x73, 0x8, 0x6, 0x0, 0xfe, 0x65, 0xf7, 0x1e, 0xff, 0xfe, 0x8a, 0xc, 0x6, 0x0, 0xfe, 0x26, 0xde, 0x22, 0xff, 0xfe, 0x8b, 0xb, 0x40, 0x0, 0xfc, 0x11, 0x35, 0x57, 0x65, 0x16, 0x68, 0xfd, 0x6e, 0x4b, 0x7, 0x10, 0x0, 0xfe, 0xf, 0x92, 0xc, 0xff, 0xff, 0x56, 0x8, 0x0, 0xfe, 0x43, 0xec, 0x23, 0xff, 0xfd, 0xfa, 0x55, 0x3, 0x5, 0x0, 0xfe, 0x24, 0xe6, 0x1f, 0xff, 0xfe, 0x67, 0x4, 0x6, 0x0, 0xfe, 0x3f, 0xf8, 0x22, 0xff, 0xfd, 0xdc, 0x2b, 0x1, 0x3e, 0x0, 0xfb, 0x40, 0x9a, 0xd2, 0xef, 0xf9, 0x16, 0xfb, 0xfd, 0xff, 0xa8, 0xd, 0x10, 0x0, 0xfe, 0x10, 0x96, 0xb, 0xff, 0xfe, 0xfc, 0x48, 0x7, 0x0, 0xfe, 0x21, 0xcd, 0x24, 0xff, 0xfe, 0xe3, 0x38, 0x6, 0x0, 0xff, 0x8e, 0x1f, 0xff, 0xfd, 0xfa, 0x4d, 0x1, 0x6, 0x0, 0xfe, 0x61, 0xfc, 0x22, 0xff, 0xfd, 0xfc, 0x50, 0x3, 0x3c, 0x0, 0xfd, 0x2, 0x54, 0xda, 0x1b, 0xff, 0xfe, 0x89, 0x7, 0x10, 0x0, 0xfe, 0x16, 0xa5, 0xb, 0xff, 0xfe, 0xee, 0x39, 0x6, 0x0, 0xfe, 0x13, 0xa9, 0x11, 0xff, 0xfd, 0xf3, 0xe8, 0xe6, 0x3, 0xe7, 0xfd, 0xe3, 0xea, 0xfa, 0xb, 0xff, 0xfe, 0xc8, 0x1f, 0x5, 0x0, 0xfe, 0x20, 0xe8, 0xc, 0xff, 0xfe, 0xed, 0xe5, 0xf, 0xe7, 0xfc, 0xe6, 0xee, 0xc4, 0x2c, 0x6, 0x0, 0xfd, 0x1, 0x8b, 0xfc, 0x23, 0xff, 0xfe, 0x5e, 0x3, 0x3b, 0x0, 0xfd, 0x1, 0x31, 0xdf, 0x1c, 0xff, 0xfe, 0x53, 0x3, 0x10, 0x0, 0xfe, 0x22, 0xbc, 0xb, 0xff, 0xfe, 0xd9, 0x2e, 0x6, 0x0, 0xfe, 0x79, 0xfe, 0xd, 0xff, 0xf9, 0xf9, 0xcd, 0x9f, 0x79, 0x63, 0x55, 0x52, 0x3, 0x53, 0xfd, 0x4d, 0x7a, 0xe6, 0xb, 0xff, 0xfe, 0xa5, 0x11, 0x5, 0x0, 0xfe, 0x65, 0xfd, 0xa, 0xff, 0xfc, 0xec, 0x92, 0x59, 0x51, 0xf, 0x53, 0xfc, 0x52, 0x5c, 0x40, 0x8, 0x6, 0x0, 0xfd, 0x8, 0xb7, 0xfd, 0xa, 0xff, 0xfc, 0xe3, 0x90, 0x86, 0x8d, 0x2, 0x8c, 0xfb, 0x8b, 0x8e, 0x9c, 0xb9, 0xec, 0xe, 0xff, 0xfe, 0x61, 0x5, 0x3b, 0x0, 0xfe, 0xa, 0x8c, 0x1c, 0xff, 0xfd, 0xec, 0x31, 0x1, 0x10, 0x0, 0xfe, 0x31, 0xd3, 0xb, 0xff, 0xfe, 0xc0, 0x23, 0x5, 0x0, 0xfe, 0x25, 0xd9, 0xd, 0xff, 0xfc, 0xc8, 0x6a, 0x32, 0x2, 0x8, 0x0, 0xfe, 0x41, 0xea, 0xb, 0xff, 0xfe, 0x85, 0xc, 0x5, 0x0, 0xfe, 0x8e, 0xfc, 0x9, 0xff, 0xfe, 0xf7, 0x8f, 0x1c, 0x0, 0xfe, 0x12, 0xdc, 0xa, 0xff, 0xfe, 0xfd, 0xa9, 0x8, 0x0, 0xfd, 0x1b, 0x5c, 0xd1, 0xd, 0xff, 0xfe, 0x63, 0x5, 0x3b, 0x0, 0xfe, 0x24, 0xd8, 0x1c, 0xff, 0xfe, 0xbb, 0x16, 0x11, 0x0, 0xfe, 0x4e, 0xed, 0xb, 0xff, 0xfe, 0xa1, 0x14, 0x5, 0x0, 0xfe, 0x75, 0xf8, 0xb, 0xff, 0xfd, 0xf6, 0x98, 0x2f, 0xb, 0x0, 0xfe, 0x6c, 0xfe, 0xa, 0xff, 0xfd, 0xfc, 0x63, 0x5, 0x5, 0x0, 0xfe, 0xb4, 0xfe, 0x9, 0xff, 0xfe, 0xe0, 0x3e, 0x1c, 0x0, 0xfe, 0x2f, 0xf3, 0xa, 0xff, 0xfe, 0xf5, 0x83, 0xa, 0x0, 0xfe, 0x48, 0xdd, 0xc, 0xff, 0xfe, 0x63, 0x5, 0x3a, 0x0, 0xfd, 0x3, 0x53, 0xfa, 0x1c, 0xff, 0xfe, 0x82, 0x6, 0x10, 0x0, 0xfe, 0x3, 0x75, 0xc, 0xff, 0xfe, 0x7c, 0x4, 0x4, 0x0, 0xfd, 0x11, 0xc7, 0xfe, 0xa, 0xff, 0xfd, 0xf5, 0x79, 0xd, 0xb, 0x0, 0xfe, 0x7, 0x90, 0xb, 0xff, 0xfe, 0xef, 0x3b, 0x5, 0x0, 0xfe, 0x11, 0xd3, 0xa, 0xff, 0xfe, 0xd8, 0x29, 0x1c, 0x0, 0xfe, 0x5c, 0xfa, 0xa, 0xff, 0xfe, 0xed, 0x5d, 0xb, 0x0, 0xff, 0x8a, 0xc, 0xff, 0xfe, 0x61, 0x4, 0x3a, 0x0, 0xfe, 0xa, 0x82, 0x1c, 0xff, 0xfd, 0xf4, 0x3c, 0x1, 0x10, 0x0, 0xfe, 0xe, 0x96, 0xc, 0xff, 0xff, 0x59, 0x5, 0x0, 0xfe, 0x52, 0xf1, 0xa, 0xff, 0xfd, 0xfd, 0xa9, 0x5, 0xc, 0x0, 0xfe, 0x1c, 0xb0, 0xb, 0xff, 0xfe, 0xd8, 0x22, 0x5, 0x0, 0xfe, 0x2a, 0xdd, 0xa, 0xff, 0xfc, 0xec, 0x6e, 0x5, 0x0, 0x9, 0x1, 0x11, 0x0, 0xfe, 0x80, 0xfb, 0xa, 0xff, 0xfe, 0xe5, 0x3d, 0xb, 0x0, 0xfe, 0x65, 0xf8, 0xb, 0xff, 0xfe, 0x5d, 0x4, 0x3a, 0x0, 0xfe, 0x11, 0xab, 0x1c, 0xff, 0xfe, 0x99, 0xb, 0x11, 0x0, 0xfe, 0x18, 0xaa, 0xb, 0xff, 0xfe, 0xe7, 0x3d, 0x5, 0x0, 0xfe, 0xa2, 0xfb, 0xa, 0xff, 0xfe, 0xed, 0x3f, 0xd, 0x0, 0xfe, 0x2d, 0xc7, 0xb, 0xff, 0xfe, 0xba, 0x19, 0x5, 0x0, 0xfe, 0x33, 0xe1, 0xb, 0xff, 0xfd, 0xe2, 0xa5, 0x9b, 0x8, 0x9f, 0xfa, 0x9e, 0x99, 0x89, 0x6b, 0x3f, 0x17, 0xc, 0x0, 0xfe, 0x98, 0xfb, 0xa, 0xff, 0xfe, 0xd4, 0x23, 0xb, 0x0, 0xfe, 0x64, 0xf4, 0xb, 0xff, 0xfe, 0x58, 0x4, 0x3a, 0x0, 0xfe, 0x2f, 0xde, 0x1b, 0xff, 0xfe, 0xb5, 0x24, 0x12, 0x0, 0xfe, 0x2f, 0xd1, 0xb, 0xff, 0xfe, 0xb8, 0x21, 0x4, 0x0, 0xfe, 0x1b, 0xda, 0xa, 0xff, 0xfd, 0xfd, 0xa3, 0x5, 0xd, 0x0, 0xfe, 0x39, 0xd6, 0xb, 0xff, 0xfe, 0x91, 0xf, 0x5, 0x0, 0xfe, 0x2e, 0xdf, 0x19, 0xff, 0xfb, 0xf8, 0xd9, 0xb9, 0x79, 0x10, 0xa, 0x0, 0xfe, 0xb1, 0xfd, 0x9, 0xff, 0xfd, 0xfd, 0xb3, 0xb, 0xb, 0x0, 0xfe, 0x78, 0xfc, 0xa, 0xff, 0xfd, 0xf7, 0x49, 0x2, 0x39, 0x0, 0xfe, 0x2, 0x58, 0x19, 0xff, 0xfc, 0xf4, 0xce, 0x89, 0x25, 0x13, 0x0, 0xfe, 0x56, 0xf9, 0xb, 0xff, 0xfe, 0x89, 0x8, 0x4, 0x0, 0xfe, 0x58, 0xee, 0xa, 0xff, 0xfe, 0xf2, 0x4f, 0xe, 0x0, 0xfe, 0x44, 0xe5, 0xb, 0xff, 0xfe, 0x69, 0x5, 0x5, 0x0, 0xfe, 0x15, 0xd7, 0x1c, 0xff, 0xfd, 0xf8, 0xa4, 0x1e, 0x8, 0x0, 0xfe, 0x6, 0xd3, 0xa, 0xff, 0xfe, 0xf8, 0x92, 0xb, 0x0, 0xfe, 0x2, 0x97, 0xb, 0xff, 0xfe, 0xdd, 0x32, 0x3a, 0x0, 0xfc, 0x2, 0x31, 0x8a, 0x80, 0x16, 0x7f, 0xfc, 0x78, 0x5d, 0x31, 0x9, 0x13, 0x0, 0xfe, 0xb, 0x8e, 0xb, 0xff, 0xfe, 0xf5, 0x5b, 0x5, 0x0, 0xfe, 0x8d, 0xf8, 0xa, 0xff, 0xfe, 0xd3, 0x20, 0xe, 0x0, 0xfe, 0x5b, 0xf4, 0xa, 0xff, 0xfe, 0xfe, 0x44, 0x6, 0x0, 0xfd, 0x2, 0xb9, 0xfe, 0x1d, 0xff, 0xfe, 0xa8, 0x16, 0x7, 0x0, 0xfe, 0x23, 0xeb, 0xa, 0xff, 0xfe, 0xf2, 0x76, 0xb, 0x0, 0xfe, 0x14, 0xb3, 0xb, 0xff, 0xfe, 0xc1, 0x1b, 0x3b, 0x0, 0xfe, 0x2, 0x5, 0x17, 0x4, 0xff, 0x3, 0x16, 0x0, 0xfe, 0x32, 0xe4, 0xb, 0xff, 0xfe, 0xcf, 0x30, 0x5, 0x0, 0xff, 0xb9, 0xa, 0xff, 0xfd, 0xfd, 0xab, 0x4, 0xd, 0x0, 0xfd, 0x5, 0x7e, 0xfd, 0xa, 0xff, 0xfe, 0xe4, 0x29, 0x7, 0x0, 0xff, 0x7e, 0x1e, 0xff, 0xfd, 0xfd, 0x70, 0x9, 0x6, 0x0, 0xfe, 0x50, 0xf4, 0xa, 0xff, 0xfe, 0xed, 0x5c, 0xb, 0x0, 0xfe, 0x33, 0xce, 0xb, 0xff, 0xfe, 0x9e, 0xe, 0x6a, 0x0, 0xfe, 0x9, 0x82, 0xc, 0xff, 0xfe, 0xac, 0x18, 0x4, 0x0, 0xfe, 0x18, 0xd1, 0xa, 0xff, 0xfe, 0xfb, 0x87, 0xe, 0x0, 0xfe, 0x11, 0x9f, 0xb, 0xff, 0xfe, 0xc7, 0x1f, 0x7, 0x0, 0xfe, 0x26, 0xe9, 0x1e, 0xff, 0xfe, 0xbe, 0x1b, 0x6, 0x0, 0xfe, 0x7c, 0xf9, 0xa, 0xff, 0xfe, 0xea, 0x4b, 0xb, 0x0, 0xfe, 0x4f, 0xe8, 0xb, 0xff, 0xfe, 0x7b, 0x9, 0x6a, 0x0, 0xfe, 0x32, 0xe7, 0xc, 0xff, 0xfe, 0x79, 0x5, 0x4, 0x0, 0xfe, 0x36, 0xdb, 0xa, 0xff, 0xfe, 0xf8, 0x6b, 0xe, 0x0, 0xfe, 0x20, 0xb8, 0xb, 0xff, 0xfe, 0xb6, 0x1a, 0x8, 0x0, 0xfe, 0x67, 0xfc, 0x1d, 0xff, 0xfe, 0xe8, 0x3a, 0x6, 0x0, 0xfe, 0xa3, 0xfc, 0xa, 0xff, 0xfe, 0xdb, 0x38, 0xb, 0x0, 0xfe, 0x68, 0xfc, 0xa, 0xff, 0xfd, 0xfb, 0x5e, 0x4, 0x69, 0x0, 0xfe, 0xe, 0xa4, 0xc, 0xff, 0xfe, 0xda, 0x38, 0x5, 0x0, 0xfe, 0x49, 0xe3, 0xa, 0xff, 0xfe, 0xf3, 0x5a, 0xe, 0x0, 0xfe, 0x35, 0xd3, 0xb, 0xff, 0xfe, 0x9b, 0x12, 0x8, 0x0, 0xfd, 0x7, 0x6a, 0xd9, 0x1c, 0xff, 0xfd, 0xfd, 0x62, 0x5, 0x4, 0x0, 0xfd, 0x5, 0xc5, 0xfe, 0xa, 0xff, 0xfe, 0xc2, 0x14, 0xa, 0x0, 0xfe, 0x1, 0x8a, 0xb, 0xff, 0xfd, 0xea, 0x39, 0x1, 0x68, 0x0, 0xfd, 0x3, 0x85, 0xf7, 0xc, 0xff, 0xfe, 0x88, 0x7, 0x5, 0x0, 0xfe, 0x52, 0xe7, 0xa, 0xff, 0xfe, 0xf3, 0x58, 0xe, 0x0, 0xfe, 0x51, 0xe9, 0xb, 0xff, 0xfe, 0x75, 0x6, 0x9, 0x0, 0xfc, 0x4, 0x38, 0x93, 0xda, 0x1b, 0xff, 0xfe, 0x78, 0xa, 0x4, 0x0, 0xfe, 0x25, 0xdb, 0xa, 0xff, 0xfd, 0xfc, 0xa6, 0x1, 0xa, 0x0, 0xfe, 0x16, 0xac, 0xb, 0xff, 0xfe, 0xd2, 0x1e, 0x68, 0x0, 0xfd, 0xb, 0x89, 0xf1, 0xc, 0xff, 0xfe, 0xe2, 0x3f, 0x6, 0x0, 0xfe, 0x54, 0xe9, 0xa, 0xff, 0xfe, 0xf8, 0x6a, 0xe, 0x0, 0xfe, 0x6f, 0xfc, 0xb, 0xff, 0xff, 0x4f, 0xc, 0x0, 0xfa, 0x10, 0x32, 0x5c, 0x82, 0x97, 0xa1, 0x8, 0xa2, 0xfd, 0x9f, 0xa3, 0xd8, 0xc, 0xff, 0xfe, 0x7c, 0xa, 0x4, 0x0, 0xfe, 0x49, 0xeb, 0xa, 0xff, 0xfe, 0xf7, 0x89, 0xb, 0x0, 0xfe, 0x2e, 0xc8, 0xb, 0xff, 0xfe, 0xb3, 0x15, 0x66, 0x0, 0xfc, 0x2, 0x38, 0xa2, 0xf5, 0xd, 0xff, 0xfe, 0x8b, 0x8, 0x6, 0x0, 0xfe, 0x54, 0xe8, 0xa, 0xff, 0xfe, 0xfc, 0x9a, 0xd, 0x0, 0xfe, 0x8, 0x8d, 0xb, 0xff, 0xfe, 0xef, 0x36, 0xf, 0x0, 0xfd, 0xa, 0x11, 0x14, 0x8, 0x15, 0xfc, 0x14, 0x15, 0x42, 0xcb, 0xb, 0xff, 0xfe, 0x73, 0x8, 0x4, 0x0, 0xfe, 0x6d, 0xf5, 0xa, 0xff, 0xfe, 0xf0, 0x67, 0xb, 0x0, 0xfe, 0x3e, 0xd9, 0xb, 0xff, 0xfe, 0x90, 0xe, 0x64, 0x0, 0xfb, 0x14, 0x4c, 0xa2, 0xdf, 0xfb, 0xd, 0xff, 0xfe, 0xd7, 0x37, 0x7, 0x0, 0xfe, 0x50, 0xe7, 0xb, 0xff, 0xfe, 0xdf, 0x33, 0xc, 0x0, 0xfe, 0x18, 0xab, 0xb, 0xff, 0xfe, 0xc7, 0x23, 0x1c, 0x0, 0xfe, 0x4, 0x98, 0xa, 0xff, 0xfd, 0xfa, 0x5d, 0x2, 0x4, 0x0, 0xfe, 0x95, 0xfa, 0xa, 0xff, 0xfe, 0xe1, 0x3c, 0xb, 0x0, 0xfe, 0x4b, 0xe7, 0xb, 0xff, 0xfe, 0x66, 0x6, 0x5e, 0x0, 0xf7, 0x4, 0xf, 0x23, 0x3d, 0x5e, 0x8c, 0xba, 0xe7, 0xfc, 0xf, 0xff, 0xfe, 0x7e, 0x5, 0x7, 0x0, 0xfe, 0x46, 0xe2, 0xb, 0xff, 0xfd, 0xfd, 0xb9, 0x14, 0xb, 0x0, 0xfe, 0x2b, 0xc5, 0xb, 0xff, 0xfe, 0xa2, 0x15, 0x1c, 0x0, 0xfe, 0x12, 0xa8, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0x4, 0x0, 0xfd, 0x5, 0xb3, 0xfd, 0xa, 0xff, 0xfe, 0xd2, 0x15, 0xb, 0x0, 0xfe, 0x5c, 0xf6, 0xa, 0xff, 0xfd, 0xf9, 0x3f, 0x1, 0x47, 0x0, 0xfd, 0x24, 0x92, 0xb7, 0x13, 0xae, 0xf9, 0xb1, 0xb6, 0xbd, 0xcb, 0xde, 0xec, 0xf7, 0x11, 0xff, 0xfe, 0xb6, 0x1c, 0x8, 0x0, 0xfe, 0x29, 0xd8, 0xc, 0xff, 0xfc, 0xfa, 0xb5, 0x3f, 0x2, 0x9, 0x0, 0xfe, 0x38, 0xdc, 0xb, 0xff, 0xfe, 0x81, 0x9, 0x1c, 0x0, 0xfe, 0x3f, 0xe1, 0xa, 0xff, 0xfe, 0xcc, 0x24, 0x4, 0x0, 0xfe, 0x1e, 0xcd, 0xb, 0xff, 0xfe, 0xba, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x7b, 0xfe, 0xa, 0xff, 0xfe, 0xe3, 0x25, 0x48, 0x0, 0xfd, 0x4b, 0xea, 0xff, 0x14, 0xfe, 0x16, 0xff, 0xfe, 0xca, 0x2f, 0x9, 0x0, 0xfe, 0x4, 0xba, 0xd, 0xff, 0xf9, 0xfd, 0xe4, 0xca, 0xa9, 0x84, 0x72, 0x6e, 0x3, 0x6f, 0xfc, 0x6d, 0x6b, 0xa1, 0xf8, 0xb, 0xff, 0xfe, 0x5e, 0x1, 0x6, 0x0, 0xfd, 0x2c, 0x71, 0x6f, 0x10, 0x6d, 0xfb, 0x6c, 0x6d, 0x94, 0xda, 0xfd, 0xa, 0xff, 0xfe, 0xa3, 0x15, 0x4, 0x0, 0xfe, 0x3e, 0xea, 0xa, 0xff, 0xfe, 0xf9, 0x93, 0xb, 0x0, 0xfe, 0x12, 0x9f, 0xb, 0xff, 0xfe, 0xbb, 0x19, 0x48, 0x0, 0xfe, 0x68, 0xf8, 0x2a, 0xff, 0xfd, 0xe7, 0x52, 0x1, 0xa, 0x0, 0xfe, 0x7e, 0xf5, 0xf, 0xff, 0xfe, 0xfd, 0xf6, 0x5, 0xf2, 0x2, 0xf1, 0xff, 0xf7, 0xb, 0xff, 0xfe, 0xed, 0x44, 0x7, 0x0, 0xfd, 0x7c, 0xed, 0xf2, 0x12, 0xf1, 0xff, 0xf9, 0xc, 0xff, 0xfe, 0x6f, 0x4, 0x4, 0x0, 0xfe, 0x5c, 0xf3, 0xa, 0xff, 0xfe, 0xf2, 0x6c, 0xb, 0x0, 0xfe, 0x23, 0xbd, 0xb, 0xff, 0xfe, 0x99, 0x10, 0x47, 0x0, 0xfd, 0x9, 0x88, 0xfe, 0x29, 0xff, 0xfd, 0xf4, 0x72, 0x6, 0xb, 0x0, 0xfe, 0x26, 0xe2, 0x24, 0xff, 0xfe, 0xcf, 0x2e, 0x6, 0x0, 0xfd, 0x4, 0xa0, 0xfd, 0x1f, 0xff, 0xfe, 0xe1, 0x31, 0x5, 0x0, 0xfe, 0x73, 0xf6, 0xa, 0xff, 0xfe, 0xec, 0x43, 0xb, 0x0, 0xfe, 0x38, 0xd4, 0xb, 0xff, 0xfe, 0x81, 0xb, 0x47, 0x0, 0xfe, 0x17, 0xa9, 0x29, 0xff, 0xfd, 0xe3, 0x5c, 0x9, 0xc, 0x0, 0xfd, 0x2, 0x7e, 0xf7, 0x23, 0xff, 0xfe, 0xae, 0x1a, 0x6, 0x0, 0xfd, 0x15, 0xc7, 0xfe, 0x1f, 0xff, 0xfe, 0x70, 0x4, 0x5, 0x0, 0xfe, 0x86, 0xf8, 0xa, 0xff, 0xfe, 0xde, 0x19, 0xb, 0x0, 0xfe, 0x51, 0xea, 0xb, 0xff, 0xfe, 0x6a, 0x5, 0x47, 0x0, 0xfe, 0x2a, 0xc7, 0x28, 0xff, 0xfd, 0xd8, 0x44, 0x5, 0xe, 0x0, 0xfd, 0xf, 0xb7, 0xfd, 0x22, 0xff, 0xfe, 0x8d, 0xc, 0x6, 0x0, 0xfe, 0x29, 0xe9, 0x1f, 0xff, 0xfe, 0xac, 0x1a, 0x5, 0x0, 0xfd, 0x3, 0xa1, 0xfb, 0x9, 0xff, 0xfd, 0xfe, 0xc1, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x72, 0xfa, 0xb, 0xff, 0xff, 0x49, 0x48, 0x0, 0xfe, 0x40, 0xdd, 0x27, 0xff, 0xfd, 0xae, 0x2e, 0x2, 0x10, 0x0, 0xfe, 0x41, 0xe7, 0x22, 0xff, 0xfe, 0x71, 0x5, 0x6, 0x0, 0xfe, 0x48, 0xf2, 0x1e, 0xff, 0xfd, 0xd3, 0x36, 0x1, 0x5, 0x0, 0xfd, 0x11, 0xc2, 0xfe, 0x9, 0xff, 0xfe, 0xfa, 0x9c, 0xb, 0x0, 0xfe, 0xb, 0x92, 0xb, 0xff, 0xfe, 0xec, 0x2c, 0x48, 0x0, 0xfe, 0x60, 0xf5, 0x24, 0xff, 0xfb, 0xfd, 0xc8, 0x65, 0xa, 0x1, 0x11, 0x0, 0xfd, 0x3, 0x4c, 0xcd, 0x20, 0xff, 0xfe, 0xf1, 0x53, 0x7, 0x0, 0xfe, 0x66, 0xf5, 0x1d, 0xff, 0xfd, 0xe0, 0x52, 0x2, 0x6, 0x0, 0xfe, 0x26, 0xe1, 0xa, 0xff, 0xfe, 0xf4, 0x71, 0xb, 0x0, 0xfe, 0x19, 0xae, 0xb, 0xff, 0xfe, 0xc7, 0x1e, 0x47, 0x0, 0xfe, 0x4, 0x81, 0x23, 0xff, 0xfb, 0xf9, 0xb7, 0x59, 0x14, 0x4, 0x14, 0x0, 0xfc, 0x2, 0x1a, 0x92, 0xf9, 0x1e, 0xff, 0xfe, 0xd8, 0x32, 0x7, 0x0, 0xfe, 0x7d, 0xf7, 0x1c, 0xff, 0xfd, 0xb4, 0x2d, 0x3, 0x7, 0x0, 0xfe, 0x48, 0xee, 0xa, 0xff, 0xfe, 0xee, 0x4c, 0xb, 0x0, 0xfe, 0x2f, 0xca, 0xb, 0xff, 0xfe, 0x9c, 0x12, 0x47, 0x0, 0xfe, 0x11, 0xa0, 0x20, 0xff, 0xfa, 0xfd, 0xd6, 0x8f, 0x4b, 0x14, 0x2, 0x18, 0x0, 0xfc, 0x5, 0x46, 0xa0, 0xef, 0x1c, 0xff, 0xfe, 0xc3, 0x24, 0x7, 0x0, 0xfe, 0x9a, 0xfa, 0x1a, 0xff, 0xfc, 0xdc, 0x70, 0x15, 0x1, 0x8, 0x0, 0xfe, 0x6f, 0xf4, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0xb, 0x0, 0xfe, 0x49, 0xe2, 0xb, 0xff, 0xfe, 0x78, 0x7, 0x47, 0x0, 0xfc, 0x1e, 0xae, 0xf6, 0xe4, 0x14, 0xe5, 0x2, 0xe4, 0xf4, 0xe2, 0xdf, 0xdb, 0xd3, 0xcb, 0xbc, 0x99, 0x6a, 0x3d, 0x15, 0x6, 0x1, 0x1b, 0x0, 0xf6, 0x1, 0x9, 0x2b, 0x66, 0x9f, 0xc6, 0xd5, 0xe0, 0xe5, 0xe6, 0x13, 0xe7, 0xfc, 0xe8, 0xf6, 0xa0, 0x17, 0x6, 0x0, 0xfc, 0x3, 0xaa, 0xe9, 0xe8, 0x14, 0xe7, 0xf9, 0xe4, 0xdd, 0xd1, 0xa7, 0x57, 0x18, 0x3, 0xa, 0x0, 0xff, 0x84, 0x2, 0xe8, 0x8, 0xe7, 0xfd, 0xea, 0xd1, 0x23, 0xb, 0x0, 0xfc, 0x5c, 0xe4, 0xf0, 0xe6, 0x7, 0xe7, 0xfd, 0xe9, 0xf0, 0x4e, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x2e, 0x0 -}; +const uint8_t dash_logo_data[2863] = { + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x3b, 0x0, 0xfd, 0x27, 0xba, 0xf1, 0x16, 0xe6, 0xf5, 0xe3, 0xde, 0xd4, + 0xc7, 0xad, 0x8a, 0x64, 0x39, 0x18, 0x9, 0x1, 0x6c, 0x0, 0xfd, 0x5, + 0x96, 0xed, 0x8, 0xe6, 0xfc, 0xe7, 0xf2, 0xb7, 0x1f, 0x61, 0x0, 0xfe, + 0x49, 0xe0, 0x1e, 0xff, 0xfa, 0xfb, 0xd9, 0x9e, 0x58, 0x1b, 0x4, 0x6a, + 0x0, 0xfe, 0x8, 0xcc, 0xb, 0xff, 0xfe, 0xbd, 0x18, 0x61, 0x0, 0xfe, + 0x67, 0xf3, 0x21, 0xff, 0xfb, 0xfd, 0xd2, 0x7d, 0x23, 0x5, 0x68, 0x0, + 0xfe, 0x1b, 0xec, 0xa, 0xff, 0xfd, 0xfe, 0x9d, 0x8, 0x61, 0x0, 0xff, + 0x8c, 0x25, 0xff, 0xfc, 0xdf, 0x7c, 0x19, 0x1, 0x65, 0x0, 0xfd, 0x1, + 0x46, 0xfd, 0xa, 0xff, 0xfe, 0xf4, 0x78, 0x61, 0x0, 0xfe, 0xa, 0xaa, + 0x27, 0xff, 0xfe, 0xb1, 0x25, 0x65, 0x0, 0xfe, 0x2, 0x6f, 0xb, 0xff, + 0xfe, 0xe9, 0x5b, 0x61, 0x0, 0xfe, 0x23, 0xc1, 0x28, 0xff, 0xfd, 0xb1, + 0x23, 0x1, 0x63, 0x0, 0xfe, 0x3, 0x98, 0xb, 0xff, 0xfe, 0xda, 0x3e, + 0x61, 0x0, 0xfe, 0x37, 0xd1, 0x29, 0xff, 0xfe, 0xae, 0x20, 0x63, 0x0, + 0xfe, 0x6, 0xc2, 0xb, 0xff, 0xfe, 0xc1, 0x20, 0x61, 0x0, 0xfe, 0x47, + 0xde, 0x2a, 0xff, 0xfe, 0x8e, 0x9, 0x62, 0x0, 0xfe, 0x1c, 0xe0, 0xb, + 0xff, 0xfe, 0xa3, 0x5, 0x61, 0x0, 0xfe, 0x5e, 0xf0, 0x2a, 0xff, 0xfe, + 0xd7, 0x37, 0x62, 0x0, 0xfe, 0x3f, 0xed, 0xa, 0xff, 0xfe, 0xfb, 0x89, + 0x61, 0x0, 0xfe, 0x1, 0x83, 0x2c, 0xff, 0xfe, 0x84, 0x7, 0x61, 0x0, + 0xfe, 0x66, 0xf9, 0xa, 0xff, 0xfe, 0xef, 0x69, 0x61, 0x0, 0xfc, 0x8, + 0x78, 0xc6, 0xc4, 0x4, 0xc2, 0x6, 0xc3, 0x7, 0xc4, 0x2, 0xc5, 0xfa, + 0xc9, 0xd0, 0xda, 0xe8, 0xf0, 0xfa, 0x11, 0xff, 0xfe, 0xd8, 0x31, 0x60, + 0x0, 0xfe, 0x1, 0x83, 0xb, 0xff, 0xfe, 0xdf, 0x46, 0x61, 0x0, 0xfc, + 0x3, 0x10, 0x17, 0x16, 0x3, 0x15, 0xff, 0x16, 0x7, 0x17, 0x6, 0x18, + 0x2, 0x1a, 0xf8, 0x20, 0x28, 0x37, 0x4e, 0x6d, 0x99, 0xcb, 0xec, 0x10, + 0xff, 0xfe, 0x63, 0x1, 0x60, 0x0, 0xff, 0x93, 0xb, 0xff, 0xfe, 0xcb, + 0x24, 0x7e, 0x0, 0xfc, 0x22, 0x5d, 0xb9, 0xf0, 0xe, 0xff, 0xfe, 0x9a, + 0x11, 0x5f, 0x0, 0xfe, 0x3, 0xae, 0xb, 0xff, 0xff, 0xae, 0x7f, 0x0, + 0x2, 0x0, 0xfd, 0xf, 0x75, 0xea, 0xd, 0xff, 0xfe, 0xcb, 0x28, 0x13, + 0x0, 0xfa, 0x6, 0x14, 0x20, 0x28, 0x2f, 0x35, 0x14, 0x39, 0xfd, 0x3a, + 0x3b, 0x11, 0xd, 0x0, 0xfb, 0x6, 0x19, 0x25, 0x2e, 0x35, 0x14, 0x37, + 0xfd, 0x3e, 0x21, 0x3, 0x6, 0x0, 0xfe, 0x17, 0xcb, 0xb, 0xff, 0xfd, + 0xac, 0x2f, 0x37, 0x7, 0x39, 0xfa, 0x38, 0x32, 0x2c, 0x26, 0x1b, 0xc, + 0x74, 0x0, 0xfe, 0x6d, 0xf2, 0xc, 0xff, 0xfe, 0xe9, 0x36, 0x10, 0x0, + 0xf7, 0xa, 0x26, 0x4b, 0x76, 0xa0, 0xc3, 0xdb, 0xeb, 0xf3, 0x14, 0xf6, + 0xfc, 0xfa, 0xf5, 0x42, 0x1, 0xa, 0x0, 0xf9, 0x12, 0x3d, 0x76, 0xad, + 0xd1, 0xea, 0xf4, 0x13, 0xf5, 0xfc, 0xf4, 0xff, 0x81, 0xa, 0x6, 0x0, + 0xfe, 0x34, 0xe3, 0xa, 0xff, 0xfd, 0xfe, 0xf7, 0xf2, 0x8, 0xf6, 0xf7, + 0xf5, 0xf1, 0xe6, 0xd5, 0xb5, 0x88, 0x5a, 0x29, 0x7, 0x71, 0x0, 0xfe, + 0x10, 0xa8, 0xc, 0xff, 0xfe, 0xfa, 0x45, 0xe, 0x0, 0xfc, 0x1b, 0x45, + 0x84, 0xc6, 0x1c, 0xff, 0xfe, 0xe2, 0x30, 0x9, 0x0, 0xfc, 0xb, 0x43, + 0x99, 0xe8, 0x1a, 0xff, 0xfe, 0x66, 0x5, 0x6, 0x0, 0xfe, 0x51, 0xf8, + 0x1c, 0xff, 0xfc, 0xcd, 0x76, 0x2d, 0x2, 0x70, 0x0, 0xfe, 0x5d, 0xf5, + 0xc, 0xff, 0xff, 0x59, 0xc, 0x0, 0xfc, 0x15, 0x59, 0xad, 0xe7, 0x1e, + 0xff, 0xfe, 0xb4, 0x18, 0x8, 0x0, 0xfd, 0x1d, 0x84, 0xe5, 0x1b, 0xff, + 0xfe, 0xf7, 0x40, 0x7, 0x0, 0xff, 0x77, 0x1f, 0xff, 0xfd, 0xd1, 0x5a, + 0x4, 0x6f, 0x0, 0xfe, 0x29, 0xcb, 0xc, 0xff, 0xff, 0x61, 0xb, 0x0, + 0xfd, 0x27, 0x9c, 0xf5, 0x20, 0xff, 0xfe, 0x9e, 0xf, 0x7, 0x0, 0xfe, + 0x19, 0xa9, 0x1d, 0xff, 0xfe, 0xd1, 0x2a, 0x6, 0x0, 0xfd, 0x3, 0x9c, + 0xfe, 0x1f, 0xff, 0xfd, 0xec, 0x50, 0x1, 0x6e, 0x0, 0xfe, 0x1a, 0xad, + 0xc, 0xff, 0xff, 0x61, 0xa, 0x0, 0xfe, 0x36, 0xc1, 0x22, 0xff, 0xfe, + 0x8d, 0xd, 0x6, 0x0, 0xfe, 0x7, 0x92, 0x1e, 0xff, 0xfe, 0xaf, 0x18, + 0x6, 0x0, 0xfd, 0x12, 0xbb, 0xfe, 0x20, 0xff, 0xfd, 0xd6, 0x2b, 0x1, + 0x6d, 0x0, 0xfe, 0x11, 0x9a, 0xc, 0xff, 0xff, 0x5f, 0x9, 0x0, 0xfe, + 0x55, 0xd6, 0x23, 0xff, 0xfe, 0x73, 0x8, 0x6, 0x0, 0xfe, 0x65, 0xf7, + 0x1e, 0xff, 0xfe, 0x8a, 0xc, 0x6, 0x0, 0xfe, 0x26, 0xde, 0x22, 0xff, + 0xfe, 0x8b, 0xb, 0x40, 0x0, 0xfc, 0x11, 0x35, 0x57, 0x65, 0x16, 0x68, + 0xfd, 0x6e, 0x4b, 0x7, 0x10, 0x0, 0xfe, 0xf, 0x92, 0xc, 0xff, 0xff, + 0x56, 0x8, 0x0, 0xfe, 0x43, 0xec, 0x23, 0xff, 0xfd, 0xfa, 0x55, 0x3, + 0x5, 0x0, 0xfe, 0x24, 0xe6, 0x1f, 0xff, 0xfe, 0x67, 0x4, 0x6, 0x0, + 0xfe, 0x3f, 0xf8, 0x22, 0xff, 0xfd, 0xdc, 0x2b, 0x1, 0x3e, 0x0, 0xfb, + 0x40, 0x9a, 0xd2, 0xef, 0xf9, 0x16, 0xfb, 0xfd, 0xff, 0xa8, 0xd, 0x10, + 0x0, 0xfe, 0x10, 0x96, 0xb, 0xff, 0xfe, 0xfc, 0x48, 0x7, 0x0, 0xfe, + 0x21, 0xcd, 0x24, 0xff, 0xfe, 0xe3, 0x38, 0x6, 0x0, 0xff, 0x8e, 0x1f, + 0xff, 0xfd, 0xfa, 0x4d, 0x1, 0x6, 0x0, 0xfe, 0x61, 0xfc, 0x22, 0xff, + 0xfd, 0xfc, 0x50, 0x3, 0x3c, 0x0, 0xfd, 0x2, 0x54, 0xda, 0x1b, 0xff, + 0xfe, 0x89, 0x7, 0x10, 0x0, 0xfe, 0x16, 0xa5, 0xb, 0xff, 0xfe, 0xee, + 0x39, 0x6, 0x0, 0xfe, 0x13, 0xa9, 0x11, 0xff, 0xfd, 0xf3, 0xe8, 0xe6, + 0x3, 0xe7, 0xfd, 0xe3, 0xea, 0xfa, 0xb, 0xff, 0xfe, 0xc8, 0x1f, 0x5, + 0x0, 0xfe, 0x20, 0xe8, 0xc, 0xff, 0xfe, 0xed, 0xe5, 0xf, 0xe7, 0xfc, + 0xe6, 0xee, 0xc4, 0x2c, 0x6, 0x0, 0xfd, 0x1, 0x8b, 0xfc, 0x23, 0xff, + 0xfe, 0x5e, 0x3, 0x3b, 0x0, 0xfd, 0x1, 0x31, 0xdf, 0x1c, 0xff, 0xfe, + 0x53, 0x3, 0x10, 0x0, 0xfe, 0x22, 0xbc, 0xb, 0xff, 0xfe, 0xd9, 0x2e, + 0x6, 0x0, 0xfe, 0x79, 0xfe, 0xd, 0xff, 0xf9, 0xf9, 0xcd, 0x9f, 0x79, + 0x63, 0x55, 0x52, 0x3, 0x53, 0xfd, 0x4d, 0x7a, 0xe6, 0xb, 0xff, 0xfe, + 0xa5, 0x11, 0x5, 0x0, 0xfe, 0x65, 0xfd, 0xa, 0xff, 0xfc, 0xec, 0x92, + 0x59, 0x51, 0xf, 0x53, 0xfc, 0x52, 0x5c, 0x40, 0x8, 0x6, 0x0, 0xfd, + 0x8, 0xb7, 0xfd, 0xa, 0xff, 0xfc, 0xe3, 0x90, 0x86, 0x8d, 0x2, 0x8c, + 0xfb, 0x8b, 0x8e, 0x9c, 0xb9, 0xec, 0xe, 0xff, 0xfe, 0x61, 0x5, 0x3b, + 0x0, 0xfe, 0xa, 0x8c, 0x1c, 0xff, 0xfd, 0xec, 0x31, 0x1, 0x10, 0x0, + 0xfe, 0x31, 0xd3, 0xb, 0xff, 0xfe, 0xc0, 0x23, 0x5, 0x0, 0xfe, 0x25, + 0xd9, 0xd, 0xff, 0xfc, 0xc8, 0x6a, 0x32, 0x2, 0x8, 0x0, 0xfe, 0x41, + 0xea, 0xb, 0xff, 0xfe, 0x85, 0xc, 0x5, 0x0, 0xfe, 0x8e, 0xfc, 0x9, + 0xff, 0xfe, 0xf7, 0x8f, 0x1c, 0x0, 0xfe, 0x12, 0xdc, 0xa, 0xff, 0xfe, + 0xfd, 0xa9, 0x8, 0x0, 0xfd, 0x1b, 0x5c, 0xd1, 0xd, 0xff, 0xfe, 0x63, + 0x5, 0x3b, 0x0, 0xfe, 0x24, 0xd8, 0x1c, 0xff, 0xfe, 0xbb, 0x16, 0x11, + 0x0, 0xfe, 0x4e, 0xed, 0xb, 0xff, 0xfe, 0xa1, 0x14, 0x5, 0x0, 0xfe, + 0x75, 0xf8, 0xb, 0xff, 0xfd, 0xf6, 0x98, 0x2f, 0xb, 0x0, 0xfe, 0x6c, + 0xfe, 0xa, 0xff, 0xfd, 0xfc, 0x63, 0x5, 0x5, 0x0, 0xfe, 0xb4, 0xfe, + 0x9, 0xff, 0xfe, 0xe0, 0x3e, 0x1c, 0x0, 0xfe, 0x2f, 0xf3, 0xa, 0xff, + 0xfe, 0xf5, 0x83, 0xa, 0x0, 0xfe, 0x48, 0xdd, 0xc, 0xff, 0xfe, 0x63, + 0x5, 0x3a, 0x0, 0xfd, 0x3, 0x53, 0xfa, 0x1c, 0xff, 0xfe, 0x82, 0x6, + 0x10, 0x0, 0xfe, 0x3, 0x75, 0xc, 0xff, 0xfe, 0x7c, 0x4, 0x4, 0x0, + 0xfd, 0x11, 0xc7, 0xfe, 0xa, 0xff, 0xfd, 0xf5, 0x79, 0xd, 0xb, 0x0, + 0xfe, 0x7, 0x90, 0xb, 0xff, 0xfe, 0xef, 0x3b, 0x5, 0x0, 0xfe, 0x11, + 0xd3, 0xa, 0xff, 0xfe, 0xd8, 0x29, 0x1c, 0x0, 0xfe, 0x5c, 0xfa, 0xa, + 0xff, 0xfe, 0xed, 0x5d, 0xb, 0x0, 0xff, 0x8a, 0xc, 0xff, 0xfe, 0x61, + 0x4, 0x3a, 0x0, 0xfe, 0xa, 0x82, 0x1c, 0xff, 0xfd, 0xf4, 0x3c, 0x1, + 0x10, 0x0, 0xfe, 0xe, 0x96, 0xc, 0xff, 0xff, 0x59, 0x5, 0x0, 0xfe, + 0x52, 0xf1, 0xa, 0xff, 0xfd, 0xfd, 0xa9, 0x5, 0xc, 0x0, 0xfe, 0x1c, + 0xb0, 0xb, 0xff, 0xfe, 0xd8, 0x22, 0x5, 0x0, 0xfe, 0x2a, 0xdd, 0xa, + 0xff, 0xfc, 0xec, 0x6e, 0x5, 0x0, 0x9, 0x1, 0x11, 0x0, 0xfe, 0x80, + 0xfb, 0xa, 0xff, 0xfe, 0xe5, 0x3d, 0xb, 0x0, 0xfe, 0x65, 0xf8, 0xb, + 0xff, 0xfe, 0x5d, 0x4, 0x3a, 0x0, 0xfe, 0x11, 0xab, 0x1c, 0xff, 0xfe, + 0x99, 0xb, 0x11, 0x0, 0xfe, 0x18, 0xaa, 0xb, 0xff, 0xfe, 0xe7, 0x3d, + 0x5, 0x0, 0xfe, 0xa2, 0xfb, 0xa, 0xff, 0xfe, 0xed, 0x3f, 0xd, 0x0, + 0xfe, 0x2d, 0xc7, 0xb, 0xff, 0xfe, 0xba, 0x19, 0x5, 0x0, 0xfe, 0x33, + 0xe1, 0xb, 0xff, 0xfd, 0xe2, 0xa5, 0x9b, 0x8, 0x9f, 0xfa, 0x9e, 0x99, + 0x89, 0x6b, 0x3f, 0x17, 0xc, 0x0, 0xfe, 0x98, 0xfb, 0xa, 0xff, 0xfe, + 0xd4, 0x23, 0xb, 0x0, 0xfe, 0x64, 0xf4, 0xb, 0xff, 0xfe, 0x58, 0x4, + 0x3a, 0x0, 0xfe, 0x2f, 0xde, 0x1b, 0xff, 0xfe, 0xb5, 0x24, 0x12, 0x0, + 0xfe, 0x2f, 0xd1, 0xb, 0xff, 0xfe, 0xb8, 0x21, 0x4, 0x0, 0xfe, 0x1b, + 0xda, 0xa, 0xff, 0xfd, 0xfd, 0xa3, 0x5, 0xd, 0x0, 0xfe, 0x39, 0xd6, + 0xb, 0xff, 0xfe, 0x91, 0xf, 0x5, 0x0, 0xfe, 0x2e, 0xdf, 0x19, 0xff, + 0xfb, 0xf8, 0xd9, 0xb9, 0x79, 0x10, 0xa, 0x0, 0xfe, 0xb1, 0xfd, 0x9, + 0xff, 0xfd, 0xfd, 0xb3, 0xb, 0xb, 0x0, 0xfe, 0x78, 0xfc, 0xa, 0xff, + 0xfd, 0xf7, 0x49, 0x2, 0x39, 0x0, 0xfe, 0x2, 0x58, 0x19, 0xff, 0xfc, + 0xf4, 0xce, 0x89, 0x25, 0x13, 0x0, 0xfe, 0x56, 0xf9, 0xb, 0xff, 0xfe, + 0x89, 0x8, 0x4, 0x0, 0xfe, 0x58, 0xee, 0xa, 0xff, 0xfe, 0xf2, 0x4f, + 0xe, 0x0, 0xfe, 0x44, 0xe5, 0xb, 0xff, 0xfe, 0x69, 0x5, 0x5, 0x0, + 0xfe, 0x15, 0xd7, 0x1c, 0xff, 0xfd, 0xf8, 0xa4, 0x1e, 0x8, 0x0, 0xfe, + 0x6, 0xd3, 0xa, 0xff, 0xfe, 0xf8, 0x92, 0xb, 0x0, 0xfe, 0x2, 0x97, + 0xb, 0xff, 0xfe, 0xdd, 0x32, 0x3a, 0x0, 0xfc, 0x2, 0x31, 0x8a, 0x80, + 0x16, 0x7f, 0xfc, 0x78, 0x5d, 0x31, 0x9, 0x13, 0x0, 0xfe, 0xb, 0x8e, + 0xb, 0xff, 0xfe, 0xf5, 0x5b, 0x5, 0x0, 0xfe, 0x8d, 0xf8, 0xa, 0xff, + 0xfe, 0xd3, 0x20, 0xe, 0x0, 0xfe, 0x5b, 0xf4, 0xa, 0xff, 0xfe, 0xfe, + 0x44, 0x6, 0x0, 0xfd, 0x2, 0xb9, 0xfe, 0x1d, 0xff, 0xfe, 0xa8, 0x16, + 0x7, 0x0, 0xfe, 0x23, 0xeb, 0xa, 0xff, 0xfe, 0xf2, 0x76, 0xb, 0x0, + 0xfe, 0x14, 0xb3, 0xb, 0xff, 0xfe, 0xc1, 0x1b, 0x3b, 0x0, 0xfe, 0x2, + 0x5, 0x17, 0x4, 0xff, 0x3, 0x16, 0x0, 0xfe, 0x32, 0xe4, 0xb, 0xff, + 0xfe, 0xcf, 0x30, 0x5, 0x0, 0xff, 0xb9, 0xa, 0xff, 0xfd, 0xfd, 0xab, + 0x4, 0xd, 0x0, 0xfd, 0x5, 0x7e, 0xfd, 0xa, 0xff, 0xfe, 0xe4, 0x29, + 0x7, 0x0, 0xff, 0x7e, 0x1e, 0xff, 0xfd, 0xfd, 0x70, 0x9, 0x6, 0x0, + 0xfe, 0x50, 0xf4, 0xa, 0xff, 0xfe, 0xed, 0x5c, 0xb, 0x0, 0xfe, 0x33, + 0xce, 0xb, 0xff, 0xfe, 0x9e, 0xe, 0x6a, 0x0, 0xfe, 0x9, 0x82, 0xc, + 0xff, 0xfe, 0xac, 0x18, 0x4, 0x0, 0xfe, 0x18, 0xd1, 0xa, 0xff, 0xfe, + 0xfb, 0x87, 0xe, 0x0, 0xfe, 0x11, 0x9f, 0xb, 0xff, 0xfe, 0xc7, 0x1f, + 0x7, 0x0, 0xfe, 0x26, 0xe9, 0x1e, 0xff, 0xfe, 0xbe, 0x1b, 0x6, 0x0, + 0xfe, 0x7c, 0xf9, 0xa, 0xff, 0xfe, 0xea, 0x4b, 0xb, 0x0, 0xfe, 0x4f, + 0xe8, 0xb, 0xff, 0xfe, 0x7b, 0x9, 0x6a, 0x0, 0xfe, 0x32, 0xe7, 0xc, + 0xff, 0xfe, 0x79, 0x5, 0x4, 0x0, 0xfe, 0x36, 0xdb, 0xa, 0xff, 0xfe, + 0xf8, 0x6b, 0xe, 0x0, 0xfe, 0x20, 0xb8, 0xb, 0xff, 0xfe, 0xb6, 0x1a, + 0x8, 0x0, 0xfe, 0x67, 0xfc, 0x1d, 0xff, 0xfe, 0xe8, 0x3a, 0x6, 0x0, + 0xfe, 0xa3, 0xfc, 0xa, 0xff, 0xfe, 0xdb, 0x38, 0xb, 0x0, 0xfe, 0x68, + 0xfc, 0xa, 0xff, 0xfd, 0xfb, 0x5e, 0x4, 0x69, 0x0, 0xfe, 0xe, 0xa4, + 0xc, 0xff, 0xfe, 0xda, 0x38, 0x5, 0x0, 0xfe, 0x49, 0xe3, 0xa, 0xff, + 0xfe, 0xf3, 0x5a, 0xe, 0x0, 0xfe, 0x35, 0xd3, 0xb, 0xff, 0xfe, 0x9b, + 0x12, 0x8, 0x0, 0xfd, 0x7, 0x6a, 0xd9, 0x1c, 0xff, 0xfd, 0xfd, 0x62, + 0x5, 0x4, 0x0, 0xfd, 0x5, 0xc5, 0xfe, 0xa, 0xff, 0xfe, 0xc2, 0x14, + 0xa, 0x0, 0xfe, 0x1, 0x8a, 0xb, 0xff, 0xfd, 0xea, 0x39, 0x1, 0x68, + 0x0, 0xfd, 0x3, 0x85, 0xf7, 0xc, 0xff, 0xfe, 0x88, 0x7, 0x5, 0x0, + 0xfe, 0x52, 0xe7, 0xa, 0xff, 0xfe, 0xf3, 0x58, 0xe, 0x0, 0xfe, 0x51, + 0xe9, 0xb, 0xff, 0xfe, 0x75, 0x6, 0x9, 0x0, 0xfc, 0x4, 0x38, 0x93, + 0xda, 0x1b, 0xff, 0xfe, 0x78, 0xa, 0x4, 0x0, 0xfe, 0x25, 0xdb, 0xa, + 0xff, 0xfd, 0xfc, 0xa6, 0x1, 0xa, 0x0, 0xfe, 0x16, 0xac, 0xb, 0xff, + 0xfe, 0xd2, 0x1e, 0x68, 0x0, 0xfd, 0xb, 0x89, 0xf1, 0xc, 0xff, 0xfe, + 0xe2, 0x3f, 0x6, 0x0, 0xfe, 0x54, 0xe9, 0xa, 0xff, 0xfe, 0xf8, 0x6a, + 0xe, 0x0, 0xfe, 0x6f, 0xfc, 0xb, 0xff, 0xff, 0x4f, 0xc, 0x0, 0xfa, + 0x10, 0x32, 0x5c, 0x82, 0x97, 0xa1, 0x8, 0xa2, 0xfd, 0x9f, 0xa3, 0xd8, + 0xc, 0xff, 0xfe, 0x7c, 0xa, 0x4, 0x0, 0xfe, 0x49, 0xeb, 0xa, 0xff, + 0xfe, 0xf7, 0x89, 0xb, 0x0, 0xfe, 0x2e, 0xc8, 0xb, 0xff, 0xfe, 0xb3, + 0x15, 0x66, 0x0, 0xfc, 0x2, 0x38, 0xa2, 0xf5, 0xd, 0xff, 0xfe, 0x8b, + 0x8, 0x6, 0x0, 0xfe, 0x54, 0xe8, 0xa, 0xff, 0xfe, 0xfc, 0x9a, 0xd, + 0x0, 0xfe, 0x8, 0x8d, 0xb, 0xff, 0xfe, 0xef, 0x36, 0xf, 0x0, 0xfd, + 0xa, 0x11, 0x14, 0x8, 0x15, 0xfc, 0x14, 0x15, 0x42, 0xcb, 0xb, 0xff, + 0xfe, 0x73, 0x8, 0x4, 0x0, 0xfe, 0x6d, 0xf5, 0xa, 0xff, 0xfe, 0xf0, + 0x67, 0xb, 0x0, 0xfe, 0x3e, 0xd9, 0xb, 0xff, 0xfe, 0x90, 0xe, 0x64, + 0x0, 0xfb, 0x14, 0x4c, 0xa2, 0xdf, 0xfb, 0xd, 0xff, 0xfe, 0xd7, 0x37, + 0x7, 0x0, 0xfe, 0x50, 0xe7, 0xb, 0xff, 0xfe, 0xdf, 0x33, 0xc, 0x0, + 0xfe, 0x18, 0xab, 0xb, 0xff, 0xfe, 0xc7, 0x23, 0x1c, 0x0, 0xfe, 0x4, + 0x98, 0xa, 0xff, 0xfd, 0xfa, 0x5d, 0x2, 0x4, 0x0, 0xfe, 0x95, 0xfa, + 0xa, 0xff, 0xfe, 0xe1, 0x3c, 0xb, 0x0, 0xfe, 0x4b, 0xe7, 0xb, 0xff, + 0xfe, 0x66, 0x6, 0x5e, 0x0, 0xf7, 0x4, 0xf, 0x23, 0x3d, 0x5e, 0x8c, + 0xba, 0xe7, 0xfc, 0xf, 0xff, 0xfe, 0x7e, 0x5, 0x7, 0x0, 0xfe, 0x46, + 0xe2, 0xb, 0xff, 0xfd, 0xfd, 0xb9, 0x14, 0xb, 0x0, 0xfe, 0x2b, 0xc5, + 0xb, 0xff, 0xfe, 0xa2, 0x15, 0x1c, 0x0, 0xfe, 0x12, 0xa8, 0xa, 0xff, + 0xfe, 0xec, 0x3a, 0x4, 0x0, 0xfd, 0x5, 0xb3, 0xfd, 0xa, 0xff, 0xfe, + 0xd2, 0x15, 0xb, 0x0, 0xfe, 0x5c, 0xf6, 0xa, 0xff, 0xfd, 0xf9, 0x3f, + 0x1, 0x47, 0x0, 0xfd, 0x24, 0x92, 0xb7, 0x13, 0xae, 0xf9, 0xb1, 0xb6, + 0xbd, 0xcb, 0xde, 0xec, 0xf7, 0x11, 0xff, 0xfe, 0xb6, 0x1c, 0x8, 0x0, + 0xfe, 0x29, 0xd8, 0xc, 0xff, 0xfc, 0xfa, 0xb5, 0x3f, 0x2, 0x9, 0x0, + 0xfe, 0x38, 0xdc, 0xb, 0xff, 0xfe, 0x81, 0x9, 0x1c, 0x0, 0xfe, 0x3f, + 0xe1, 0xa, 0xff, 0xfe, 0xcc, 0x24, 0x4, 0x0, 0xfe, 0x1e, 0xcd, 0xb, + 0xff, 0xfe, 0xba, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x7b, 0xfe, 0xa, 0xff, + 0xfe, 0xe3, 0x25, 0x48, 0x0, 0xfd, 0x4b, 0xea, 0xff, 0x14, 0xfe, 0x16, + 0xff, 0xfe, 0xca, 0x2f, 0x9, 0x0, 0xfe, 0x4, 0xba, 0xd, 0xff, 0xf9, + 0xfd, 0xe4, 0xca, 0xa9, 0x84, 0x72, 0x6e, 0x3, 0x6f, 0xfc, 0x6d, 0x6b, + 0xa1, 0xf8, 0xb, 0xff, 0xfe, 0x5e, 0x1, 0x6, 0x0, 0xfd, 0x2c, 0x71, + 0x6f, 0x10, 0x6d, 0xfb, 0x6c, 0x6d, 0x94, 0xda, 0xfd, 0xa, 0xff, 0xfe, + 0xa3, 0x15, 0x4, 0x0, 0xfe, 0x3e, 0xea, 0xa, 0xff, 0xfe, 0xf9, 0x93, + 0xb, 0x0, 0xfe, 0x12, 0x9f, 0xb, 0xff, 0xfe, 0xbb, 0x19, 0x48, 0x0, + 0xfe, 0x68, 0xf8, 0x2a, 0xff, 0xfd, 0xe7, 0x52, 0x1, 0xa, 0x0, 0xfe, + 0x7e, 0xf5, 0xf, 0xff, 0xfe, 0xfd, 0xf6, 0x5, 0xf2, 0x2, 0xf1, 0xff, + 0xf7, 0xb, 0xff, 0xfe, 0xed, 0x44, 0x7, 0x0, 0xfd, 0x7c, 0xed, 0xf2, + 0x12, 0xf1, 0xff, 0xf9, 0xc, 0xff, 0xfe, 0x6f, 0x4, 0x4, 0x0, 0xfe, + 0x5c, 0xf3, 0xa, 0xff, 0xfe, 0xf2, 0x6c, 0xb, 0x0, 0xfe, 0x23, 0xbd, + 0xb, 0xff, 0xfe, 0x99, 0x10, 0x47, 0x0, 0xfd, 0x9, 0x88, 0xfe, 0x29, + 0xff, 0xfd, 0xf4, 0x72, 0x6, 0xb, 0x0, 0xfe, 0x26, 0xe2, 0x24, 0xff, + 0xfe, 0xcf, 0x2e, 0x6, 0x0, 0xfd, 0x4, 0xa0, 0xfd, 0x1f, 0xff, 0xfe, + 0xe1, 0x31, 0x5, 0x0, 0xfe, 0x73, 0xf6, 0xa, 0xff, 0xfe, 0xec, 0x43, + 0xb, 0x0, 0xfe, 0x38, 0xd4, 0xb, 0xff, 0xfe, 0x81, 0xb, 0x47, 0x0, + 0xfe, 0x17, 0xa9, 0x29, 0xff, 0xfd, 0xe3, 0x5c, 0x9, 0xc, 0x0, 0xfd, + 0x2, 0x7e, 0xf7, 0x23, 0xff, 0xfe, 0xae, 0x1a, 0x6, 0x0, 0xfd, 0x15, + 0xc7, 0xfe, 0x1f, 0xff, 0xfe, 0x70, 0x4, 0x5, 0x0, 0xfe, 0x86, 0xf8, + 0xa, 0xff, 0xfe, 0xde, 0x19, 0xb, 0x0, 0xfe, 0x51, 0xea, 0xb, 0xff, + 0xfe, 0x6a, 0x5, 0x47, 0x0, 0xfe, 0x2a, 0xc7, 0x28, 0xff, 0xfd, 0xd8, + 0x44, 0x5, 0xe, 0x0, 0xfd, 0xf, 0xb7, 0xfd, 0x22, 0xff, 0xfe, 0x8d, + 0xc, 0x6, 0x0, 0xfe, 0x29, 0xe9, 0x1f, 0xff, 0xfe, 0xac, 0x1a, 0x5, + 0x0, 0xfd, 0x3, 0xa1, 0xfb, 0x9, 0xff, 0xfd, 0xfe, 0xc1, 0x1, 0xa, + 0x0, 0xfd, 0x1, 0x72, 0xfa, 0xb, 0xff, 0xff, 0x49, 0x48, 0x0, 0xfe, + 0x40, 0xdd, 0x27, 0xff, 0xfd, 0xae, 0x2e, 0x2, 0x10, 0x0, 0xfe, 0x41, + 0xe7, 0x22, 0xff, 0xfe, 0x71, 0x5, 0x6, 0x0, 0xfe, 0x48, 0xf2, 0x1e, + 0xff, 0xfd, 0xd3, 0x36, 0x1, 0x5, 0x0, 0xfd, 0x11, 0xc2, 0xfe, 0x9, + 0xff, 0xfe, 0xfa, 0x9c, 0xb, 0x0, 0xfe, 0xb, 0x92, 0xb, 0xff, 0xfe, + 0xec, 0x2c, 0x48, 0x0, 0xfe, 0x60, 0xf5, 0x24, 0xff, 0xfb, 0xfd, 0xc8, + 0x65, 0xa, 0x1, 0x11, 0x0, 0xfd, 0x3, 0x4c, 0xcd, 0x20, 0xff, 0xfe, + 0xf1, 0x53, 0x7, 0x0, 0xfe, 0x66, 0xf5, 0x1d, 0xff, 0xfd, 0xe0, 0x52, + 0x2, 0x6, 0x0, 0xfe, 0x26, 0xe1, 0xa, 0xff, 0xfe, 0xf4, 0x71, 0xb, + 0x0, 0xfe, 0x19, 0xae, 0xb, 0xff, 0xfe, 0xc7, 0x1e, 0x47, 0x0, 0xfe, + 0x4, 0x81, 0x23, 0xff, 0xfb, 0xf9, 0xb7, 0x59, 0x14, 0x4, 0x14, 0x0, + 0xfc, 0x2, 0x1a, 0x92, 0xf9, 0x1e, 0xff, 0xfe, 0xd8, 0x32, 0x7, 0x0, + 0xfe, 0x7d, 0xf7, 0x1c, 0xff, 0xfd, 0xb4, 0x2d, 0x3, 0x7, 0x0, 0xfe, + 0x48, 0xee, 0xa, 0xff, 0xfe, 0xee, 0x4c, 0xb, 0x0, 0xfe, 0x2f, 0xca, + 0xb, 0xff, 0xfe, 0x9c, 0x12, 0x47, 0x0, 0xfe, 0x11, 0xa0, 0x20, 0xff, + 0xfa, 0xfd, 0xd6, 0x8f, 0x4b, 0x14, 0x2, 0x18, 0x0, 0xfc, 0x5, 0x46, + 0xa0, 0xef, 0x1c, 0xff, 0xfe, 0xc3, 0x24, 0x7, 0x0, 0xfe, 0x9a, 0xfa, + 0x1a, 0xff, 0xfc, 0xdc, 0x70, 0x15, 0x1, 0x8, 0x0, 0xfe, 0x6f, 0xf4, + 0xa, 0xff, 0xfe, 0xec, 0x3a, 0xb, 0x0, 0xfe, 0x49, 0xe2, 0xb, 0xff, + 0xfe, 0x78, 0x7, 0x47, 0x0, 0xfc, 0x1e, 0xae, 0xf6, 0xe4, 0x14, 0xe5, + 0x2, 0xe4, 0xf4, 0xe2, 0xdf, 0xdb, 0xd3, 0xcb, 0xbc, 0x99, 0x6a, 0x3d, + 0x15, 0x6, 0x1, 0x1b, 0x0, 0xf6, 0x1, 0x9, 0x2b, 0x66, 0x9f, 0xc6, + 0xd5, 0xe0, 0xe5, 0xe6, 0x13, 0xe7, 0xfc, 0xe8, 0xf6, 0xa0, 0x17, 0x6, + 0x0, 0xfc, 0x3, 0xaa, 0xe9, 0xe8, 0x14, 0xe7, 0xf9, 0xe4, 0xdd, 0xd1, + 0xa7, 0x57, 0x18, 0x3, 0xa, 0x0, 0xff, 0x84, 0x2, 0xe8, 0x8, 0xe7, + 0xfd, 0xea, 0xd1, 0x23, 0xb, 0x0, 0xfc, 0x5c, 0xe4, 0xf0, 0xe6, 0x7, + 0xe7, 0xfd, 0xe9, 0xf0, 0x4e, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, + 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, + 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x2e, 0x0}; static const Image dash_logo_image = {256, 64, 2863, dash_logo_data}; const VariantAnimation dash_logo = { 21, { - {0, 0, 25, 0, &dash_logo_image}, - {0, 0, 25, 5, &dash_logo_image}, - {0, 0, 25, 10, &dash_logo_image}, - {0, 0, 25, 15, &dash_logo_image}, - {0, 0, 25, 20, &dash_logo_image}, - {0, 0, 25, 25, &dash_logo_image}, - {0, 0, 25, 30, &dash_logo_image}, - {0, 0, 25, 35, &dash_logo_image}, - {0, 0, 25, 40, &dash_logo_image}, - {0, 0, 25, 45, &dash_logo_image}, - {0, 0, 25, 50, &dash_logo_image}, - {0, 0, 25, 55, &dash_logo_image}, - {0, 0, 25, 60, &dash_logo_image}, - {0, 0, 25, 65, &dash_logo_image}, - {0, 0, 25, 70, &dash_logo_image}, - {0, 0, 25, 75, &dash_logo_image}, - {0, 0, 25, 80, &dash_logo_image}, - {0, 0, 25, 85, &dash_logo_image}, - {0, 0, 25, 90, &dash_logo_image}, - {0, 0, 25, 95, &dash_logo_image}, + {0, 0, 25, 0, &dash_logo_image}, {0, 0, 25, 5, &dash_logo_image}, + {0, 0, 25, 10, &dash_logo_image}, {0, 0, 25, 15, &dash_logo_image}, + {0, 0, 25, 20, &dash_logo_image}, {0, 0, 25, 25, &dash_logo_image}, + {0, 0, 25, 30, &dash_logo_image}, {0, 0, 25, 35, &dash_logo_image}, + {0, 0, 25, 40, &dash_logo_image}, {0, 0, 25, 45, &dash_logo_image}, + {0, 0, 25, 50, &dash_logo_image}, {0, 0, 25, 55, &dash_logo_image}, + {0, 0, 25, 60, &dash_logo_image}, {0, 0, 25, 65, &dash_logo_image}, + {0, 0, 25, 70, &dash_logo_image}, {0, 0, 25, 75, &dash_logo_image}, + {0, 0, 25, 80, &dash_logo_image}, {0, 0, 25, 85, &dash_logo_image}, + {0, 0, 25, 90, &dash_logo_image}, {0, 0, 25, 95, &dash_logo_image}, {0, 0, 25, 100, &dash_logo_image}, - } -}; + }}; const VariantAnimation dash_logo_reversed = { 21, { - {0, 0, 25, 100, &dash_logo_image}, - {0, 0, 25, 95, &dash_logo_image}, - {0, 0, 25, 90, &dash_logo_image}, - {0, 0, 25, 85, &dash_logo_image}, - {0, 0, 25, 80, &dash_logo_image}, - {0, 0, 25, 75, &dash_logo_image}, - {0, 0, 25, 70, &dash_logo_image}, - {0, 0, 25, 65, &dash_logo_image}, - {0, 0, 25, 60, &dash_logo_image}, - {0, 0, 25, 55, &dash_logo_image}, - {0, 0, 25, 50, &dash_logo_image}, - {0, 0, 25, 45, &dash_logo_image}, - {0, 0, 25, 40, &dash_logo_image}, - {0, 0, 25, 35, &dash_logo_image}, - {0, 0, 25, 30, &dash_logo_image}, - {0, 0, 25, 25, &dash_logo_image}, - {0, 0, 25, 20, &dash_logo_image}, - {0, 0, 25, 15, &dash_logo_image}, - {0, 0, 25, 10, &dash_logo_image}, - {0, 0, 25, 5, &dash_logo_image}, + {0, 0, 25, 100, &dash_logo_image}, {0, 0, 25, 95, &dash_logo_image}, + {0, 0, 25, 90, &dash_logo_image}, {0, 0, 25, 85, &dash_logo_image}, + {0, 0, 25, 80, &dash_logo_image}, {0, 0, 25, 75, &dash_logo_image}, + {0, 0, 25, 70, &dash_logo_image}, {0, 0, 25, 65, &dash_logo_image}, + {0, 0, 25, 60, &dash_logo_image}, {0, 0, 25, 55, &dash_logo_image}, + {0, 0, 25, 50, &dash_logo_image}, {0, 0, 25, 45, &dash_logo_image}, + {0, 0, 25, 40, &dash_logo_image}, {0, 0, 25, 35, &dash_logo_image}, + {0, 0, 25, 30, &dash_logo_image}, {0, 0, 25, 25, &dash_logo_image}, + {0, 0, 25, 20, &dash_logo_image}, {0, 0, 25, 15, &dash_logo_image}, + {0, 0, 25, 10, &dash_logo_image}, {0, 0, 25, 5, &dash_logo_image}, {0, 0, 25, 0, &dash_logo_image}, - } -}; + }}; -const uint8_t dash_screensaver_data[2837] = -{ - 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x46, 0x0, 0xfd, 0x27, 0xba, 0xf1, 0x16, 0xe6, 0xf5, 0xe3, 0xde, 0xd4, 0xc7, 0xad, 0x8a, 0x64, 0x39, 0x18, 0x9, 0x1, 0x6c, 0x0, 0xfd, 0x5, 0x96, 0xed, 0x8, 0xe6, 0xfc, 0xe7, 0xf2, 0xb7, 0x1f, 0x28, 0x0, 0xfe, 0x49, 0xe0, 0x1e, 0xff, 0xfa, 0xfb, 0xd9, 0x9e, 0x58, 0x1b, 0x4, 0x6a, 0x0, 0xfe, 0x8, 0xcc, 0xb, 0xff, 0xfe, 0xbd, 0x18, 0x28, 0x0, 0xfe, 0x67, 0xf3, 0x21, 0xff, 0xfb, 0xfd, 0xd2, 0x7d, 0x23, 0x5, 0x68, 0x0, 0xfe, 0x1b, 0xec, 0xa, 0xff, 0xfd, 0xfe, 0x9d, 0x8, 0x28, 0x0, 0xff, 0x8c, 0x25, 0xff, 0xfc, 0xdf, 0x7c, 0x19, 0x1, 0x65, 0x0, 0xfd, 0x1, 0x46, 0xfd, 0xa, 0xff, 0xfe, 0xf4, 0x78, 0x28, 0x0, 0xfe, 0xa, 0xaa, 0x27, 0xff, 0xfe, 0xb1, 0x25, 0x65, 0x0, 0xfe, 0x2, 0x6f, 0xb, 0xff, 0xfe, 0xe9, 0x5b, 0x28, 0x0, 0xfe, 0x23, 0xc1, 0x28, 0xff, 0xfd, 0xb1, 0x23, 0x1, 0x63, 0x0, 0xfe, 0x3, 0x98, 0xb, 0xff, 0xfe, 0xda, 0x3e, 0x28, 0x0, 0xfe, 0x37, 0xd1, 0x29, 0xff, 0xfe, 0xae, 0x20, 0x63, 0x0, 0xfe, 0x6, 0xc2, 0xb, 0xff, 0xfe, 0xc1, 0x20, 0x28, 0x0, 0xfe, 0x47, 0xde, 0x2a, 0xff, 0xfe, 0x8e, 0x9, 0x62, 0x0, 0xfe, 0x1c, 0xe0, 0xb, 0xff, 0xfe, 0xa3, 0x5, 0x28, 0x0, 0xfe, 0x5e, 0xf0, 0x2a, 0xff, 0xfe, 0xd7, 0x37, 0x62, 0x0, 0xfe, 0x3f, 0xed, 0xa, 0xff, 0xfe, 0xfb, 0x89, 0x28, 0x0, 0xfe, 0x1, 0x83, 0x2c, 0xff, 0xfe, 0x84, 0x7, 0x61, 0x0, 0xfe, 0x66, 0xf9, 0xa, 0xff, 0xfe, 0xef, 0x69, 0x28, 0x0, 0xfc, 0x8, 0x78, 0xc6, 0xc4, 0x4, 0xc2, 0x6, 0xc3, 0x7, 0xc4, 0x2, 0xc5, 0xfa, 0xc9, 0xd0, 0xda, 0xe8, 0xf0, 0xfa, 0x11, 0xff, 0xfe, 0xd8, 0x31, 0x60, 0x0, 0xfe, 0x1, 0x83, 0xb, 0xff, 0xfe, 0xdf, 0x46, 0x28, 0x0, 0xfc, 0x3, 0x10, 0x17, 0x16, 0x3, 0x15, 0xff, 0x16, 0x7, 0x17, 0x6, 0x18, 0x2, 0x1a, 0xf8, 0x20, 0x28, 0x37, 0x4e, 0x6d, 0x99, 0xcb, 0xec, 0x10, 0xff, 0xfe, 0x63, 0x1, 0x60, 0x0, 0xff, 0x93, 0xb, 0xff, 0xfe, 0xcb, 0x24, 0x45, 0x0, 0xfc, 0x22, 0x5d, 0xb9, 0xf0, 0xe, 0xff, 0xfe, 0x9a, 0x11, 0x5f, 0x0, 0xfe, 0x3, 0xae, 0xb, 0xff, 0xff, 0xae, 0x48, 0x0, 0xfd, 0xf, 0x75, 0xea, 0xd, 0xff, 0xfe, 0xcb, 0x28, 0x13, 0x0, 0xfa, 0x6, 0x14, 0x20, 0x28, 0x2f, 0x35, 0x14, 0x39, 0xfd, 0x3a, 0x3b, 0x11, 0xd, 0x0, 0xfb, 0x6, 0x19, 0x25, 0x2e, 0x35, 0x14, 0x37, 0xfd, 0x3e, 0x21, 0x3, 0x6, 0x0, 0xfe, 0x17, 0xcb, 0xb, 0xff, 0xfd, 0xac, 0x2f, 0x37, 0x7, 0x39, 0xfa, 0x38, 0x32, 0x2c, 0x26, 0x1b, 0xc, 0x3b, 0x0, 0xfe, 0x6d, 0xf2, 0xc, 0xff, 0xfe, 0xe9, 0x36, 0x10, 0x0, 0xf7, 0xa, 0x26, 0x4b, 0x76, 0xa0, 0xc3, 0xdb, 0xeb, 0xf3, 0x14, 0xf6, 0xfc, 0xfa, 0xf5, 0x42, 0x1, 0xa, 0x0, 0xf9, 0x12, 0x3d, 0x76, 0xad, 0xd1, 0xea, 0xf4, 0x13, 0xf5, 0xfc, 0xf4, 0xff, 0x81, 0xa, 0x6, 0x0, 0xfe, 0x34, 0xe3, 0xa, 0xff, 0xfd, 0xfe, 0xf7, 0xf2, 0x8, 0xf6, 0xf7, 0xf5, 0xf1, 0xe6, 0xd5, 0xb5, 0x88, 0x5a, 0x29, 0x7, 0x38, 0x0, 0xfe, 0x10, 0xa8, 0xc, 0xff, 0xfe, 0xfa, 0x45, 0xe, 0x0, 0xfc, 0x1b, 0x45, 0x84, 0xc6, 0x1c, 0xff, 0xfe, 0xe2, 0x30, 0x9, 0x0, 0xfc, 0xb, 0x43, 0x99, 0xe8, 0x1a, 0xff, 0xfe, 0x66, 0x5, 0x6, 0x0, 0xfe, 0x51, 0xf8, 0x1c, 0xff, 0xfc, 0xcd, 0x76, 0x2d, 0x2, 0x37, 0x0, 0xfe, 0x5d, 0xf5, 0xc, 0xff, 0xff, 0x59, 0xc, 0x0, 0xfc, 0x15, 0x59, 0xad, 0xe7, 0x1e, 0xff, 0xfe, 0xb4, 0x18, 0x8, 0x0, 0xfd, 0x1d, 0x84, 0xe5, 0x1b, 0xff, 0xfe, 0xf7, 0x40, 0x7, 0x0, 0xff, 0x77, 0x1f, 0xff, 0xfd, 0xd1, 0x5a, 0x4, 0x36, 0x0, 0xfe, 0x29, 0xcb, 0xc, 0xff, 0xff, 0x61, 0xb, 0x0, 0xfd, 0x27, 0x9c, 0xf5, 0x20, 0xff, 0xfe, 0x9e, 0xf, 0x7, 0x0, 0xfe, 0x19, 0xa9, 0x1d, 0xff, 0xfe, 0xd1, 0x2a, 0x6, 0x0, 0xfd, 0x3, 0x9c, 0xfe, 0x1f, 0xff, 0xfd, 0xec, 0x50, 0x1, 0x35, 0x0, 0xfe, 0x1a, 0xad, 0xc, 0xff, 0xff, 0x61, 0xa, 0x0, 0xfe, 0x36, 0xc1, 0x22, 0xff, 0xfe, 0x8d, 0xd, 0x6, 0x0, 0xfe, 0x7, 0x92, 0x1e, 0xff, 0xfe, 0xaf, 0x18, 0x6, 0x0, 0xfd, 0x12, 0xbb, 0xfe, 0x20, 0xff, 0xfd, 0xd6, 0x2b, 0x1, 0x34, 0x0, 0xfe, 0x11, 0x9a, 0xc, 0xff, 0xff, 0x5f, 0x9, 0x0, 0xfe, 0x55, 0xd6, 0x23, 0xff, 0xfe, 0x73, 0x8, 0x6, 0x0, 0xfe, 0x65, 0xf7, 0x1e, 0xff, 0xfe, 0x8a, 0xc, 0x6, 0x0, 0xfe, 0x26, 0xde, 0x22, 0xff, 0xfe, 0x8b, 0xb, 0x7, 0x0, 0xfc, 0x11, 0x35, 0x57, 0x65, 0x16, 0x68, 0xfd, 0x6e, 0x4b, 0x7, 0x10, 0x0, 0xfe, 0xf, 0x92, 0xc, 0xff, 0xff, 0x56, 0x8, 0x0, 0xfe, 0x43, 0xec, 0x23, 0xff, 0xfd, 0xfa, 0x55, 0x3, 0x5, 0x0, 0xfe, 0x24, 0xe6, 0x1f, 0xff, 0xfe, 0x67, 0x4, 0x6, 0x0, 0xfe, 0x3f, 0xf8, 0x22, 0xff, 0xfd, 0xdc, 0x2b, 0x1, 0x5, 0x0, 0xfb, 0x40, 0x9a, 0xd2, 0xef, 0xf9, 0x16, 0xfb, 0xfd, 0xff, 0xa8, 0xd, 0x10, 0x0, 0xfe, 0x10, 0x96, 0xb, 0xff, 0xfe, 0xfc, 0x48, 0x7, 0x0, 0xfe, 0x21, 0xcd, 0x24, 0xff, 0xfe, 0xe3, 0x38, 0x6, 0x0, 0xff, 0x8e, 0x1f, 0xff, 0xfd, 0xfa, 0x4d, 0x1, 0x6, 0x0, 0xfe, 0x61, 0xfc, 0x22, 0xff, 0xfd, 0xfc, 0x50, 0x3, 0x3, 0x0, 0xfd, 0x2, 0x54, 0xda, 0x1b, 0xff, 0xfe, 0x89, 0x7, 0x10, 0x0, 0xfe, 0x16, 0xa5, 0xb, 0xff, 0xfe, 0xee, 0x39, 0x6, 0x0, 0xfe, 0x13, 0xa9, 0x11, 0xff, 0xfd, 0xf3, 0xe8, 0xe6, 0x3, 0xe7, 0xfd, 0xe3, 0xea, 0xfa, 0xb, 0xff, 0xfe, 0xc8, 0x1f, 0x5, 0x0, 0xfe, 0x20, 0xe8, 0xc, 0xff, 0xfe, 0xed, 0xe5, 0xf, 0xe7, 0xfc, 0xe6, 0xee, 0xc4, 0x2c, 0x6, 0x0, 0xfd, 0x1, 0x8b, 0xfc, 0x23, 0xff, 0xfe, 0x5e, 0x3, 0x2, 0x0, 0xfd, 0x1, 0x31, 0xdf, 0x1c, 0xff, 0xfe, 0x53, 0x3, 0x10, 0x0, 0xfe, 0x22, 0xbc, 0xb, 0xff, 0xfe, 0xd9, 0x2e, 0x6, 0x0, 0xfe, 0x79, 0xfe, 0xd, 0xff, 0xf9, 0xf9, 0xcd, 0x9f, 0x79, 0x63, 0x55, 0x52, 0x3, 0x53, 0xfd, 0x4d, 0x7a, 0xe6, 0xb, 0xff, 0xfe, 0xa5, 0x11, 0x5, 0x0, 0xfe, 0x65, 0xfd, 0xa, 0xff, 0xfc, 0xec, 0x92, 0x59, 0x51, 0xf, 0x53, 0xfc, 0x52, 0x5c, 0x40, 0x8, 0x6, 0x0, 0xfd, 0x8, 0xb7, 0xfd, 0xa, 0xff, 0xfc, 0xe3, 0x90, 0x86, 0x8d, 0x2, 0x8c, 0xfb, 0x8b, 0x8e, 0x9c, 0xb9, 0xec, 0xe, 0xff, 0xfe, 0x61, 0x5, 0x2, 0x0, 0xfe, 0xa, 0x8c, 0x1c, 0xff, 0xfd, 0xec, 0x31, 0x1, 0x10, 0x0, 0xfe, 0x31, 0xd3, 0xb, 0xff, 0xfe, 0xc0, 0x23, 0x5, 0x0, 0xfe, 0x25, 0xd9, 0xd, 0xff, 0xfc, 0xc8, 0x6a, 0x32, 0x2, 0x8, 0x0, 0xfe, 0x41, 0xea, 0xb, 0xff, 0xfe, 0x85, 0xc, 0x5, 0x0, 0xfe, 0x8e, 0xfc, 0x9, 0xff, 0xfe, 0xf7, 0x8f, 0x1c, 0x0, 0xfe, 0x12, 0xdc, 0xa, 0xff, 0xfe, 0xfd, 0xa9, 0x8, 0x0, 0xfd, 0x1b, 0x5c, 0xd1, 0xd, 0xff, 0xfe, 0x63, 0x5, 0x2, 0x0, 0xfe, 0x24, 0xd8, 0x1c, 0xff, 0xfe, 0xbb, 0x16, 0x11, 0x0, 0xfe, 0x4e, 0xed, 0xb, 0xff, 0xfe, 0xa1, 0x14, 0x5, 0x0, 0xfe, 0x75, 0xf8, 0xb, 0xff, 0xfd, 0xf6, 0x98, 0x2f, 0xb, 0x0, 0xfe, 0x6c, 0xfe, 0xa, 0xff, 0xfd, 0xfc, 0x63, 0x5, 0x5, 0x0, 0xfe, 0xb4, 0xfe, 0x9, 0xff, 0xfe, 0xe0, 0x3e, 0x1c, 0x0, 0xfe, 0x2f, 0xf3, 0xa, 0xff, 0xfe, 0xf5, 0x83, 0xa, 0x0, 0xfe, 0x48, 0xdd, 0xc, 0xff, 0xfa, 0x63, 0x5, 0x0, 0x3, 0x53, 0xfa, 0x1c, 0xff, 0xfe, 0x82, 0x6, 0x10, 0x0, 0xfe, 0x3, 0x75, 0xc, 0xff, 0xfe, 0x7c, 0x4, 0x4, 0x0, 0xfd, 0x11, 0xc7, 0xfe, 0xa, 0xff, 0xfd, 0xf5, 0x79, 0xd, 0xb, 0x0, 0xfe, 0x7, 0x90, 0xb, 0xff, 0xfe, 0xef, 0x3b, 0x5, 0x0, 0xfe, 0x11, 0xd3, 0xa, 0xff, 0xfe, 0xd8, 0x29, 0x1c, 0x0, 0xfe, 0x5c, 0xfa, 0xa, 0xff, 0xfe, 0xed, 0x5d, 0xb, 0x0, 0xff, 0x8a, 0xc, 0xff, 0xfb, 0x61, 0x4, 0x0, 0xa, 0x82, 0x1c, 0xff, 0xfd, 0xf4, 0x3c, 0x1, 0x10, 0x0, 0xfe, 0xe, 0x96, 0xc, 0xff, 0xff, 0x59, 0x5, 0x0, 0xfe, 0x52, 0xf1, 0xa, 0xff, 0xfd, 0xfd, 0xa9, 0x5, 0xc, 0x0, 0xfe, 0x1c, 0xb0, 0xb, 0xff, 0xfe, 0xd8, 0x22, 0x5, 0x0, 0xfe, 0x2a, 0xdd, 0xa, 0xff, 0xfc, 0xec, 0x6e, 0x5, 0x0, 0x9, 0x1, 0x11, 0x0, 0xfe, 0x80, 0xfb, 0xa, 0xff, 0xfe, 0xe5, 0x3d, 0xb, 0x0, 0xfe, 0x65, 0xf8, 0xb, 0xff, 0xfb, 0x5d, 0x4, 0x0, 0x11, 0xab, 0x1c, 0xff, 0xfe, 0x99, 0xb, 0x11, 0x0, 0xfe, 0x18, 0xaa, 0xb, 0xff, 0xfe, 0xe7, 0x3d, 0x5, 0x0, 0xfe, 0xa2, 0xfb, 0xa, 0xff, 0xfe, 0xed, 0x3f, 0xd, 0x0, 0xfe, 0x2d, 0xc7, 0xb, 0xff, 0xfe, 0xba, 0x19, 0x5, 0x0, 0xfe, 0x33, 0xe1, 0xb, 0xff, 0xfd, 0xe2, 0xa5, 0x9b, 0x8, 0x9f, 0xfa, 0x9e, 0x99, 0x89, 0x6b, 0x3f, 0x17, 0xc, 0x0, 0xfe, 0x98, 0xfb, 0xa, 0xff, 0xfe, 0xd4, 0x23, 0xb, 0x0, 0xfe, 0x64, 0xf4, 0xb, 0xff, 0xfb, 0x58, 0x4, 0x0, 0x2f, 0xde, 0x1b, 0xff, 0xfe, 0xb5, 0x24, 0x12, 0x0, 0xfe, 0x2f, 0xd1, 0xb, 0xff, 0xfe, 0xb8, 0x21, 0x4, 0x0, 0xfe, 0x1b, 0xda, 0xa, 0xff, 0xfd, 0xfd, 0xa3, 0x5, 0xd, 0x0, 0xfe, 0x39, 0xd6, 0xb, 0xff, 0xfe, 0x91, 0xf, 0x5, 0x0, 0xfe, 0x2e, 0xdf, 0x19, 0xff, 0xfb, 0xf8, 0xd9, 0xb9, 0x79, 0x10, 0xa, 0x0, 0xfe, 0xb1, 0xfd, 0x9, 0xff, 0xfd, 0xfd, 0xb3, 0xb, 0xb, 0x0, 0xfe, 0x78, 0xfc, 0xa, 0xff, 0xfe, 0xf7, 0x49, 0x2, 0x2, 0xff, 0x58, 0x19, 0xff, 0xfc, 0xf4, 0xce, 0x89, 0x25, 0x13, 0x0, 0xfe, 0x56, 0xf9, 0xb, 0xff, 0xfe, 0x89, 0x8, 0x4, 0x0, 0xfe, 0x58, 0xee, 0xa, 0xff, 0xfe, 0xf2, 0x4f, 0xe, 0x0, 0xfe, 0x44, 0xe5, 0xb, 0xff, 0xfe, 0x69, 0x5, 0x5, 0x0, 0xfe, 0x15, 0xd7, 0x1c, 0xff, 0xfd, 0xf8, 0xa4, 0x1e, 0x8, 0x0, 0xfe, 0x6, 0xd3, 0xa, 0xff, 0xfe, 0xf8, 0x92, 0xb, 0x0, 0xfe, 0x2, 0x97, 0xb, 0xff, 0xf9, 0xdd, 0x32, 0x0, 0x2, 0x31, 0x8a, 0x80, 0x16, 0x7f, 0xfc, 0x78, 0x5d, 0x31, 0x9, 0x13, 0x0, 0xfe, 0xb, 0x8e, 0xb, 0xff, 0xfe, 0xf5, 0x5b, 0x5, 0x0, 0xfe, 0x8d, 0xf8, 0xa, 0xff, 0xfe, 0xd3, 0x20, 0xe, 0x0, 0xfe, 0x5b, 0xf4, 0xa, 0xff, 0xfe, 0xfe, 0x44, 0x6, 0x0, 0xfd, 0x2, 0xb9, 0xfe, 0x1d, 0xff, 0xfe, 0xa8, 0x16, 0x7, 0x0, 0xfe, 0x23, 0xeb, 0xa, 0xff, 0xfe, 0xf2, 0x76, 0xb, 0x0, 0xfe, 0x14, 0xb3, 0xb, 0xff, 0xfe, 0xc1, 0x1b, 0x2, 0x0, 0xfe, 0x2, 0x5, 0x17, 0x4, 0xff, 0x3, 0x16, 0x0, 0xfe, 0x32, 0xe4, 0xb, 0xff, 0xfe, 0xcf, 0x30, 0x5, 0x0, 0xff, 0xb9, 0xa, 0xff, 0xfd, 0xfd, 0xab, 0x4, 0xd, 0x0, 0xfd, 0x5, 0x7e, 0xfd, 0xa, 0xff, 0xfe, 0xe4, 0x29, 0x7, 0x0, 0xff, 0x7e, 0x1e, 0xff, 0xfd, 0xfd, 0x70, 0x9, 0x6, 0x0, 0xfe, 0x50, 0xf4, 0xa, 0xff, 0xfe, 0xed, 0x5c, 0xb, 0x0, 0xfe, 0x33, 0xce, 0xb, 0xff, 0xfe, 0x9e, 0xe, 0x31, 0x0, 0xfe, 0x9, 0x82, 0xc, 0xff, 0xfe, 0xac, 0x18, 0x4, 0x0, 0xfe, 0x18, 0xd1, 0xa, 0xff, 0xfe, 0xfb, 0x87, 0xe, 0x0, 0xfe, 0x11, 0x9f, 0xb, 0xff, 0xfe, 0xc7, 0x1f, 0x7, 0x0, 0xfe, 0x26, 0xe9, 0x1e, 0xff, 0xfe, 0xbe, 0x1b, 0x6, 0x0, 0xfe, 0x7c, 0xf9, 0xa, 0xff, 0xfe, 0xea, 0x4b, 0xb, 0x0, 0xfe, 0x4f, 0xe8, 0xb, 0xff, 0xfe, 0x7b, 0x9, 0x31, 0x0, 0xfe, 0x32, 0xe7, 0xc, 0xff, 0xfe, 0x79, 0x5, 0x4, 0x0, 0xfe, 0x36, 0xdb, 0xa, 0xff, 0xfe, 0xf8, 0x6b, 0xe, 0x0, 0xfe, 0x20, 0xb8, 0xb, 0xff, 0xfe, 0xb6, 0x1a, 0x8, 0x0, 0xfe, 0x67, 0xfc, 0x1d, 0xff, 0xfe, 0xe8, 0x3a, 0x6, 0x0, 0xfe, 0xa3, 0xfc, 0xa, 0xff, 0xfe, 0xdb, 0x38, 0xb, 0x0, 0xfe, 0x68, 0xfc, 0xa, 0xff, 0xfd, 0xfb, 0x5e, 0x4, 0x30, 0x0, 0xfe, 0xe, 0xa4, 0xc, 0xff, 0xfe, 0xda, 0x38, 0x5, 0x0, 0xfe, 0x49, 0xe3, 0xa, 0xff, 0xfe, 0xf3, 0x5a, 0xe, 0x0, 0xfe, 0x35, 0xd3, 0xb, 0xff, 0xfe, 0x9b, 0x12, 0x8, 0x0, 0xfd, 0x7, 0x6a, 0xd9, 0x1c, 0xff, 0xfd, 0xfd, 0x62, 0x5, 0x4, 0x0, 0xfd, 0x5, 0xc5, 0xfe, 0xa, 0xff, 0xfe, 0xc2, 0x14, 0xa, 0x0, 0xfe, 0x1, 0x8a, 0xb, 0xff, 0xfd, 0xea, 0x39, 0x1, 0x2f, 0x0, 0xfd, 0x3, 0x85, 0xf7, 0xc, 0xff, 0xfe, 0x88, 0x7, 0x5, 0x0, 0xfe, 0x52, 0xe7, 0xa, 0xff, 0xfe, 0xf3, 0x58, 0xe, 0x0, 0xfe, 0x51, 0xe9, 0xb, 0xff, 0xfe, 0x75, 0x6, 0x9, 0x0, 0xfc, 0x4, 0x38, 0x93, 0xda, 0x1b, 0xff, 0xfe, 0x78, 0xa, 0x4, 0x0, 0xfe, 0x25, 0xdb, 0xa, 0xff, 0xfd, 0xfc, 0xa6, 0x1, 0xa, 0x0, 0xfe, 0x16, 0xac, 0xb, 0xff, 0xfe, 0xd2, 0x1e, 0x2f, 0x0, 0xfd, 0xb, 0x89, 0xf1, 0xc, 0xff, 0xfe, 0xe2, 0x3f, 0x6, 0x0, 0xfe, 0x54, 0xe9, 0xa, 0xff, 0xfe, 0xf8, 0x6a, 0xe, 0x0, 0xfe, 0x6f, 0xfc, 0xb, 0xff, 0xff, 0x4f, 0xc, 0x0, 0xfa, 0x10, 0x32, 0x5c, 0x82, 0x97, 0xa1, 0x8, 0xa2, 0xfd, 0x9f, 0xa3, 0xd8, 0xc, 0xff, 0xfe, 0x7c, 0xa, 0x4, 0x0, 0xfe, 0x49, 0xeb, 0xa, 0xff, 0xfe, 0xf7, 0x89, 0xb, 0x0, 0xfe, 0x2e, 0xc8, 0xb, 0xff, 0xfe, 0xb3, 0x15, 0x2d, 0x0, 0xfc, 0x2, 0x38, 0xa2, 0xf5, 0xd, 0xff, 0xfe, 0x8b, 0x8, 0x6, 0x0, 0xfe, 0x54, 0xe8, 0xa, 0xff, 0xfe, 0xfc, 0x9a, 0xd, 0x0, 0xfe, 0x8, 0x8d, 0xb, 0xff, 0xfe, 0xef, 0x36, 0xf, 0x0, 0xfd, 0xa, 0x11, 0x14, 0x8, 0x15, 0xfc, 0x14, 0x15, 0x42, 0xcb, 0xb, 0xff, 0xfe, 0x73, 0x8, 0x4, 0x0, 0xfe, 0x6d, 0xf5, 0xa, 0xff, 0xfe, 0xf0, 0x67, 0xb, 0x0, 0xfe, 0x3e, 0xd9, 0xb, 0xff, 0xfe, 0x90, 0xe, 0x2b, 0x0, 0xfb, 0x14, 0x4c, 0xa2, 0xdf, 0xfb, 0xd, 0xff, 0xfe, 0xd7, 0x37, 0x7, 0x0, 0xfe, 0x50, 0xe7, 0xb, 0xff, 0xfe, 0xdf, 0x33, 0xc, 0x0, 0xfe, 0x18, 0xab, 0xb, 0xff, 0xfe, 0xc7, 0x23, 0x1c, 0x0, 0xfe, 0x4, 0x98, 0xa, 0xff, 0xfd, 0xfa, 0x5d, 0x2, 0x4, 0x0, 0xfe, 0x95, 0xfa, 0xa, 0xff, 0xfe, 0xe1, 0x3c, 0xb, 0x0, 0xfe, 0x4b, 0xe7, 0xb, 0xff, 0xfe, 0x66, 0x6, 0x25, 0x0, 0xf7, 0x4, 0xf, 0x23, 0x3d, 0x5e, 0x8c, 0xba, 0xe7, 0xfc, 0xf, 0xff, 0xfe, 0x7e, 0x5, 0x7, 0x0, 0xfe, 0x46, 0xe2, 0xb, 0xff, 0xfd, 0xfd, 0xb9, 0x14, 0xb, 0x0, 0xfe, 0x2b, 0xc5, 0xb, 0xff, 0xfe, 0xa2, 0x15, 0x1c, 0x0, 0xfe, 0x12, 0xa8, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0x4, 0x0, 0xfd, 0x5, 0xb3, 0xfd, 0xa, 0xff, 0xfe, 0xd2, 0x15, 0xb, 0x0, 0xfe, 0x5c, 0xf6, 0xa, 0xff, 0xfd, 0xf9, 0x3f, 0x1, 0xe, 0x0, 0xfd, 0x24, 0x92, 0xb7, 0x13, 0xae, 0xf9, 0xb1, 0xb6, 0xbd, 0xcb, 0xde, 0xec, 0xf7, 0x11, 0xff, 0xfe, 0xb6, 0x1c, 0x8, 0x0, 0xfe, 0x29, 0xd8, 0xc, 0xff, 0xfc, 0xfa, 0xb5, 0x3f, 0x2, 0x9, 0x0, 0xfe, 0x38, 0xdc, 0xb, 0xff, 0xfe, 0x81, 0x9, 0x1c, 0x0, 0xfe, 0x3f, 0xe1, 0xa, 0xff, 0xfe, 0xcc, 0x24, 0x4, 0x0, 0xfe, 0x1e, 0xcd, 0xb, 0xff, 0xfe, 0xba, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x7b, 0xfe, 0xa, 0xff, 0xfe, 0xe3, 0x25, 0xf, 0x0, 0xfd, 0x4b, 0xea, 0xff, 0x14, 0xfe, 0x16, 0xff, 0xfe, 0xca, 0x2f, 0x9, 0x0, 0xfe, 0x4, 0xba, 0xd, 0xff, 0xf9, 0xfd, 0xe4, 0xca, 0xa9, 0x84, 0x72, 0x6e, 0x3, 0x6f, 0xfc, 0x6d, 0x6b, 0xa1, 0xf8, 0xb, 0xff, 0xfe, 0x5e, 0x1, 0x6, 0x0, 0xfd, 0x2c, 0x71, 0x6f, 0x10, 0x6d, 0xfb, 0x6c, 0x6d, 0x94, 0xda, 0xfd, 0xa, 0xff, 0xfe, 0xa3, 0x15, 0x4, 0x0, 0xfe, 0x3e, 0xea, 0xa, 0xff, 0xfe, 0xf9, 0x93, 0xb, 0x0, 0xfe, 0x12, 0x9f, 0xb, 0xff, 0xfe, 0xbb, 0x19, 0xf, 0x0, 0xfe, 0x68, 0xf8, 0x2a, 0xff, 0xfd, 0xe7, 0x52, 0x1, 0xa, 0x0, 0xfe, 0x7e, 0xf5, 0xf, 0xff, 0xfe, 0xfd, 0xf6, 0x5, 0xf2, 0x2, 0xf1, 0xff, 0xf7, 0xb, 0xff, 0xfe, 0xed, 0x44, 0x7, 0x0, 0xfd, 0x7c, 0xed, 0xf2, 0x12, 0xf1, 0xff, 0xf9, 0xc, 0xff, 0xfe, 0x6f, 0x4, 0x4, 0x0, 0xfe, 0x5c, 0xf3, 0xa, 0xff, 0xfe, 0xf2, 0x6c, 0xb, 0x0, 0xfe, 0x23, 0xbd, 0xb, 0xff, 0xfe, 0x99, 0x10, 0xe, 0x0, 0xfd, 0x9, 0x88, 0xfe, 0x29, 0xff, 0xfd, 0xf4, 0x72, 0x6, 0xb, 0x0, 0xfe, 0x26, 0xe2, 0x24, 0xff, 0xfe, 0xcf, 0x2e, 0x6, 0x0, 0xfd, 0x4, 0xa0, 0xfd, 0x1f, 0xff, 0xfe, 0xe1, 0x31, 0x5, 0x0, 0xfe, 0x73, 0xf6, 0xa, 0xff, 0xfe, 0xec, 0x43, 0xb, 0x0, 0xfe, 0x38, 0xd4, 0xb, 0xff, 0xfe, 0x81, 0xb, 0xe, 0x0, 0xfe, 0x17, 0xa9, 0x29, 0xff, 0xfd, 0xe3, 0x5c, 0x9, 0xc, 0x0, 0xfd, 0x2, 0x7e, 0xf7, 0x23, 0xff, 0xfe, 0xae, 0x1a, 0x6, 0x0, 0xfd, 0x15, 0xc7, 0xfe, 0x1f, 0xff, 0xfe, 0x70, 0x4, 0x5, 0x0, 0xfe, 0x86, 0xf8, 0xa, 0xff, 0xfe, 0xde, 0x19, 0xb, 0x0, 0xfe, 0x51, 0xea, 0xb, 0xff, 0xfe, 0x6a, 0x5, 0xe, 0x0, 0xfe, 0x2a, 0xc7, 0x28, 0xff, 0xfd, 0xd8, 0x44, 0x5, 0xe, 0x0, 0xfd, 0xf, 0xb7, 0xfd, 0x22, 0xff, 0xfe, 0x8d, 0xc, 0x6, 0x0, 0xfe, 0x29, 0xe9, 0x1f, 0xff, 0xfe, 0xac, 0x1a, 0x5, 0x0, 0xfd, 0x3, 0xa1, 0xfb, 0x9, 0xff, 0xfd, 0xfe, 0xc1, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x72, 0xfa, 0xb, 0xff, 0xff, 0x49, 0xf, 0x0, 0xfe, 0x40, 0xdd, 0x27, 0xff, 0xfd, 0xae, 0x2e, 0x2, 0x10, 0x0, 0xfe, 0x41, 0xe7, 0x22, 0xff, 0xfe, 0x71, 0x5, 0x6, 0x0, 0xfe, 0x48, 0xf2, 0x1e, 0xff, 0xfd, 0xd3, 0x36, 0x1, 0x5, 0x0, 0xfd, 0x11, 0xc2, 0xfe, 0x9, 0xff, 0xfe, 0xfa, 0x9c, 0xb, 0x0, 0xfe, 0xb, 0x92, 0xb, 0xff, 0xfe, 0xec, 0x2c, 0xf, 0x0, 0xfe, 0x60, 0xf5, 0x24, 0xff, 0xfb, 0xfd, 0xc8, 0x65, 0xa, 0x1, 0x11, 0x0, 0xfd, 0x3, 0x4c, 0xcd, 0x20, 0xff, 0xfe, 0xf1, 0x53, 0x7, 0x0, 0xfe, 0x66, 0xf5, 0x1d, 0xff, 0xfd, 0xe0, 0x52, 0x2, 0x6, 0x0, 0xfe, 0x26, 0xe1, 0xa, 0xff, 0xfe, 0xf4, 0x71, 0xb, 0x0, 0xfe, 0x19, 0xae, 0xb, 0xff, 0xfe, 0xc7, 0x1e, 0xe, 0x0, 0xfe, 0x4, 0x81, 0x23, 0xff, 0xfb, 0xf9, 0xb7, 0x59, 0x14, 0x4, 0x14, 0x0, 0xfc, 0x2, 0x1a, 0x92, 0xf9, 0x1e, 0xff, 0xfe, 0xd8, 0x32, 0x7, 0x0, 0xfe, 0x7d, 0xf7, 0x1c, 0xff, 0xfd, 0xb4, 0x2d, 0x3, 0x7, 0x0, 0xfe, 0x48, 0xee, 0xa, 0xff, 0xfe, 0xee, 0x4c, 0xb, 0x0, 0xfe, 0x2f, 0xca, 0xb, 0xff, 0xfe, 0x9c, 0x12, 0xe, 0x0, 0xfe, 0x11, 0xa0, 0x20, 0xff, 0xfa, 0xfd, 0xd6, 0x8f, 0x4b, 0x14, 0x2, 0x18, 0x0, 0xfc, 0x5, 0x46, 0xa0, 0xef, 0x1c, 0xff, 0xfe, 0xc3, 0x24, 0x7, 0x0, 0xfe, 0x9a, 0xfa, 0x1a, 0xff, 0xfc, 0xdc, 0x70, 0x15, 0x1, 0x8, 0x0, 0xfe, 0x6f, 0xf4, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0xb, 0x0, 0xfe, 0x49, 0xe2, 0xb, 0xff, 0xfe, 0x78, 0x7, 0xe, 0x0, 0xfc, 0x1e, 0xae, 0xf6, 0xe4, 0x14, 0xe5, 0x2, 0xe4, 0xf4, 0xe2, 0xdf, 0xdb, 0xd3, 0xcb, 0xbc, 0x99, 0x6a, 0x3d, 0x15, 0x6, 0x1, 0x1b, 0x0, 0xf6, 0x1, 0x9, 0x2b, 0x66, 0x9f, 0xc6, 0xd5, 0xe0, 0xe5, 0xe6, 0x13, 0xe7, 0xfc, 0xe8, 0xf6, 0xa0, 0x17, 0x6, 0x0, 0xfc, 0x3, 0xaa, 0xe9, 0xe8, 0x14, 0xe7, 0xf9, 0xe4, 0xdd, 0xd1, 0xa7, 0x57, 0x18, 0x3, 0xa, 0x0, 0xff, 0x84, 0x2, 0xe8, 0x8, 0xe7, 0xfd, 0xea, 0xd1, 0x23, 0xb, 0x0, 0xfc, 0x5c, 0xe4, 0xf0, 0xe6, 0x7, 0xe7, 0xfd, 0xe9, 0xf0, 0x4e, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x38, 0x0 -}; -static const Image dash_screensaver_image = {199, 64, 2837, dash_screensaver_data}; +const uint8_t dash_screensaver_data[2837] = { + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x46, 0x0, 0xfd, 0x27, 0xba, 0xf1, + 0x16, 0xe6, 0xf5, 0xe3, 0xde, 0xd4, 0xc7, 0xad, 0x8a, 0x64, 0x39, 0x18, + 0x9, 0x1, 0x6c, 0x0, 0xfd, 0x5, 0x96, 0xed, 0x8, 0xe6, 0xfc, 0xe7, + 0xf2, 0xb7, 0x1f, 0x28, 0x0, 0xfe, 0x49, 0xe0, 0x1e, 0xff, 0xfa, 0xfb, + 0xd9, 0x9e, 0x58, 0x1b, 0x4, 0x6a, 0x0, 0xfe, 0x8, 0xcc, 0xb, 0xff, + 0xfe, 0xbd, 0x18, 0x28, 0x0, 0xfe, 0x67, 0xf3, 0x21, 0xff, 0xfb, 0xfd, + 0xd2, 0x7d, 0x23, 0x5, 0x68, 0x0, 0xfe, 0x1b, 0xec, 0xa, 0xff, 0xfd, + 0xfe, 0x9d, 0x8, 0x28, 0x0, 0xff, 0x8c, 0x25, 0xff, 0xfc, 0xdf, 0x7c, + 0x19, 0x1, 0x65, 0x0, 0xfd, 0x1, 0x46, 0xfd, 0xa, 0xff, 0xfe, 0xf4, + 0x78, 0x28, 0x0, 0xfe, 0xa, 0xaa, 0x27, 0xff, 0xfe, 0xb1, 0x25, 0x65, + 0x0, 0xfe, 0x2, 0x6f, 0xb, 0xff, 0xfe, 0xe9, 0x5b, 0x28, 0x0, 0xfe, + 0x23, 0xc1, 0x28, 0xff, 0xfd, 0xb1, 0x23, 0x1, 0x63, 0x0, 0xfe, 0x3, + 0x98, 0xb, 0xff, 0xfe, 0xda, 0x3e, 0x28, 0x0, 0xfe, 0x37, 0xd1, 0x29, + 0xff, 0xfe, 0xae, 0x20, 0x63, 0x0, 0xfe, 0x6, 0xc2, 0xb, 0xff, 0xfe, + 0xc1, 0x20, 0x28, 0x0, 0xfe, 0x47, 0xde, 0x2a, 0xff, 0xfe, 0x8e, 0x9, + 0x62, 0x0, 0xfe, 0x1c, 0xe0, 0xb, 0xff, 0xfe, 0xa3, 0x5, 0x28, 0x0, + 0xfe, 0x5e, 0xf0, 0x2a, 0xff, 0xfe, 0xd7, 0x37, 0x62, 0x0, 0xfe, 0x3f, + 0xed, 0xa, 0xff, 0xfe, 0xfb, 0x89, 0x28, 0x0, 0xfe, 0x1, 0x83, 0x2c, + 0xff, 0xfe, 0x84, 0x7, 0x61, 0x0, 0xfe, 0x66, 0xf9, 0xa, 0xff, 0xfe, + 0xef, 0x69, 0x28, 0x0, 0xfc, 0x8, 0x78, 0xc6, 0xc4, 0x4, 0xc2, 0x6, + 0xc3, 0x7, 0xc4, 0x2, 0xc5, 0xfa, 0xc9, 0xd0, 0xda, 0xe8, 0xf0, 0xfa, + 0x11, 0xff, 0xfe, 0xd8, 0x31, 0x60, 0x0, 0xfe, 0x1, 0x83, 0xb, 0xff, + 0xfe, 0xdf, 0x46, 0x28, 0x0, 0xfc, 0x3, 0x10, 0x17, 0x16, 0x3, 0x15, + 0xff, 0x16, 0x7, 0x17, 0x6, 0x18, 0x2, 0x1a, 0xf8, 0x20, 0x28, 0x37, + 0x4e, 0x6d, 0x99, 0xcb, 0xec, 0x10, 0xff, 0xfe, 0x63, 0x1, 0x60, 0x0, + 0xff, 0x93, 0xb, 0xff, 0xfe, 0xcb, 0x24, 0x45, 0x0, 0xfc, 0x22, 0x5d, + 0xb9, 0xf0, 0xe, 0xff, 0xfe, 0x9a, 0x11, 0x5f, 0x0, 0xfe, 0x3, 0xae, + 0xb, 0xff, 0xff, 0xae, 0x48, 0x0, 0xfd, 0xf, 0x75, 0xea, 0xd, 0xff, + 0xfe, 0xcb, 0x28, 0x13, 0x0, 0xfa, 0x6, 0x14, 0x20, 0x28, 0x2f, 0x35, + 0x14, 0x39, 0xfd, 0x3a, 0x3b, 0x11, 0xd, 0x0, 0xfb, 0x6, 0x19, 0x25, + 0x2e, 0x35, 0x14, 0x37, 0xfd, 0x3e, 0x21, 0x3, 0x6, 0x0, 0xfe, 0x17, + 0xcb, 0xb, 0xff, 0xfd, 0xac, 0x2f, 0x37, 0x7, 0x39, 0xfa, 0x38, 0x32, + 0x2c, 0x26, 0x1b, 0xc, 0x3b, 0x0, 0xfe, 0x6d, 0xf2, 0xc, 0xff, 0xfe, + 0xe9, 0x36, 0x10, 0x0, 0xf7, 0xa, 0x26, 0x4b, 0x76, 0xa0, 0xc3, 0xdb, + 0xeb, 0xf3, 0x14, 0xf6, 0xfc, 0xfa, 0xf5, 0x42, 0x1, 0xa, 0x0, 0xf9, + 0x12, 0x3d, 0x76, 0xad, 0xd1, 0xea, 0xf4, 0x13, 0xf5, 0xfc, 0xf4, 0xff, + 0x81, 0xa, 0x6, 0x0, 0xfe, 0x34, 0xe3, 0xa, 0xff, 0xfd, 0xfe, 0xf7, + 0xf2, 0x8, 0xf6, 0xf7, 0xf5, 0xf1, 0xe6, 0xd5, 0xb5, 0x88, 0x5a, 0x29, + 0x7, 0x38, 0x0, 0xfe, 0x10, 0xa8, 0xc, 0xff, 0xfe, 0xfa, 0x45, 0xe, + 0x0, 0xfc, 0x1b, 0x45, 0x84, 0xc6, 0x1c, 0xff, 0xfe, 0xe2, 0x30, 0x9, + 0x0, 0xfc, 0xb, 0x43, 0x99, 0xe8, 0x1a, 0xff, 0xfe, 0x66, 0x5, 0x6, + 0x0, 0xfe, 0x51, 0xf8, 0x1c, 0xff, 0xfc, 0xcd, 0x76, 0x2d, 0x2, 0x37, + 0x0, 0xfe, 0x5d, 0xf5, 0xc, 0xff, 0xff, 0x59, 0xc, 0x0, 0xfc, 0x15, + 0x59, 0xad, 0xe7, 0x1e, 0xff, 0xfe, 0xb4, 0x18, 0x8, 0x0, 0xfd, 0x1d, + 0x84, 0xe5, 0x1b, 0xff, 0xfe, 0xf7, 0x40, 0x7, 0x0, 0xff, 0x77, 0x1f, + 0xff, 0xfd, 0xd1, 0x5a, 0x4, 0x36, 0x0, 0xfe, 0x29, 0xcb, 0xc, 0xff, + 0xff, 0x61, 0xb, 0x0, 0xfd, 0x27, 0x9c, 0xf5, 0x20, 0xff, 0xfe, 0x9e, + 0xf, 0x7, 0x0, 0xfe, 0x19, 0xa9, 0x1d, 0xff, 0xfe, 0xd1, 0x2a, 0x6, + 0x0, 0xfd, 0x3, 0x9c, 0xfe, 0x1f, 0xff, 0xfd, 0xec, 0x50, 0x1, 0x35, + 0x0, 0xfe, 0x1a, 0xad, 0xc, 0xff, 0xff, 0x61, 0xa, 0x0, 0xfe, 0x36, + 0xc1, 0x22, 0xff, 0xfe, 0x8d, 0xd, 0x6, 0x0, 0xfe, 0x7, 0x92, 0x1e, + 0xff, 0xfe, 0xaf, 0x18, 0x6, 0x0, 0xfd, 0x12, 0xbb, 0xfe, 0x20, 0xff, + 0xfd, 0xd6, 0x2b, 0x1, 0x34, 0x0, 0xfe, 0x11, 0x9a, 0xc, 0xff, 0xff, + 0x5f, 0x9, 0x0, 0xfe, 0x55, 0xd6, 0x23, 0xff, 0xfe, 0x73, 0x8, 0x6, + 0x0, 0xfe, 0x65, 0xf7, 0x1e, 0xff, 0xfe, 0x8a, 0xc, 0x6, 0x0, 0xfe, + 0x26, 0xde, 0x22, 0xff, 0xfe, 0x8b, 0xb, 0x7, 0x0, 0xfc, 0x11, 0x35, + 0x57, 0x65, 0x16, 0x68, 0xfd, 0x6e, 0x4b, 0x7, 0x10, 0x0, 0xfe, 0xf, + 0x92, 0xc, 0xff, 0xff, 0x56, 0x8, 0x0, 0xfe, 0x43, 0xec, 0x23, 0xff, + 0xfd, 0xfa, 0x55, 0x3, 0x5, 0x0, 0xfe, 0x24, 0xe6, 0x1f, 0xff, 0xfe, + 0x67, 0x4, 0x6, 0x0, 0xfe, 0x3f, 0xf8, 0x22, 0xff, 0xfd, 0xdc, 0x2b, + 0x1, 0x5, 0x0, 0xfb, 0x40, 0x9a, 0xd2, 0xef, 0xf9, 0x16, 0xfb, 0xfd, + 0xff, 0xa8, 0xd, 0x10, 0x0, 0xfe, 0x10, 0x96, 0xb, 0xff, 0xfe, 0xfc, + 0x48, 0x7, 0x0, 0xfe, 0x21, 0xcd, 0x24, 0xff, 0xfe, 0xe3, 0x38, 0x6, + 0x0, 0xff, 0x8e, 0x1f, 0xff, 0xfd, 0xfa, 0x4d, 0x1, 0x6, 0x0, 0xfe, + 0x61, 0xfc, 0x22, 0xff, 0xfd, 0xfc, 0x50, 0x3, 0x3, 0x0, 0xfd, 0x2, + 0x54, 0xda, 0x1b, 0xff, 0xfe, 0x89, 0x7, 0x10, 0x0, 0xfe, 0x16, 0xa5, + 0xb, 0xff, 0xfe, 0xee, 0x39, 0x6, 0x0, 0xfe, 0x13, 0xa9, 0x11, 0xff, + 0xfd, 0xf3, 0xe8, 0xe6, 0x3, 0xe7, 0xfd, 0xe3, 0xea, 0xfa, 0xb, 0xff, + 0xfe, 0xc8, 0x1f, 0x5, 0x0, 0xfe, 0x20, 0xe8, 0xc, 0xff, 0xfe, 0xed, + 0xe5, 0xf, 0xe7, 0xfc, 0xe6, 0xee, 0xc4, 0x2c, 0x6, 0x0, 0xfd, 0x1, + 0x8b, 0xfc, 0x23, 0xff, 0xfe, 0x5e, 0x3, 0x2, 0x0, 0xfd, 0x1, 0x31, + 0xdf, 0x1c, 0xff, 0xfe, 0x53, 0x3, 0x10, 0x0, 0xfe, 0x22, 0xbc, 0xb, + 0xff, 0xfe, 0xd9, 0x2e, 0x6, 0x0, 0xfe, 0x79, 0xfe, 0xd, 0xff, 0xf9, + 0xf9, 0xcd, 0x9f, 0x79, 0x63, 0x55, 0x52, 0x3, 0x53, 0xfd, 0x4d, 0x7a, + 0xe6, 0xb, 0xff, 0xfe, 0xa5, 0x11, 0x5, 0x0, 0xfe, 0x65, 0xfd, 0xa, + 0xff, 0xfc, 0xec, 0x92, 0x59, 0x51, 0xf, 0x53, 0xfc, 0x52, 0x5c, 0x40, + 0x8, 0x6, 0x0, 0xfd, 0x8, 0xb7, 0xfd, 0xa, 0xff, 0xfc, 0xe3, 0x90, + 0x86, 0x8d, 0x2, 0x8c, 0xfb, 0x8b, 0x8e, 0x9c, 0xb9, 0xec, 0xe, 0xff, + 0xfe, 0x61, 0x5, 0x2, 0x0, 0xfe, 0xa, 0x8c, 0x1c, 0xff, 0xfd, 0xec, + 0x31, 0x1, 0x10, 0x0, 0xfe, 0x31, 0xd3, 0xb, 0xff, 0xfe, 0xc0, 0x23, + 0x5, 0x0, 0xfe, 0x25, 0xd9, 0xd, 0xff, 0xfc, 0xc8, 0x6a, 0x32, 0x2, + 0x8, 0x0, 0xfe, 0x41, 0xea, 0xb, 0xff, 0xfe, 0x85, 0xc, 0x5, 0x0, + 0xfe, 0x8e, 0xfc, 0x9, 0xff, 0xfe, 0xf7, 0x8f, 0x1c, 0x0, 0xfe, 0x12, + 0xdc, 0xa, 0xff, 0xfe, 0xfd, 0xa9, 0x8, 0x0, 0xfd, 0x1b, 0x5c, 0xd1, + 0xd, 0xff, 0xfe, 0x63, 0x5, 0x2, 0x0, 0xfe, 0x24, 0xd8, 0x1c, 0xff, + 0xfe, 0xbb, 0x16, 0x11, 0x0, 0xfe, 0x4e, 0xed, 0xb, 0xff, 0xfe, 0xa1, + 0x14, 0x5, 0x0, 0xfe, 0x75, 0xf8, 0xb, 0xff, 0xfd, 0xf6, 0x98, 0x2f, + 0xb, 0x0, 0xfe, 0x6c, 0xfe, 0xa, 0xff, 0xfd, 0xfc, 0x63, 0x5, 0x5, + 0x0, 0xfe, 0xb4, 0xfe, 0x9, 0xff, 0xfe, 0xe0, 0x3e, 0x1c, 0x0, 0xfe, + 0x2f, 0xf3, 0xa, 0xff, 0xfe, 0xf5, 0x83, 0xa, 0x0, 0xfe, 0x48, 0xdd, + 0xc, 0xff, 0xfa, 0x63, 0x5, 0x0, 0x3, 0x53, 0xfa, 0x1c, 0xff, 0xfe, + 0x82, 0x6, 0x10, 0x0, 0xfe, 0x3, 0x75, 0xc, 0xff, 0xfe, 0x7c, 0x4, + 0x4, 0x0, 0xfd, 0x11, 0xc7, 0xfe, 0xa, 0xff, 0xfd, 0xf5, 0x79, 0xd, + 0xb, 0x0, 0xfe, 0x7, 0x90, 0xb, 0xff, 0xfe, 0xef, 0x3b, 0x5, 0x0, + 0xfe, 0x11, 0xd3, 0xa, 0xff, 0xfe, 0xd8, 0x29, 0x1c, 0x0, 0xfe, 0x5c, + 0xfa, 0xa, 0xff, 0xfe, 0xed, 0x5d, 0xb, 0x0, 0xff, 0x8a, 0xc, 0xff, + 0xfb, 0x61, 0x4, 0x0, 0xa, 0x82, 0x1c, 0xff, 0xfd, 0xf4, 0x3c, 0x1, + 0x10, 0x0, 0xfe, 0xe, 0x96, 0xc, 0xff, 0xff, 0x59, 0x5, 0x0, 0xfe, + 0x52, 0xf1, 0xa, 0xff, 0xfd, 0xfd, 0xa9, 0x5, 0xc, 0x0, 0xfe, 0x1c, + 0xb0, 0xb, 0xff, 0xfe, 0xd8, 0x22, 0x5, 0x0, 0xfe, 0x2a, 0xdd, 0xa, + 0xff, 0xfc, 0xec, 0x6e, 0x5, 0x0, 0x9, 0x1, 0x11, 0x0, 0xfe, 0x80, + 0xfb, 0xa, 0xff, 0xfe, 0xe5, 0x3d, 0xb, 0x0, 0xfe, 0x65, 0xf8, 0xb, + 0xff, 0xfb, 0x5d, 0x4, 0x0, 0x11, 0xab, 0x1c, 0xff, 0xfe, 0x99, 0xb, + 0x11, 0x0, 0xfe, 0x18, 0xaa, 0xb, 0xff, 0xfe, 0xe7, 0x3d, 0x5, 0x0, + 0xfe, 0xa2, 0xfb, 0xa, 0xff, 0xfe, 0xed, 0x3f, 0xd, 0x0, 0xfe, 0x2d, + 0xc7, 0xb, 0xff, 0xfe, 0xba, 0x19, 0x5, 0x0, 0xfe, 0x33, 0xe1, 0xb, + 0xff, 0xfd, 0xe2, 0xa5, 0x9b, 0x8, 0x9f, 0xfa, 0x9e, 0x99, 0x89, 0x6b, + 0x3f, 0x17, 0xc, 0x0, 0xfe, 0x98, 0xfb, 0xa, 0xff, 0xfe, 0xd4, 0x23, + 0xb, 0x0, 0xfe, 0x64, 0xf4, 0xb, 0xff, 0xfb, 0x58, 0x4, 0x0, 0x2f, + 0xde, 0x1b, 0xff, 0xfe, 0xb5, 0x24, 0x12, 0x0, 0xfe, 0x2f, 0xd1, 0xb, + 0xff, 0xfe, 0xb8, 0x21, 0x4, 0x0, 0xfe, 0x1b, 0xda, 0xa, 0xff, 0xfd, + 0xfd, 0xa3, 0x5, 0xd, 0x0, 0xfe, 0x39, 0xd6, 0xb, 0xff, 0xfe, 0x91, + 0xf, 0x5, 0x0, 0xfe, 0x2e, 0xdf, 0x19, 0xff, 0xfb, 0xf8, 0xd9, 0xb9, + 0x79, 0x10, 0xa, 0x0, 0xfe, 0xb1, 0xfd, 0x9, 0xff, 0xfd, 0xfd, 0xb3, + 0xb, 0xb, 0x0, 0xfe, 0x78, 0xfc, 0xa, 0xff, 0xfe, 0xf7, 0x49, 0x2, + 0x2, 0xff, 0x58, 0x19, 0xff, 0xfc, 0xf4, 0xce, 0x89, 0x25, 0x13, 0x0, + 0xfe, 0x56, 0xf9, 0xb, 0xff, 0xfe, 0x89, 0x8, 0x4, 0x0, 0xfe, 0x58, + 0xee, 0xa, 0xff, 0xfe, 0xf2, 0x4f, 0xe, 0x0, 0xfe, 0x44, 0xe5, 0xb, + 0xff, 0xfe, 0x69, 0x5, 0x5, 0x0, 0xfe, 0x15, 0xd7, 0x1c, 0xff, 0xfd, + 0xf8, 0xa4, 0x1e, 0x8, 0x0, 0xfe, 0x6, 0xd3, 0xa, 0xff, 0xfe, 0xf8, + 0x92, 0xb, 0x0, 0xfe, 0x2, 0x97, 0xb, 0xff, 0xf9, 0xdd, 0x32, 0x0, + 0x2, 0x31, 0x8a, 0x80, 0x16, 0x7f, 0xfc, 0x78, 0x5d, 0x31, 0x9, 0x13, + 0x0, 0xfe, 0xb, 0x8e, 0xb, 0xff, 0xfe, 0xf5, 0x5b, 0x5, 0x0, 0xfe, + 0x8d, 0xf8, 0xa, 0xff, 0xfe, 0xd3, 0x20, 0xe, 0x0, 0xfe, 0x5b, 0xf4, + 0xa, 0xff, 0xfe, 0xfe, 0x44, 0x6, 0x0, 0xfd, 0x2, 0xb9, 0xfe, 0x1d, + 0xff, 0xfe, 0xa8, 0x16, 0x7, 0x0, 0xfe, 0x23, 0xeb, 0xa, 0xff, 0xfe, + 0xf2, 0x76, 0xb, 0x0, 0xfe, 0x14, 0xb3, 0xb, 0xff, 0xfe, 0xc1, 0x1b, + 0x2, 0x0, 0xfe, 0x2, 0x5, 0x17, 0x4, 0xff, 0x3, 0x16, 0x0, 0xfe, + 0x32, 0xe4, 0xb, 0xff, 0xfe, 0xcf, 0x30, 0x5, 0x0, 0xff, 0xb9, 0xa, + 0xff, 0xfd, 0xfd, 0xab, 0x4, 0xd, 0x0, 0xfd, 0x5, 0x7e, 0xfd, 0xa, + 0xff, 0xfe, 0xe4, 0x29, 0x7, 0x0, 0xff, 0x7e, 0x1e, 0xff, 0xfd, 0xfd, + 0x70, 0x9, 0x6, 0x0, 0xfe, 0x50, 0xf4, 0xa, 0xff, 0xfe, 0xed, 0x5c, + 0xb, 0x0, 0xfe, 0x33, 0xce, 0xb, 0xff, 0xfe, 0x9e, 0xe, 0x31, 0x0, + 0xfe, 0x9, 0x82, 0xc, 0xff, 0xfe, 0xac, 0x18, 0x4, 0x0, 0xfe, 0x18, + 0xd1, 0xa, 0xff, 0xfe, 0xfb, 0x87, 0xe, 0x0, 0xfe, 0x11, 0x9f, 0xb, + 0xff, 0xfe, 0xc7, 0x1f, 0x7, 0x0, 0xfe, 0x26, 0xe9, 0x1e, 0xff, 0xfe, + 0xbe, 0x1b, 0x6, 0x0, 0xfe, 0x7c, 0xf9, 0xa, 0xff, 0xfe, 0xea, 0x4b, + 0xb, 0x0, 0xfe, 0x4f, 0xe8, 0xb, 0xff, 0xfe, 0x7b, 0x9, 0x31, 0x0, + 0xfe, 0x32, 0xe7, 0xc, 0xff, 0xfe, 0x79, 0x5, 0x4, 0x0, 0xfe, 0x36, + 0xdb, 0xa, 0xff, 0xfe, 0xf8, 0x6b, 0xe, 0x0, 0xfe, 0x20, 0xb8, 0xb, + 0xff, 0xfe, 0xb6, 0x1a, 0x8, 0x0, 0xfe, 0x67, 0xfc, 0x1d, 0xff, 0xfe, + 0xe8, 0x3a, 0x6, 0x0, 0xfe, 0xa3, 0xfc, 0xa, 0xff, 0xfe, 0xdb, 0x38, + 0xb, 0x0, 0xfe, 0x68, 0xfc, 0xa, 0xff, 0xfd, 0xfb, 0x5e, 0x4, 0x30, + 0x0, 0xfe, 0xe, 0xa4, 0xc, 0xff, 0xfe, 0xda, 0x38, 0x5, 0x0, 0xfe, + 0x49, 0xe3, 0xa, 0xff, 0xfe, 0xf3, 0x5a, 0xe, 0x0, 0xfe, 0x35, 0xd3, + 0xb, 0xff, 0xfe, 0x9b, 0x12, 0x8, 0x0, 0xfd, 0x7, 0x6a, 0xd9, 0x1c, + 0xff, 0xfd, 0xfd, 0x62, 0x5, 0x4, 0x0, 0xfd, 0x5, 0xc5, 0xfe, 0xa, + 0xff, 0xfe, 0xc2, 0x14, 0xa, 0x0, 0xfe, 0x1, 0x8a, 0xb, 0xff, 0xfd, + 0xea, 0x39, 0x1, 0x2f, 0x0, 0xfd, 0x3, 0x85, 0xf7, 0xc, 0xff, 0xfe, + 0x88, 0x7, 0x5, 0x0, 0xfe, 0x52, 0xe7, 0xa, 0xff, 0xfe, 0xf3, 0x58, + 0xe, 0x0, 0xfe, 0x51, 0xe9, 0xb, 0xff, 0xfe, 0x75, 0x6, 0x9, 0x0, + 0xfc, 0x4, 0x38, 0x93, 0xda, 0x1b, 0xff, 0xfe, 0x78, 0xa, 0x4, 0x0, + 0xfe, 0x25, 0xdb, 0xa, 0xff, 0xfd, 0xfc, 0xa6, 0x1, 0xa, 0x0, 0xfe, + 0x16, 0xac, 0xb, 0xff, 0xfe, 0xd2, 0x1e, 0x2f, 0x0, 0xfd, 0xb, 0x89, + 0xf1, 0xc, 0xff, 0xfe, 0xe2, 0x3f, 0x6, 0x0, 0xfe, 0x54, 0xe9, 0xa, + 0xff, 0xfe, 0xf8, 0x6a, 0xe, 0x0, 0xfe, 0x6f, 0xfc, 0xb, 0xff, 0xff, + 0x4f, 0xc, 0x0, 0xfa, 0x10, 0x32, 0x5c, 0x82, 0x97, 0xa1, 0x8, 0xa2, + 0xfd, 0x9f, 0xa3, 0xd8, 0xc, 0xff, 0xfe, 0x7c, 0xa, 0x4, 0x0, 0xfe, + 0x49, 0xeb, 0xa, 0xff, 0xfe, 0xf7, 0x89, 0xb, 0x0, 0xfe, 0x2e, 0xc8, + 0xb, 0xff, 0xfe, 0xb3, 0x15, 0x2d, 0x0, 0xfc, 0x2, 0x38, 0xa2, 0xf5, + 0xd, 0xff, 0xfe, 0x8b, 0x8, 0x6, 0x0, 0xfe, 0x54, 0xe8, 0xa, 0xff, + 0xfe, 0xfc, 0x9a, 0xd, 0x0, 0xfe, 0x8, 0x8d, 0xb, 0xff, 0xfe, 0xef, + 0x36, 0xf, 0x0, 0xfd, 0xa, 0x11, 0x14, 0x8, 0x15, 0xfc, 0x14, 0x15, + 0x42, 0xcb, 0xb, 0xff, 0xfe, 0x73, 0x8, 0x4, 0x0, 0xfe, 0x6d, 0xf5, + 0xa, 0xff, 0xfe, 0xf0, 0x67, 0xb, 0x0, 0xfe, 0x3e, 0xd9, 0xb, 0xff, + 0xfe, 0x90, 0xe, 0x2b, 0x0, 0xfb, 0x14, 0x4c, 0xa2, 0xdf, 0xfb, 0xd, + 0xff, 0xfe, 0xd7, 0x37, 0x7, 0x0, 0xfe, 0x50, 0xe7, 0xb, 0xff, 0xfe, + 0xdf, 0x33, 0xc, 0x0, 0xfe, 0x18, 0xab, 0xb, 0xff, 0xfe, 0xc7, 0x23, + 0x1c, 0x0, 0xfe, 0x4, 0x98, 0xa, 0xff, 0xfd, 0xfa, 0x5d, 0x2, 0x4, + 0x0, 0xfe, 0x95, 0xfa, 0xa, 0xff, 0xfe, 0xe1, 0x3c, 0xb, 0x0, 0xfe, + 0x4b, 0xe7, 0xb, 0xff, 0xfe, 0x66, 0x6, 0x25, 0x0, 0xf7, 0x4, 0xf, + 0x23, 0x3d, 0x5e, 0x8c, 0xba, 0xe7, 0xfc, 0xf, 0xff, 0xfe, 0x7e, 0x5, + 0x7, 0x0, 0xfe, 0x46, 0xe2, 0xb, 0xff, 0xfd, 0xfd, 0xb9, 0x14, 0xb, + 0x0, 0xfe, 0x2b, 0xc5, 0xb, 0xff, 0xfe, 0xa2, 0x15, 0x1c, 0x0, 0xfe, + 0x12, 0xa8, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0x4, 0x0, 0xfd, 0x5, 0xb3, + 0xfd, 0xa, 0xff, 0xfe, 0xd2, 0x15, 0xb, 0x0, 0xfe, 0x5c, 0xf6, 0xa, + 0xff, 0xfd, 0xf9, 0x3f, 0x1, 0xe, 0x0, 0xfd, 0x24, 0x92, 0xb7, 0x13, + 0xae, 0xf9, 0xb1, 0xb6, 0xbd, 0xcb, 0xde, 0xec, 0xf7, 0x11, 0xff, 0xfe, + 0xb6, 0x1c, 0x8, 0x0, 0xfe, 0x29, 0xd8, 0xc, 0xff, 0xfc, 0xfa, 0xb5, + 0x3f, 0x2, 0x9, 0x0, 0xfe, 0x38, 0xdc, 0xb, 0xff, 0xfe, 0x81, 0x9, + 0x1c, 0x0, 0xfe, 0x3f, 0xe1, 0xa, 0xff, 0xfe, 0xcc, 0x24, 0x4, 0x0, + 0xfe, 0x1e, 0xcd, 0xb, 0xff, 0xfe, 0xba, 0x1, 0xa, 0x0, 0xfd, 0x1, + 0x7b, 0xfe, 0xa, 0xff, 0xfe, 0xe3, 0x25, 0xf, 0x0, 0xfd, 0x4b, 0xea, + 0xff, 0x14, 0xfe, 0x16, 0xff, 0xfe, 0xca, 0x2f, 0x9, 0x0, 0xfe, 0x4, + 0xba, 0xd, 0xff, 0xf9, 0xfd, 0xe4, 0xca, 0xa9, 0x84, 0x72, 0x6e, 0x3, + 0x6f, 0xfc, 0x6d, 0x6b, 0xa1, 0xf8, 0xb, 0xff, 0xfe, 0x5e, 0x1, 0x6, + 0x0, 0xfd, 0x2c, 0x71, 0x6f, 0x10, 0x6d, 0xfb, 0x6c, 0x6d, 0x94, 0xda, + 0xfd, 0xa, 0xff, 0xfe, 0xa3, 0x15, 0x4, 0x0, 0xfe, 0x3e, 0xea, 0xa, + 0xff, 0xfe, 0xf9, 0x93, 0xb, 0x0, 0xfe, 0x12, 0x9f, 0xb, 0xff, 0xfe, + 0xbb, 0x19, 0xf, 0x0, 0xfe, 0x68, 0xf8, 0x2a, 0xff, 0xfd, 0xe7, 0x52, + 0x1, 0xa, 0x0, 0xfe, 0x7e, 0xf5, 0xf, 0xff, 0xfe, 0xfd, 0xf6, 0x5, + 0xf2, 0x2, 0xf1, 0xff, 0xf7, 0xb, 0xff, 0xfe, 0xed, 0x44, 0x7, 0x0, + 0xfd, 0x7c, 0xed, 0xf2, 0x12, 0xf1, 0xff, 0xf9, 0xc, 0xff, 0xfe, 0x6f, + 0x4, 0x4, 0x0, 0xfe, 0x5c, 0xf3, 0xa, 0xff, 0xfe, 0xf2, 0x6c, 0xb, + 0x0, 0xfe, 0x23, 0xbd, 0xb, 0xff, 0xfe, 0x99, 0x10, 0xe, 0x0, 0xfd, + 0x9, 0x88, 0xfe, 0x29, 0xff, 0xfd, 0xf4, 0x72, 0x6, 0xb, 0x0, 0xfe, + 0x26, 0xe2, 0x24, 0xff, 0xfe, 0xcf, 0x2e, 0x6, 0x0, 0xfd, 0x4, 0xa0, + 0xfd, 0x1f, 0xff, 0xfe, 0xe1, 0x31, 0x5, 0x0, 0xfe, 0x73, 0xf6, 0xa, + 0xff, 0xfe, 0xec, 0x43, 0xb, 0x0, 0xfe, 0x38, 0xd4, 0xb, 0xff, 0xfe, + 0x81, 0xb, 0xe, 0x0, 0xfe, 0x17, 0xa9, 0x29, 0xff, 0xfd, 0xe3, 0x5c, + 0x9, 0xc, 0x0, 0xfd, 0x2, 0x7e, 0xf7, 0x23, 0xff, 0xfe, 0xae, 0x1a, + 0x6, 0x0, 0xfd, 0x15, 0xc7, 0xfe, 0x1f, 0xff, 0xfe, 0x70, 0x4, 0x5, + 0x0, 0xfe, 0x86, 0xf8, 0xa, 0xff, 0xfe, 0xde, 0x19, 0xb, 0x0, 0xfe, + 0x51, 0xea, 0xb, 0xff, 0xfe, 0x6a, 0x5, 0xe, 0x0, 0xfe, 0x2a, 0xc7, + 0x28, 0xff, 0xfd, 0xd8, 0x44, 0x5, 0xe, 0x0, 0xfd, 0xf, 0xb7, 0xfd, + 0x22, 0xff, 0xfe, 0x8d, 0xc, 0x6, 0x0, 0xfe, 0x29, 0xe9, 0x1f, 0xff, + 0xfe, 0xac, 0x1a, 0x5, 0x0, 0xfd, 0x3, 0xa1, 0xfb, 0x9, 0xff, 0xfd, + 0xfe, 0xc1, 0x1, 0xa, 0x0, 0xfd, 0x1, 0x72, 0xfa, 0xb, 0xff, 0xff, + 0x49, 0xf, 0x0, 0xfe, 0x40, 0xdd, 0x27, 0xff, 0xfd, 0xae, 0x2e, 0x2, + 0x10, 0x0, 0xfe, 0x41, 0xe7, 0x22, 0xff, 0xfe, 0x71, 0x5, 0x6, 0x0, + 0xfe, 0x48, 0xf2, 0x1e, 0xff, 0xfd, 0xd3, 0x36, 0x1, 0x5, 0x0, 0xfd, + 0x11, 0xc2, 0xfe, 0x9, 0xff, 0xfe, 0xfa, 0x9c, 0xb, 0x0, 0xfe, 0xb, + 0x92, 0xb, 0xff, 0xfe, 0xec, 0x2c, 0xf, 0x0, 0xfe, 0x60, 0xf5, 0x24, + 0xff, 0xfb, 0xfd, 0xc8, 0x65, 0xa, 0x1, 0x11, 0x0, 0xfd, 0x3, 0x4c, + 0xcd, 0x20, 0xff, 0xfe, 0xf1, 0x53, 0x7, 0x0, 0xfe, 0x66, 0xf5, 0x1d, + 0xff, 0xfd, 0xe0, 0x52, 0x2, 0x6, 0x0, 0xfe, 0x26, 0xe1, 0xa, 0xff, + 0xfe, 0xf4, 0x71, 0xb, 0x0, 0xfe, 0x19, 0xae, 0xb, 0xff, 0xfe, 0xc7, + 0x1e, 0xe, 0x0, 0xfe, 0x4, 0x81, 0x23, 0xff, 0xfb, 0xf9, 0xb7, 0x59, + 0x14, 0x4, 0x14, 0x0, 0xfc, 0x2, 0x1a, 0x92, 0xf9, 0x1e, 0xff, 0xfe, + 0xd8, 0x32, 0x7, 0x0, 0xfe, 0x7d, 0xf7, 0x1c, 0xff, 0xfd, 0xb4, 0x2d, + 0x3, 0x7, 0x0, 0xfe, 0x48, 0xee, 0xa, 0xff, 0xfe, 0xee, 0x4c, 0xb, + 0x0, 0xfe, 0x2f, 0xca, 0xb, 0xff, 0xfe, 0x9c, 0x12, 0xe, 0x0, 0xfe, + 0x11, 0xa0, 0x20, 0xff, 0xfa, 0xfd, 0xd6, 0x8f, 0x4b, 0x14, 0x2, 0x18, + 0x0, 0xfc, 0x5, 0x46, 0xa0, 0xef, 0x1c, 0xff, 0xfe, 0xc3, 0x24, 0x7, + 0x0, 0xfe, 0x9a, 0xfa, 0x1a, 0xff, 0xfc, 0xdc, 0x70, 0x15, 0x1, 0x8, + 0x0, 0xfe, 0x6f, 0xf4, 0xa, 0xff, 0xfe, 0xec, 0x3a, 0xb, 0x0, 0xfe, + 0x49, 0xe2, 0xb, 0xff, 0xfe, 0x78, 0x7, 0xe, 0x0, 0xfc, 0x1e, 0xae, + 0xf6, 0xe4, 0x14, 0xe5, 0x2, 0xe4, 0xf4, 0xe2, 0xdf, 0xdb, 0xd3, 0xcb, + 0xbc, 0x99, 0x6a, 0x3d, 0x15, 0x6, 0x1, 0x1b, 0x0, 0xf6, 0x1, 0x9, + 0x2b, 0x66, 0x9f, 0xc6, 0xd5, 0xe0, 0xe5, 0xe6, 0x13, 0xe7, 0xfc, 0xe8, + 0xf6, 0xa0, 0x17, 0x6, 0x0, 0xfc, 0x3, 0xaa, 0xe9, 0xe8, 0x14, 0xe7, + 0xf9, 0xe4, 0xdd, 0xd1, 0xa7, 0x57, 0x18, 0x3, 0xa, 0x0, 0xff, 0x84, + 0x2, 0xe8, 0x8, 0xe7, 0xfd, 0xea, 0xd1, 0x23, 0xb, 0x0, 0xfc, 0x5c, + 0xe4, 0xf0, 0xe6, 0x7, 0xe7, 0xfd, 0xe9, 0xf0, 0x4e, 0x7f, 0x0, 0x7f, + 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, + 0x0, 0x7f, 0x0, 0x38, 0x0}; +static const Image dash_screensaver_image = {199, 64, 2837, + dash_screensaver_data}; const VariantAnimation dash_screensaver = { 114, @@ -204,8 +652,7 @@ const VariantAnimation dash_screensaver = { {27, 0, 125, 100, &dash_screensaver_image}, {28, 0, 125, 100, &dash_screensaver_image}, {29, 0, 125, 100, &dash_screensaver_image}, - } -}; + }}; VariantInfo dash_svi __attribute__((section("variant_info"))) = { .version = 1, @@ -213,6 +660,4 @@ VariantInfo dash_svi __attribute__((section("variant_info"))) = { .logo = &dash_logo, .logo_reversed = &dash_logo_reversed, .screensaver_timeout = ONE_SEC * 60 * 10, - .screensaver = &dash_screensaver -}; - + .screensaver = &dash_screensaver}; diff --git a/tools/variant/fox.c b/tools/variant/fox.c index 937939a75..0de5bd181 100644 --- a/tools/variant/fox.c +++ b/tools/variant/fox.c @@ -21,69 +21,296 @@ #include "keepkey/board/timer.h" -const uint8_t fox_logo_data[2432] = -{ - 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x55, 0x0, 0xfe, 0xa, 0x7, 0x10, 0x0, 0xfd, 0x1, 0xa, 0x4, 0x7f, 0x0, 0x6b, 0x0, 0xfb, 0x1, 0x23, 0x35, 0x1c, 0x6, 0xc, 0x0, 0xfb, 0x1, 0x11, 0x30, 0x44, 0x13, 0x7f, 0x0, 0x6c, 0x0, 0xf9, 0x1b, 0x50, 0x52, 0x40, 0x24, 0xe, 0x3, 0x7, 0x1, 0xf9, 0x5, 0x16, 0x33, 0x54, 0x65, 0x52, 0xb, 0x7f, 0x0, 0x6c, 0x0, 0xfe, 0x10, 0x51, 0x2, 0x60, 0xfb, 0x59, 0x49, 0x35, 0x26, 0x23, 0x3, 0x1f, 0xf7, 0x23, 0x2a, 0x3d, 0x58, 0x63, 0x64, 0x62, 0x44, 0x6, 0x7f, 0x0, 0x6c, 0x0, 0xfe, 0x9, 0x48, 0x4, 0x60, 0xf6, 0x5f, 0x5b, 0x59, 0x51, 0x4e, 0x54, 0x5a, 0x5d, 0x60, 0x63, 0x3, 0x60, 0xfe, 0x33, 0x2, 0x7f, 0x0, 0x6c, 0x0, 0xfd, 0x4, 0x3b, 0x5e, 0x6, 0x60, 0xfe, 0x5d, 0x5c, 0x7, 0x60, 0xfe, 0x5b, 0x24, 0x7f, 0x0, 0x6d, 0x0, 0xfd, 0x2, 0x2f, 0x5d, 0xf, 0x60, 0xfe, 0x56, 0x18, 0x7f, 0x0, 0x6e, 0x0, 0xfc, 0x22, 0x59, 0x60, 0x5e, 0xb, 0x60, 0xfc, 0x5e, 0x60, 0x4f, 0xe, 0x7f, 0x0, 0x6e, 0x0, 0xfc, 0x1b, 0x56, 0x5a, 0x5c, 0xa, 0x60, 0xfb, 0x5e, 0x5a, 0x5d, 0x41, 0x5, 0x7f, 0x0, 0x6e, 0x0, 0xfd, 0x11, 0x4b, 0x59, 0xc, 0x60, 0xfc, 0x5c, 0x57, 0x2c, 0x3, 0x7f, 0x0, 0x6e, 0x0, 0xfd, 0x1b, 0x54, 0x5f, 0xd, 0x60, 0xfd, 0x59, 0x2c, 0x2, 0xa, 0x0, 0xfe, 0x4, 0x17, 0x3, 0x1c, 0xff, 0xe, 0x6, 0x0, 0xfe, 0x9, 0x4, 0x35, 0x0, 0xfe, 0x4, 0x17, 0x3, 0x1c, 0xff, 0xe, 0x6, 0x0, 0xfe, 0x9, 0x4, 0x7f, 0x0, 0x13, 0x0, 0xfe, 0x31, 0x5e, 0xe, 0x60, 0xfd, 0x5f, 0x54, 0x19, 0x8, 0x0, 0xfc, 0x4, 0x41, 0x87, 0xbb, 0x2, 0xca, 0xfc, 0xc7, 0xad, 0x7e, 0x2e, 0x3, 0x0, 0xfd, 0x3c, 0x93, 0x45, 0x33, 0x0, 0xfc, 0x4, 0x41, 0x87, 0xbb, 0x2, 0xca, 0xfc, 0xc7, 0xad, 0x7e, 0x2e, 0x3, 0x0, 0xfd, 0x3c, 0x93, 0x45, 0xa, 0x0, 0xfe, 0x23, 0x21, 0x5, 0x0, 0xfd, 0x3f, 0x8b, 0x79, 0x7d, 0x0, 0xfe, 0x9, 0x47, 0x10, 0x60, 0xfe, 0x64, 0x31, 0x8, 0x0, 0xf0, 0x76, 0xdb, 0xec, 0xdd, 0xd3, 0xcd, 0xd6, 0xe0, 0xec, 0xcd, 0x72, 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x33, 0x0, 0xf0, 0x76, 0xdb, 0xec, 0xdd, 0xd3, 0xcd, 0xd6, 0xe0, 0xec, 0xcd, 0x72, 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x9, 0x0, 0xfc, 0x25, 0xc6, 0xcb, 0x25, 0x3, 0x0, 0xfc, 0x76, 0xec, 0xee, 0x85, 0x7d, 0x0, 0xfe, 0x19, 0x57, 0x10, 0x60, 0xfd, 0x63, 0x4a, 0x8, 0x6, 0x0, 0xef, 0x60, 0xdb, 0xe0, 0x96, 0x45, 0x1c, 0xe, 0x25, 0x4a, 0xa6, 0xe2, 0xdb, 0x41, 0x4, 0x76, 0xe6, 0x7a, 0x32, 0x0, 0xef, 0x60, 0xdb, 0xe0, 0x96, 0x45, 0x1c, 0xe, 0x25, 0x4a, 0xa6, 0xe2, 0xdb, 0x41, 0x4, 0x76, 0xe6, 0x7a, 0x9, 0x0, 0xfc, 0x25, 0xbf, 0xc6, 0x25, 0x2, 0x0, 0xfc, 0x11, 0xe0, 0xd2, 0x43, 0x4, 0x0, 0xfe, 0x9f, 0xad, 0x77, 0x0, 0xfd, 0x1, 0x1e, 0x56, 0xf, 0x60, 0xfc, 0x61, 0x65, 0x4b, 0xc, 0x5, 0x0, 0xfb, 0x4, 0xad, 0xe8, 0x82, 0x4, 0x5, 0x0, 0xf8, 0x12, 0x7e, 0x9e, 0x25, 0x4, 0x76, 0xe6, 0x7a, 0x31, 0x0, 0xfb, 0x4, 0xad, 0xe8, 0x82, 0x4, 0x5, 0x0, 0xf8, 0x12, 0x7e, 0x9e, 0x25, 0x4, 0x76, 0xe6, 0x7a, 0xa, 0x0, 0xfe, 0x29, 0x2f, 0x3, 0x0, 0xfd, 0x43, 0xf2, 0x8b, 0x5, 0x0, 0x2, 0xcd, 0x78, 0x0, 0xfc, 0x4, 0x3b, 0x61, 0x65, 0xc, 0x60, 0xfc, 0x64, 0x5c, 0x39, 0x12, 0x6, 0x0, 0xfc, 0x17, 0xc7, 0xdb, 0x33, 0x7, 0x0, 0xf9, 0x4, 0xe, 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x2, 0x0, 0xfd, 0x12, 0x1c, 0xe, 0x9, 0x0, 0xff, 0x12, 0x2, 0x1c, 0xff, 0x4, 0x2, 0x0, 0xfe, 0xe, 0x9, 0x2, 0x0, 0xff, 0xe, 0x3, 0x0, 0xff, 0x4, 0x2, 0x1c, 0xff, 0x4, 0x9, 0x0, 0xff, 0xe, 0x2, 0x1c, 0xff, 0x17, 0x4, 0x0, 0xfc, 0x17, 0xc7, 0xdb, 0x33, 0x7, 0x0, 0xf9, 0x4, 0xe, 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x2, 0x0, 0xfd, 0x12, 0x1c, 0xe, 0xa, 0x0, 0xfd, 0x58, 0xf4, 0x6a, 0x5, 0x0, 0xfe, 0xcb, 0xd0, 0x77, 0x0, 0xfc, 0x4, 0x27, 0x54, 0x60, 0x2, 0x64, 0xff, 0x62, 0x8, 0x60, 0xfb, 0x61, 0x62, 0x4e, 0x22, 0x4, 0x7, 0x0, 0xfc, 0x12, 0xc1, 0xe4, 0x60, 0xa, 0x0, 0xf5, 0x4, 0x76, 0xe6, 0x7a, 0x2a, 0x72, 0xb0, 0xc4, 0xb0, 0x76, 0x20, 0x4, 0x0, 0xe9, 0x4, 0x38, 0x87, 0xb4, 0xc4, 0xc1, 0x96, 0x41, 0x17, 0x8b, 0x8f, 0x17, 0x5c, 0xa2, 0x33, 0xe, 0x58, 0xa2, 0xc1, 0xbe, 0x96, 0x4a, 0x4, 0x5, 0x0, 0xfd, 0x2a, 0x76, 0xb0, 0x2, 0xc4, 0xfd, 0xbb, 0x82, 0x38, 0x2, 0x0, 0xfc, 0x12, 0xc1, 0xe4, 0x60, 0xa, 0x0, 0xf5, 0x4, 0x76, 0xe6, 0x7a, 0x2a, 0x72, 0xb0, 0xc4, 0xb0, 0x76, 0x20, 0x3, 0x0, 0xee, 0x51, 0x4f, 0x0, 0x3f, 0x6d, 0xaf, 0xf4, 0xbd, 0x70, 0x43, 0x4, 0x6a, 0x7f, 0xe5, 0xe9, 0x7f, 0x64, 0xd, 0x73, 0x0, 0xfd, 0x9, 0x3a, 0x5d, 0x4, 0x60, 0xff, 0x5e, 0x7, 0x60, 0x2, 0x63, 0xfe, 0x41, 0x11, 0xa, 0x0, 0xfb, 0x82, 0xe8, 0xd0, 0x6d, 0x25, 0x8, 0x0, 0xfa, 0x4, 0x76, 0xe6, 0xa2, 0xb0, 0xdb, 0x2, 0xd3, 0xfc, 0xe4, 0xe6, 0xa6, 0x1c, 0x3, 0x0, 0xfc, 0x69, 0xca, 0xea, 0xdb, 0x2, 0xcd, 0xee, 0xe2, 0xcd, 0x7e, 0xca, 0xd6, 0x2e, 0x93, 0xe6, 0x76, 0xa6, 0xe2, 0xe4, 0xd3, 0xdd, 0xe8, 0xdd, 0x96, 0x17, 0x3, 0x0, 0xfc, 0x45, 0xbe, 0xe6, 0xd0, 0x2, 0xc1, 0xfc, 0xd3, 0xe4, 0xc4, 0x4f, 0x2, 0x0, 0xfb, 0x82, 0xe8, 0xd0, 0x6d, 0x25, 0x8, 0x0, 0xfa, 0x4, 0x76, 0xe6, 0xa2, 0xb0, 0xdb, 0x2, 0xd3, 0xfc, 0xe4, 0xe6, 0xa6, 0x1c, 0x2, 0x0, 0xf3, 0xd6, 0xcb, 0x0, 0x99, 0xe1, 0xe7, 0xf8, 0xea, 0xe4, 0x9f, 0x37, 0xdd, 0xe4, 0x2, 0xf4, 0xfd, 0xe4, 0xd9, 0x45, 0x72, 0x0, 0xfd, 0xa, 0x3a, 0x62, 0x4, 0x60, 0xfd, 0x5e, 0x57, 0x5c, 0x2, 0x61, 0xf9, 0x80, 0x88, 0x65, 0x64, 0x5b, 0x48, 0x19, 0xb, 0x0, 0xfe, 0x1c, 0xa6, 0x2, 0xe4, 0xf9, 0xd0, 0xad, 0x87, 0x60, 0x38, 0x17, 0x4, 0x2, 0x0, 0xfa, 0x4, 0x76, 0xea, 0xe2, 0xcd, 0x69, 0x2, 0x2a, 0xf5, 0x5c, 0xbb, 0xea, 0x93, 0x9, 0x0, 0x4a, 0xd3, 0xe6, 0xa2, 0x41, 0x2, 0x25, 0xe7, 0x60, 0xb0, 0xdb, 0xe6, 0xd6, 0x2e, 0x93, 0xec, 0xd6, 0xe4, 0x9e, 0x4f, 0x2a, 0x3c, 0x76, 0xca, 0xea, 0x8b, 0x4, 0x0, 0x2e, 0xbe, 0xe2, 0x96, 0x2e, 0x2, 0x12, 0xf8, 0x2e, 0x87, 0xdd, 0xc1, 0x20, 0x0, 0x1c, 0xa6, 0x2, 0xe4, 0xf9, 0xd0, 0xad, 0x87, 0x60, 0x38, 0x17, 0x4, 0x2, 0x0, 0xfa, 0x4, 0x76, 0xea, 0xe2, 0xcd, 0x69, 0x2, 0x2a, 0xe9, 0x5c, 0xbb, 0xea, 0x93, 0x9, 0x0, 0xdd, 0xcd, 0x0, 0x1, 0x13, 0x7c, 0xf4, 0x8e, 0x1b, 0x7, 0x0, 0x11, 0x33, 0xd4, 0xd6, 0x37, 0x11, 0x72, 0x0, 0xfe, 0x10, 0x3e, 0x2, 0x61, 0x5, 0x60, 0xf5, 0x59, 0x55, 0x61, 0x76, 0xc5, 0xd8, 0x96, 0x5b, 0x49, 0x32, 0x9, 0xc, 0x0, 0xfc, 0x12, 0x5c, 0xa2, 0xc7, 0x2, 0xe0, 0xf5, 0xe2, 0xdd, 0xc1, 0x8b, 0x33, 0x0, 0x4, 0x76, 0xec, 0xdd, 0x60, 0x4, 0x0, 0xf7, 0x45, 0xd8, 0xcd, 0x2a, 0x9, 0x9e, 0xe6, 0x87, 0xe, 0x4, 0x0, 0xf6, 0x25, 0xbe, 0xee, 0xd6, 0x2e, 0x93, 0xee, 0xe6, 0x82, 0x12, 0x4, 0x0, 0xf7, 0x4a, 0xd8, 0xd3, 0x38, 0x0, 0x87, 0xe8, 0x93, 0x12, 0x4, 0x0, 0xfc, 0x9, 0x93, 0xe8, 0x69, 0x2, 0x0, 0xfc, 0x12, 0x5c, 0xa2, 0xc7, 0x2, 0xe0, 0xf5, 0xe2, 0xdd, 0xc1, 0x8b, 0x33, 0x0, 0x4, 0x76, 0xec, 0xdd, 0x60, 0x4, 0x0, 0xf9, 0x45, 0xd8, 0xcd, 0x2a, 0x9, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfd, 0xd, 0x46, 0x64, 0x7, 0x60, 0xf6, 0x5e, 0x53, 0x55, 0x89, 0xea, 0xef, 0xbf, 0x54, 0x3c, 0x1f, 0xf, 0x0, 0xf1, 0x9, 0x1c, 0x3c, 0x5c, 0x87, 0xb4, 0xdb, 0xea, 0xbb, 0x38, 0x4, 0x76, 0xea, 0xa2, 0x9, 0x4, 0x0, 0xfb, 0x9, 0xb0, 0xe0, 0x4a, 0x25, 0x2, 0xd0, 0xff, 0x2e, 0x6, 0x0, 0xf8, 0x69, 0xe4, 0xd6, 0x2e, 0x93, 0xee, 0xc4, 0x20, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe4, 0x6d, 0x1c, 0xc4, 0xdb, 0x3c, 0x6, 0x0, 0xfd, 0x45, 0xdd, 0x9e, 0x4, 0x0, 0xf1, 0x9, 0x1c, 0x3c, 0x5c, 0x87, 0xb4, 0xdb, 0xea, 0xbb, 0x38, 0x4, 0x76, 0xea, 0xa2, 0x9, 0x4, 0x0, 0xf9, 0x9, 0xb0, 0xe0, 0x4a, 0x25, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1b, 0x5e, 0x8, 0x60, 0xf9, 0x5f, 0x56, 0x50, 0x57, 0xa4, 0xc7, 0x70, 0x2, 0x39, 0xff, 0x12, 0x14, 0x0, 0xf7, 0x4, 0x4f, 0xbe, 0xec, 0xad, 0x12, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xad, 0xe, 0x6, 0x0, 0xf8, 0x33, 0xd8, 0xd6, 0x2e, 0x93, 0xee, 0xa2, 0x9, 0x6, 0x0, 0xf9, 0x60, 0xe4, 0x87, 0x2a, 0xd6, 0xe4, 0xb7, 0x6, 0xb0, 0xfd, 0xbe, 0xea, 0xb7, 0x9, 0x0, 0xf7, 0x4, 0x4f, 0xbe, 0xec, 0xad, 0x12, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1b, 0x5e, 0x9, 0x60, 0xf7, 0x5b, 0x51, 0x4f, 0x5c, 0x60, 0x3d, 0x3f, 0x2e, 0x7, 0x16, 0x0, 0xf9, 0x4a, 0xe0, 0xd6, 0x2e, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xa6, 0x4, 0x6, 0x0, 0xff, 0x20, 0x2, 0xd6, 0xfb, 0x2e, 0x93, 0xee, 0x96, 0x9, 0x6, 0x0, 0xf9, 0x60, 0xe4, 0x8b, 0x2a, 0xd6, 0xe6, 0xc7, 0x7, 0xc4, 0xfe, 0xc1, 0x93, 0xb, 0x0, 0xf9, 0x4a, 0xe0, 0xd6, 0x2e, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1b, 0x5e, 0xa, 0x60, 0xff, 0x55, 0x2, 0x50, 0xfc, 0x42, 0x40, 0x3f, 0x1f, 0xd, 0x0, 0xfe, 0x2e, 0x20, 0x8, 0x0, 0xf9, 0x20, 0xd3, 0xdd, 0x33, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x2e, 0xd8, 0xbb, 0xe, 0x6, 0x0, 0xf8, 0x45, 0xe2, 0xd6, 0x2e, 0x93, 0xee, 0xb0, 0x12, 0x5, 0x0, 0xf8, 0x4, 0x87, 0xe6, 0x7e, 0x17, 0xc4, 0xd3, 0x41, 0x9, 0x1c, 0xfd, 0x0, 0x2e, 0x20, 0x8, 0x0, 0xf9, 0x20, 0xd3, 0xdd, 0x33, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x2e, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1c, 0x5e, 0x7, 0x60, 0xfc, 0x5d, 0x5e, 0x60, 0x58, 0x2, 0x50, 0xfc, 0x47, 0x40, 0x36, 0xe, 0xc, 0x0, 0xfc, 0x4f, 0xd3, 0xb7, 0x33, 0x7, 0x0, 0xf9, 0x60, 0xe4, 0xc4, 0x17, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x12, 0xbb, 0xe2, 0x65, 0x6, 0x0, 0xf8, 0x8f, 0xea, 0xd6, 0x2e, 0x93, 0xee, 0xdb, 0x58, 0x5, 0x0, 0xf7, 0x25, 0xbe, 0xe0, 0x53, 0x0, 0x9a, 0xe6, 0x7e, 0x9, 0x5, 0x0, 0xf9, 0x12, 0x4, 0x0, 0x4f, 0xd3, 0xb7, 0x33, 0x7, 0x0, 0xf9, 0x60, 0xe4, 0xc4, 0x17, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x12, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xcb, 0xd2, 0x73, 0x0, 0xfd, 0x1c, 0x5d, 0x61, 0x5, 0x60, 0xf5, 0x5d, 0x58, 0x55, 0x5a, 0x5b, 0x52, 0x50, 0x47, 0x3f, 0x28, 0x3, 0xc, 0x0, 0xfa, 0x33, 0xc4, 0xe8, 0xbb, 0x5c, 0x17, 0x3, 0x4, 0xf7, 0xe, 0x5c, 0xc7, 0xec, 0x8b, 0x9, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf6, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0x65, 0xe4, 0xc7, 0x4a, 0x9, 0x2, 0x4, 0xf4, 0x12, 0x76, 0xdb, 0xec, 0xd6, 0x2e, 0x93, 0xee, 0xea, 0xc4, 0x4a, 0x9, 0x2, 0x4, 0xf5, 0x33, 0xb0, 0xec, 0xb4, 0x1c, 0x0, 0x4a, 0xd3, 0xd8, 0x6d, 0xe, 0x3, 0x4, 0xf6, 0x45, 0xa2, 0x76, 0x4, 0x33, 0xc4, 0xe8, 0xbb, 0x5c, 0x17, 0x3, 0x4, 0xf7, 0xe, 0x5c, 0xc7, 0xec, 0x8b, 0x9, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfd, 0xb3, 0xe5, 0x37, 0x72, 0x0, 0xfd, 0x9, 0x40, 0x66, 0x6, 0x60, 0xfc, 0x5f, 0x5b, 0x56, 0x54, 0x2, 0x50, 0xfc, 0x47, 0x3e, 0x19, 0x1, 0xd, 0x0, 0xef, 0x4a, 0xbe, 0xee, 0xe2, 0xc1, 0x9a, 0x93, 0xa9, 0xc4, 0xe2, 0xea, 0xa6, 0x20, 0x4, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xe2, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0x9, 0x9a, 0xee, 0xd8, 0xa2, 0x8b, 0x93, 0xb7, 0xe4, 0xb7, 0xdd, 0xd6, 0x2e, 0x93, 0xe6, 0xbb, 0xd3, 0xdd, 0xb4, 0x93, 0xa9, 0xd6, 0xec, 0xbe, 0x41, 0x3, 0x0, 0xf6, 0x7e, 0xe6, 0xe4, 0xbe, 0xa2, 0x9e, 0xbb, 0xdd, 0xe2, 0x7e, 0x2, 0x0, 0xef, 0x4a, 0xbe, 0xee, 0xe2, 0xc1, 0x9a, 0x93, 0xa9, 0xc4, 0xe2, 0xea, 0xa6, 0x20, 0x4, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfb, 0x5e, 0xe7, 0xcd, 0x8b, 0x11, 0x71, 0x0, 0xfd, 0x14, 0x52, 0x64, 0x7, 0x60, 0xf9, 0x5f, 0x5c, 0x6b, 0x5d, 0x43, 0x33, 0xa, 0xf, 0x0, 0xfb, 0x2a, 0x87, 0xc4, 0xdd, 0xe4, 0x3, 0xe2, 0xf8, 0xc7, 0x7e, 0x17, 0x0, 0x4, 0x6d, 0xd6, 0x69, 0x5, 0x0, 0xfc, 0x4, 0x82, 0xd0, 0x53, 0x2, 0x0, 0xfc, 0x12, 0x7e, 0xc1, 0xdb, 0x2, 0xdd, 0xf5, 0xc7, 0x7a, 0x33, 0xbe, 0xc1, 0x2a, 0x93, 0xe6, 0x65, 0x4a, 0xb0, 0x2, 0xdd, 0xfc, 0xe0, 0xd0, 0x9e, 0x33, 0x4, 0x0, 0xfc, 0x4, 0x58, 0xb4, 0xd8, 0x2, 0xe0, 0xfc, 0xd3, 0xb4, 0x69, 0xe, 0x3, 0x0, 0xfb, 0x2a, 0x87, 0xc4, 0xdd, 0xe4, 0x3, 0xe2, 0xf8, 0xc7, 0x7e, 0x17, 0x0, 0x4, 0x6d, 0xd6, 0x69, 0x5, 0x0, 0xf9, 0x4, 0x82, 0xd0, 0x53, 0x0, 0xad, 0xa4, 0x3, 0x0, 0xfd, 0x43, 0xd4, 0x49, 0x6, 0x0, 0xfc, 0x82, 0xd6, 0xe1, 0x4b, 0x71, 0x0, 0xfc, 0x1, 0x29, 0x65, 0x62, 0x6, 0x60, 0xf9, 0x5e, 0x7a, 0xc6, 0xb4, 0x69, 0x25, 0x3, 0x11, 0x0, 0xf8, 0x1c, 0x3c, 0x60, 0x69, 0x58, 0x3c, 0x1c, 0x4, 0x3, 0x0, 0xfd, 0x9, 0x25, 0xe, 0x6, 0x0, 0xfd, 0x12, 0x25, 0x9, 0x4, 0x0, 0xfb, 0x20, 0x41, 0x4a, 0x41, 0x25, 0x2, 0x0, 0xf3, 0x20, 0x25, 0x9, 0x93, 0xe6, 0x5c, 0x0, 0x12, 0x38, 0x4a, 0x3c, 0x20, 0xe, 0x7, 0x0, 0xfa, 0x12, 0x33, 0x4a, 0x41, 0x2a, 0x12, 0x7, 0x0, 0xf8, 0x1c, 0x3c, 0x60, 0x69, 0x58, 0x3c, 0x1c, 0x4, 0x3, 0x0, 0xfd, 0x9, 0x25, 0xe, 0x6, 0x0, 0xfc, 0x12, 0x25, 0x9, 0x0, 0x2, 0x25, 0x3, 0x0, 0xfd, 0xe, 0x25, 0xe, 0x8, 0x0, 0xff, 0x13, 0x73, 0x0, 0xfd, 0x7, 0x46, 0x64, 0x5, 0x60, 0xfd, 0x5f, 0x6c, 0xb9, 0x2, 0xef, 0xfc, 0xda, 0x8a, 0x35, 0x5, 0x34, 0x0, 0xfc, 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x39, 0x0, 0xfd, 0x1b, 0x58, 0x61, 0x4, 0x60, 0xfd, 0x66, 0xa7, 0xe9, 0x3, 0xf0, 0xfc, 0xeb, 0xc4, 0x73, 0x14, 0x33, 0x0, 0xfc, 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x39, 0x0, 0xfd, 0x2, 0x35, 0x64, 0x3, 0x60, 0xfd, 0x5e, 0x9a, 0xe2, 0x6, 0xf0, 0xfe, 0xd7, 0x3d, 0x33, 0x0, 0xfc, 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x3a, 0x0, 0xf9, 0xd, 0x4d, 0x64, 0x60, 0x5d, 0x83, 0xd8, 0x7, 0xf0, 0xfe, 0xde, 0x43, 0x33, 0x0, 0xfc, 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x3a, 0x0, 0xfa, 0x1, 0x24, 0x5c, 0x61, 0x81, 0xce, 0x8, 0xf0, 0xfe, 0xde, 0x43, 0x34, 0x0, 0xfd, 0x4a, 0x87, 0x2e, 0x7f, 0x0, 0x3b, 0x0, 0xfb, 0x2, 0x37, 0x6e, 0xbc, 0xef, 0x7, 0xf0, 0xfd, 0xef, 0xcd, 0x37, 0x7f, 0x0, 0x73, 0x0, 0xfa, 0x11, 0x51, 0x9f, 0xc8, 0xe1, 0xef, 0x4, 0xf0, 0xfc, 0xe1, 0xa0, 0x4f, 0x9, 0x7f, 0x0, 0x74, 0x0, 0xf4, 0x8, 0x1c, 0x3d, 0x6c, 0xa2, 0xce, 0xe7, 0xe4, 0xaf, 0x5c, 0x18, 0x2, 0x7f, 0x0, 0x78, 0x0, 0xfa, 0x7, 0x17, 0x3d, 0x70, 0x67, 0x21, 0x7f, 0x0, 0x7d, 0x0, 0xff, 0x1, 0x2, 0x3, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x54, 0x0 -}; +const uint8_t fox_logo_data[2432] = { + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x55, 0x0, 0xfe, 0xa, 0x7, 0x10, 0x0, 0xfd, 0x1, 0xa, 0x4, 0x7f, + 0x0, 0x6b, 0x0, 0xfb, 0x1, 0x23, 0x35, 0x1c, 0x6, 0xc, 0x0, 0xfb, + 0x1, 0x11, 0x30, 0x44, 0x13, 0x7f, 0x0, 0x6c, 0x0, 0xf9, 0x1b, 0x50, + 0x52, 0x40, 0x24, 0xe, 0x3, 0x7, 0x1, 0xf9, 0x5, 0x16, 0x33, 0x54, + 0x65, 0x52, 0xb, 0x7f, 0x0, 0x6c, 0x0, 0xfe, 0x10, 0x51, 0x2, 0x60, + 0xfb, 0x59, 0x49, 0x35, 0x26, 0x23, 0x3, 0x1f, 0xf7, 0x23, 0x2a, 0x3d, + 0x58, 0x63, 0x64, 0x62, 0x44, 0x6, 0x7f, 0x0, 0x6c, 0x0, 0xfe, 0x9, + 0x48, 0x4, 0x60, 0xf6, 0x5f, 0x5b, 0x59, 0x51, 0x4e, 0x54, 0x5a, 0x5d, + 0x60, 0x63, 0x3, 0x60, 0xfe, 0x33, 0x2, 0x7f, 0x0, 0x6c, 0x0, 0xfd, + 0x4, 0x3b, 0x5e, 0x6, 0x60, 0xfe, 0x5d, 0x5c, 0x7, 0x60, 0xfe, 0x5b, + 0x24, 0x7f, 0x0, 0x6d, 0x0, 0xfd, 0x2, 0x2f, 0x5d, 0xf, 0x60, 0xfe, + 0x56, 0x18, 0x7f, 0x0, 0x6e, 0x0, 0xfc, 0x22, 0x59, 0x60, 0x5e, 0xb, + 0x60, 0xfc, 0x5e, 0x60, 0x4f, 0xe, 0x7f, 0x0, 0x6e, 0x0, 0xfc, 0x1b, + 0x56, 0x5a, 0x5c, 0xa, 0x60, 0xfb, 0x5e, 0x5a, 0x5d, 0x41, 0x5, 0x7f, + 0x0, 0x6e, 0x0, 0xfd, 0x11, 0x4b, 0x59, 0xc, 0x60, 0xfc, 0x5c, 0x57, + 0x2c, 0x3, 0x7f, 0x0, 0x6e, 0x0, 0xfd, 0x1b, 0x54, 0x5f, 0xd, 0x60, + 0xfd, 0x59, 0x2c, 0x2, 0xa, 0x0, 0xfe, 0x4, 0x17, 0x3, 0x1c, 0xff, + 0xe, 0x6, 0x0, 0xfe, 0x9, 0x4, 0x35, 0x0, 0xfe, 0x4, 0x17, 0x3, + 0x1c, 0xff, 0xe, 0x6, 0x0, 0xfe, 0x9, 0x4, 0x7f, 0x0, 0x13, 0x0, + 0xfe, 0x31, 0x5e, 0xe, 0x60, 0xfd, 0x5f, 0x54, 0x19, 0x8, 0x0, 0xfc, + 0x4, 0x41, 0x87, 0xbb, 0x2, 0xca, 0xfc, 0xc7, 0xad, 0x7e, 0x2e, 0x3, + 0x0, 0xfd, 0x3c, 0x93, 0x45, 0x33, 0x0, 0xfc, 0x4, 0x41, 0x87, 0xbb, + 0x2, 0xca, 0xfc, 0xc7, 0xad, 0x7e, 0x2e, 0x3, 0x0, 0xfd, 0x3c, 0x93, + 0x45, 0xa, 0x0, 0xfe, 0x23, 0x21, 0x5, 0x0, 0xfd, 0x3f, 0x8b, 0x79, + 0x7d, 0x0, 0xfe, 0x9, 0x47, 0x10, 0x60, 0xfe, 0x64, 0x31, 0x8, 0x0, + 0xf0, 0x76, 0xdb, 0xec, 0xdd, 0xd3, 0xcd, 0xd6, 0xe0, 0xec, 0xcd, 0x72, + 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x33, 0x0, 0xf0, 0x76, 0xdb, 0xec, 0xdd, + 0xd3, 0xcd, 0xd6, 0xe0, 0xec, 0xcd, 0x72, 0x0, 0x4, 0x76, 0xe6, 0x7a, + 0x9, 0x0, 0xfc, 0x25, 0xc6, 0xcb, 0x25, 0x3, 0x0, 0xfc, 0x76, 0xec, + 0xee, 0x85, 0x7d, 0x0, 0xfe, 0x19, 0x57, 0x10, 0x60, 0xfd, 0x63, 0x4a, + 0x8, 0x6, 0x0, 0xef, 0x60, 0xdb, 0xe0, 0x96, 0x45, 0x1c, 0xe, 0x25, + 0x4a, 0xa6, 0xe2, 0xdb, 0x41, 0x4, 0x76, 0xe6, 0x7a, 0x32, 0x0, 0xef, + 0x60, 0xdb, 0xe0, 0x96, 0x45, 0x1c, 0xe, 0x25, 0x4a, 0xa6, 0xe2, 0xdb, + 0x41, 0x4, 0x76, 0xe6, 0x7a, 0x9, 0x0, 0xfc, 0x25, 0xbf, 0xc6, 0x25, + 0x2, 0x0, 0xfc, 0x11, 0xe0, 0xd2, 0x43, 0x4, 0x0, 0xfe, 0x9f, 0xad, + 0x77, 0x0, 0xfd, 0x1, 0x1e, 0x56, 0xf, 0x60, 0xfc, 0x61, 0x65, 0x4b, + 0xc, 0x5, 0x0, 0xfb, 0x4, 0xad, 0xe8, 0x82, 0x4, 0x5, 0x0, 0xf8, + 0x12, 0x7e, 0x9e, 0x25, 0x4, 0x76, 0xe6, 0x7a, 0x31, 0x0, 0xfb, 0x4, + 0xad, 0xe8, 0x82, 0x4, 0x5, 0x0, 0xf8, 0x12, 0x7e, 0x9e, 0x25, 0x4, + 0x76, 0xe6, 0x7a, 0xa, 0x0, 0xfe, 0x29, 0x2f, 0x3, 0x0, 0xfd, 0x43, + 0xf2, 0x8b, 0x5, 0x0, 0x2, 0xcd, 0x78, 0x0, 0xfc, 0x4, 0x3b, 0x61, + 0x65, 0xc, 0x60, 0xfc, 0x64, 0x5c, 0x39, 0x12, 0x6, 0x0, 0xfc, 0x17, + 0xc7, 0xdb, 0x33, 0x7, 0x0, 0xf9, 0x4, 0xe, 0x0, 0x4, 0x76, 0xe6, + 0x7a, 0x2, 0x0, 0xfd, 0x12, 0x1c, 0xe, 0x9, 0x0, 0xff, 0x12, 0x2, + 0x1c, 0xff, 0x4, 0x2, 0x0, 0xfe, 0xe, 0x9, 0x2, 0x0, 0xff, 0xe, + 0x3, 0x0, 0xff, 0x4, 0x2, 0x1c, 0xff, 0x4, 0x9, 0x0, 0xff, 0xe, + 0x2, 0x1c, 0xff, 0x17, 0x4, 0x0, 0xfc, 0x17, 0xc7, 0xdb, 0x33, 0x7, + 0x0, 0xf9, 0x4, 0xe, 0x0, 0x4, 0x76, 0xe6, 0x7a, 0x2, 0x0, 0xfd, + 0x12, 0x1c, 0xe, 0xa, 0x0, 0xfd, 0x58, 0xf4, 0x6a, 0x5, 0x0, 0xfe, + 0xcb, 0xd0, 0x77, 0x0, 0xfc, 0x4, 0x27, 0x54, 0x60, 0x2, 0x64, 0xff, + 0x62, 0x8, 0x60, 0xfb, 0x61, 0x62, 0x4e, 0x22, 0x4, 0x7, 0x0, 0xfc, + 0x12, 0xc1, 0xe4, 0x60, 0xa, 0x0, 0xf5, 0x4, 0x76, 0xe6, 0x7a, 0x2a, + 0x72, 0xb0, 0xc4, 0xb0, 0x76, 0x20, 0x4, 0x0, 0xe9, 0x4, 0x38, 0x87, + 0xb4, 0xc4, 0xc1, 0x96, 0x41, 0x17, 0x8b, 0x8f, 0x17, 0x5c, 0xa2, 0x33, + 0xe, 0x58, 0xa2, 0xc1, 0xbe, 0x96, 0x4a, 0x4, 0x5, 0x0, 0xfd, 0x2a, + 0x76, 0xb0, 0x2, 0xc4, 0xfd, 0xbb, 0x82, 0x38, 0x2, 0x0, 0xfc, 0x12, + 0xc1, 0xe4, 0x60, 0xa, 0x0, 0xf5, 0x4, 0x76, 0xe6, 0x7a, 0x2a, 0x72, + 0xb0, 0xc4, 0xb0, 0x76, 0x20, 0x3, 0x0, 0xee, 0x51, 0x4f, 0x0, 0x3f, + 0x6d, 0xaf, 0xf4, 0xbd, 0x70, 0x43, 0x4, 0x6a, 0x7f, 0xe5, 0xe9, 0x7f, + 0x64, 0xd, 0x73, 0x0, 0xfd, 0x9, 0x3a, 0x5d, 0x4, 0x60, 0xff, 0x5e, + 0x7, 0x60, 0x2, 0x63, 0xfe, 0x41, 0x11, 0xa, 0x0, 0xfb, 0x82, 0xe8, + 0xd0, 0x6d, 0x25, 0x8, 0x0, 0xfa, 0x4, 0x76, 0xe6, 0xa2, 0xb0, 0xdb, + 0x2, 0xd3, 0xfc, 0xe4, 0xe6, 0xa6, 0x1c, 0x3, 0x0, 0xfc, 0x69, 0xca, + 0xea, 0xdb, 0x2, 0xcd, 0xee, 0xe2, 0xcd, 0x7e, 0xca, 0xd6, 0x2e, 0x93, + 0xe6, 0x76, 0xa6, 0xe2, 0xe4, 0xd3, 0xdd, 0xe8, 0xdd, 0x96, 0x17, 0x3, + 0x0, 0xfc, 0x45, 0xbe, 0xe6, 0xd0, 0x2, 0xc1, 0xfc, 0xd3, 0xe4, 0xc4, + 0x4f, 0x2, 0x0, 0xfb, 0x82, 0xe8, 0xd0, 0x6d, 0x25, 0x8, 0x0, 0xfa, + 0x4, 0x76, 0xe6, 0xa2, 0xb0, 0xdb, 0x2, 0xd3, 0xfc, 0xe4, 0xe6, 0xa6, + 0x1c, 0x2, 0x0, 0xf3, 0xd6, 0xcb, 0x0, 0x99, 0xe1, 0xe7, 0xf8, 0xea, + 0xe4, 0x9f, 0x37, 0xdd, 0xe4, 0x2, 0xf4, 0xfd, 0xe4, 0xd9, 0x45, 0x72, + 0x0, 0xfd, 0xa, 0x3a, 0x62, 0x4, 0x60, 0xfd, 0x5e, 0x57, 0x5c, 0x2, + 0x61, 0xf9, 0x80, 0x88, 0x65, 0x64, 0x5b, 0x48, 0x19, 0xb, 0x0, 0xfe, + 0x1c, 0xa6, 0x2, 0xe4, 0xf9, 0xd0, 0xad, 0x87, 0x60, 0x38, 0x17, 0x4, + 0x2, 0x0, 0xfa, 0x4, 0x76, 0xea, 0xe2, 0xcd, 0x69, 0x2, 0x2a, 0xf5, + 0x5c, 0xbb, 0xea, 0x93, 0x9, 0x0, 0x4a, 0xd3, 0xe6, 0xa2, 0x41, 0x2, + 0x25, 0xe7, 0x60, 0xb0, 0xdb, 0xe6, 0xd6, 0x2e, 0x93, 0xec, 0xd6, 0xe4, + 0x9e, 0x4f, 0x2a, 0x3c, 0x76, 0xca, 0xea, 0x8b, 0x4, 0x0, 0x2e, 0xbe, + 0xe2, 0x96, 0x2e, 0x2, 0x12, 0xf8, 0x2e, 0x87, 0xdd, 0xc1, 0x20, 0x0, + 0x1c, 0xa6, 0x2, 0xe4, 0xf9, 0xd0, 0xad, 0x87, 0x60, 0x38, 0x17, 0x4, + 0x2, 0x0, 0xfa, 0x4, 0x76, 0xea, 0xe2, 0xcd, 0x69, 0x2, 0x2a, 0xe9, + 0x5c, 0xbb, 0xea, 0x93, 0x9, 0x0, 0xdd, 0xcd, 0x0, 0x1, 0x13, 0x7c, + 0xf4, 0x8e, 0x1b, 0x7, 0x0, 0x11, 0x33, 0xd4, 0xd6, 0x37, 0x11, 0x72, + 0x0, 0xfe, 0x10, 0x3e, 0x2, 0x61, 0x5, 0x60, 0xf5, 0x59, 0x55, 0x61, + 0x76, 0xc5, 0xd8, 0x96, 0x5b, 0x49, 0x32, 0x9, 0xc, 0x0, 0xfc, 0x12, + 0x5c, 0xa2, 0xc7, 0x2, 0xe0, 0xf5, 0xe2, 0xdd, 0xc1, 0x8b, 0x33, 0x0, + 0x4, 0x76, 0xec, 0xdd, 0x60, 0x4, 0x0, 0xf7, 0x45, 0xd8, 0xcd, 0x2a, + 0x9, 0x9e, 0xe6, 0x87, 0xe, 0x4, 0x0, 0xf6, 0x25, 0xbe, 0xee, 0xd6, + 0x2e, 0x93, 0xee, 0xe6, 0x82, 0x12, 0x4, 0x0, 0xf7, 0x4a, 0xd8, 0xd3, + 0x38, 0x0, 0x87, 0xe8, 0x93, 0x12, 0x4, 0x0, 0xfc, 0x9, 0x93, 0xe8, + 0x69, 0x2, 0x0, 0xfc, 0x12, 0x5c, 0xa2, 0xc7, 0x2, 0xe0, 0xf5, 0xe2, + 0xdd, 0xc1, 0x8b, 0x33, 0x0, 0x4, 0x76, 0xec, 0xdd, 0x60, 0x4, 0x0, + 0xf9, 0x45, 0xd8, 0xcd, 0x2a, 0x9, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, + 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfd, 0xd, 0x46, + 0x64, 0x7, 0x60, 0xf6, 0x5e, 0x53, 0x55, 0x89, 0xea, 0xef, 0xbf, 0x54, + 0x3c, 0x1f, 0xf, 0x0, 0xf1, 0x9, 0x1c, 0x3c, 0x5c, 0x87, 0xb4, 0xdb, + 0xea, 0xbb, 0x38, 0x4, 0x76, 0xea, 0xa2, 0x9, 0x4, 0x0, 0xfb, 0x9, + 0xb0, 0xe0, 0x4a, 0x25, 0x2, 0xd0, 0xff, 0x2e, 0x6, 0x0, 0xf8, 0x69, + 0xe4, 0xd6, 0x2e, 0x93, 0xee, 0xc4, 0x20, 0x5, 0x0, 0xf8, 0x4, 0x93, + 0xe4, 0x6d, 0x1c, 0xc4, 0xdb, 0x3c, 0x6, 0x0, 0xfd, 0x45, 0xdd, 0x9e, + 0x4, 0x0, 0xf1, 0x9, 0x1c, 0x3c, 0x5c, 0x87, 0xb4, 0xdb, 0xea, 0xbb, + 0x38, 0x4, 0x76, 0xea, 0xa2, 0x9, 0x4, 0x0, 0xf9, 0x9, 0xb0, 0xe0, + 0x4a, 0x25, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, + 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1b, 0x5e, 0x8, 0x60, 0xf9, 0x5f, + 0x56, 0x50, 0x57, 0xa4, 0xc7, 0x70, 0x2, 0x39, 0xff, 0x12, 0x14, 0x0, + 0xf7, 0x4, 0x4f, 0xbe, 0xec, 0xad, 0x12, 0x76, 0xe6, 0x7a, 0x5, 0x0, + 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xad, 0xe, 0x6, 0x0, 0xf8, + 0x33, 0xd8, 0xd6, 0x2e, 0x93, 0xee, 0xa2, 0x9, 0x6, 0x0, 0xf9, 0x60, + 0xe4, 0x87, 0x2a, 0xd6, 0xe4, 0xb7, 0x6, 0xb0, 0xfd, 0xbe, 0xea, 0xb7, + 0x9, 0x0, 0xf7, 0x4, 0x4f, 0xbe, 0xec, 0xad, 0x12, 0x76, 0xe6, 0x7a, + 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xcd, 0x3, 0x0, + 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, + 0x1b, 0x5e, 0x9, 0x60, 0xf7, 0x5b, 0x51, 0x4f, 0x5c, 0x60, 0x3d, 0x3f, + 0x2e, 0x7, 0x16, 0x0, 0xf9, 0x4a, 0xe0, 0xd6, 0x2e, 0x76, 0xe6, 0x7a, + 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xa6, 0x4, 0x6, + 0x0, 0xff, 0x20, 0x2, 0xd6, 0xfb, 0x2e, 0x93, 0xee, 0x96, 0x9, 0x6, + 0x0, 0xf9, 0x60, 0xe4, 0x8b, 0x2a, 0xd6, 0xe6, 0xc7, 0x7, 0xc4, 0xfe, + 0xc1, 0x93, 0xb, 0x0, 0xf9, 0x4a, 0xe0, 0xd6, 0x2e, 0x76, 0xe6, 0x7a, + 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x33, 0xdd, 0xcd, 0x3, 0x0, + 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, 0xd4, 0xcd, 0x73, 0x0, 0xfe, + 0x1b, 0x5e, 0xa, 0x60, 0xff, 0x55, 0x2, 0x50, 0xfc, 0x42, 0x40, 0x3f, + 0x1f, 0xd, 0x0, 0xfe, 0x2e, 0x20, 0x8, 0x0, 0xf9, 0x20, 0xd3, 0xdd, + 0x33, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x2e, + 0xd8, 0xbb, 0xe, 0x6, 0x0, 0xf8, 0x45, 0xe2, 0xd6, 0x2e, 0x93, 0xee, + 0xb0, 0x12, 0x5, 0x0, 0xf8, 0x4, 0x87, 0xe6, 0x7e, 0x17, 0xc4, 0xd3, + 0x41, 0x9, 0x1c, 0xfd, 0x0, 0x2e, 0x20, 0x8, 0x0, 0xf9, 0x20, 0xd3, + 0xdd, 0x33, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, + 0x2e, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfe, + 0xd4, 0xcd, 0x73, 0x0, 0xfe, 0x1c, 0x5e, 0x7, 0x60, 0xfc, 0x5d, 0x5e, + 0x60, 0x58, 0x2, 0x50, 0xfc, 0x47, 0x40, 0x36, 0xe, 0xc, 0x0, 0xfc, + 0x4f, 0xd3, 0xb7, 0x33, 0x7, 0x0, 0xf9, 0x60, 0xe4, 0xc4, 0x17, 0x76, + 0xe6, 0x7a, 0x5, 0x0, 0xf8, 0x4, 0x93, 0xe2, 0x5c, 0x12, 0xbb, 0xe2, + 0x65, 0x6, 0x0, 0xf8, 0x8f, 0xea, 0xd6, 0x2e, 0x93, 0xee, 0xdb, 0x58, + 0x5, 0x0, 0xf7, 0x25, 0xbe, 0xe0, 0x53, 0x0, 0x9a, 0xe6, 0x7e, 0x9, + 0x5, 0x0, 0xf9, 0x12, 0x4, 0x0, 0x4f, 0xd3, 0xb7, 0x33, 0x7, 0x0, + 0xf9, 0x60, 0xe4, 0xc4, 0x17, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, + 0x93, 0xe2, 0x5c, 0x12, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, + 0x5, 0x0, 0xfe, 0xcb, 0xd2, 0x73, 0x0, 0xfd, 0x1c, 0x5d, 0x61, 0x5, + 0x60, 0xf5, 0x5d, 0x58, 0x55, 0x5a, 0x5b, 0x52, 0x50, 0x47, 0x3f, 0x28, + 0x3, 0xc, 0x0, 0xfa, 0x33, 0xc4, 0xe8, 0xbb, 0x5c, 0x17, 0x3, 0x4, + 0xf7, 0xe, 0x5c, 0xc7, 0xec, 0x8b, 0x9, 0x76, 0xe6, 0x7a, 0x5, 0x0, + 0xf6, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0x65, 0xe4, 0xc7, 0x4a, 0x9, 0x2, + 0x4, 0xf4, 0x12, 0x76, 0xdb, 0xec, 0xd6, 0x2e, 0x93, 0xee, 0xea, 0xc4, + 0x4a, 0x9, 0x2, 0x4, 0xf5, 0x33, 0xb0, 0xec, 0xb4, 0x1c, 0x0, 0x4a, + 0xd3, 0xd8, 0x6d, 0xe, 0x3, 0x4, 0xf6, 0x45, 0xa2, 0x76, 0x4, 0x33, + 0xc4, 0xe8, 0xbb, 0x5c, 0x17, 0x3, 0x4, 0xf7, 0xe, 0x5c, 0xc7, 0xec, + 0x8b, 0x9, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, + 0x0, 0xdd, 0xcd, 0x3, 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfd, + 0xb3, 0xe5, 0x37, 0x72, 0x0, 0xfd, 0x9, 0x40, 0x66, 0x6, 0x60, 0xfc, + 0x5f, 0x5b, 0x56, 0x54, 0x2, 0x50, 0xfc, 0x47, 0x3e, 0x19, 0x1, 0xd, + 0x0, 0xef, 0x4a, 0xbe, 0xee, 0xe2, 0xc1, 0x9a, 0x93, 0xa9, 0xc4, 0xe2, + 0xea, 0xa6, 0x20, 0x4, 0x76, 0xe6, 0x7a, 0x5, 0x0, 0xe2, 0x4, 0x93, + 0xe2, 0x5c, 0x0, 0x9, 0x9a, 0xee, 0xd8, 0xa2, 0x8b, 0x93, 0xb7, 0xe4, + 0xb7, 0xdd, 0xd6, 0x2e, 0x93, 0xe6, 0xbb, 0xd3, 0xdd, 0xb4, 0x93, 0xa9, + 0xd6, 0xec, 0xbe, 0x41, 0x3, 0x0, 0xf6, 0x7e, 0xe6, 0xe4, 0xbe, 0xa2, + 0x9e, 0xbb, 0xdd, 0xe2, 0x7e, 0x2, 0x0, 0xef, 0x4a, 0xbe, 0xee, 0xe2, + 0xc1, 0x9a, 0x93, 0xa9, 0xc4, 0xe2, 0xea, 0xa6, 0x20, 0x4, 0x76, 0xe6, + 0x7a, 0x5, 0x0, 0xf9, 0x4, 0x93, 0xe2, 0x5c, 0x0, 0xdd, 0xcd, 0x3, + 0x0, 0xfd, 0x51, 0xf4, 0x64, 0x5, 0x0, 0xfb, 0x5e, 0xe7, 0xcd, 0x8b, + 0x11, 0x71, 0x0, 0xfd, 0x14, 0x52, 0x64, 0x7, 0x60, 0xf9, 0x5f, 0x5c, + 0x6b, 0x5d, 0x43, 0x33, 0xa, 0xf, 0x0, 0xfb, 0x2a, 0x87, 0xc4, 0xdd, + 0xe4, 0x3, 0xe2, 0xf8, 0xc7, 0x7e, 0x17, 0x0, 0x4, 0x6d, 0xd6, 0x69, + 0x5, 0x0, 0xfc, 0x4, 0x82, 0xd0, 0x53, 0x2, 0x0, 0xfc, 0x12, 0x7e, + 0xc1, 0xdb, 0x2, 0xdd, 0xf5, 0xc7, 0x7a, 0x33, 0xbe, 0xc1, 0x2a, 0x93, + 0xe6, 0x65, 0x4a, 0xb0, 0x2, 0xdd, 0xfc, 0xe0, 0xd0, 0x9e, 0x33, 0x4, + 0x0, 0xfc, 0x4, 0x58, 0xb4, 0xd8, 0x2, 0xe0, 0xfc, 0xd3, 0xb4, 0x69, + 0xe, 0x3, 0x0, 0xfb, 0x2a, 0x87, 0xc4, 0xdd, 0xe4, 0x3, 0xe2, 0xf8, + 0xc7, 0x7e, 0x17, 0x0, 0x4, 0x6d, 0xd6, 0x69, 0x5, 0x0, 0xf9, 0x4, + 0x82, 0xd0, 0x53, 0x0, 0xad, 0xa4, 0x3, 0x0, 0xfd, 0x43, 0xd4, 0x49, + 0x6, 0x0, 0xfc, 0x82, 0xd6, 0xe1, 0x4b, 0x71, 0x0, 0xfc, 0x1, 0x29, + 0x65, 0x62, 0x6, 0x60, 0xf9, 0x5e, 0x7a, 0xc6, 0xb4, 0x69, 0x25, 0x3, + 0x11, 0x0, 0xf8, 0x1c, 0x3c, 0x60, 0x69, 0x58, 0x3c, 0x1c, 0x4, 0x3, + 0x0, 0xfd, 0x9, 0x25, 0xe, 0x6, 0x0, 0xfd, 0x12, 0x25, 0x9, 0x4, + 0x0, 0xfb, 0x20, 0x41, 0x4a, 0x41, 0x25, 0x2, 0x0, 0xf3, 0x20, 0x25, + 0x9, 0x93, 0xe6, 0x5c, 0x0, 0x12, 0x38, 0x4a, 0x3c, 0x20, 0xe, 0x7, + 0x0, 0xfa, 0x12, 0x33, 0x4a, 0x41, 0x2a, 0x12, 0x7, 0x0, 0xf8, 0x1c, + 0x3c, 0x60, 0x69, 0x58, 0x3c, 0x1c, 0x4, 0x3, 0x0, 0xfd, 0x9, 0x25, + 0xe, 0x6, 0x0, 0xfc, 0x12, 0x25, 0x9, 0x0, 0x2, 0x25, 0x3, 0x0, + 0xfd, 0xe, 0x25, 0xe, 0x8, 0x0, 0xff, 0x13, 0x73, 0x0, 0xfd, 0x7, + 0x46, 0x64, 0x5, 0x60, 0xfd, 0x5f, 0x6c, 0xb9, 0x2, 0xef, 0xfc, 0xda, + 0x8a, 0x35, 0x5, 0x34, 0x0, 0xfc, 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, + 0x39, 0x0, 0xfd, 0x1b, 0x58, 0x61, 0x4, 0x60, 0xfd, 0x66, 0xa7, 0xe9, + 0x3, 0xf0, 0xfc, 0xeb, 0xc4, 0x73, 0x14, 0x33, 0x0, 0xfc, 0x4, 0x93, + 0xe6, 0x5c, 0x7f, 0x0, 0x39, 0x0, 0xfd, 0x2, 0x35, 0x64, 0x3, 0x60, + 0xfd, 0x5e, 0x9a, 0xe2, 0x6, 0xf0, 0xfe, 0xd7, 0x3d, 0x33, 0x0, 0xfc, + 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x3a, 0x0, 0xf9, 0xd, 0x4d, 0x64, + 0x60, 0x5d, 0x83, 0xd8, 0x7, 0xf0, 0xfe, 0xde, 0x43, 0x33, 0x0, 0xfc, + 0x4, 0x93, 0xe6, 0x5c, 0x7f, 0x0, 0x3a, 0x0, 0xfa, 0x1, 0x24, 0x5c, + 0x61, 0x81, 0xce, 0x8, 0xf0, 0xfe, 0xde, 0x43, 0x34, 0x0, 0xfd, 0x4a, + 0x87, 0x2e, 0x7f, 0x0, 0x3b, 0x0, 0xfb, 0x2, 0x37, 0x6e, 0xbc, 0xef, + 0x7, 0xf0, 0xfd, 0xef, 0xcd, 0x37, 0x7f, 0x0, 0x73, 0x0, 0xfa, 0x11, + 0x51, 0x9f, 0xc8, 0xe1, 0xef, 0x4, 0xf0, 0xfc, 0xe1, 0xa0, 0x4f, 0x9, + 0x7f, 0x0, 0x74, 0x0, 0xf4, 0x8, 0x1c, 0x3d, 0x6c, 0xa2, 0xce, 0xe7, + 0xe4, 0xaf, 0x5c, 0x18, 0x2, 0x7f, 0x0, 0x78, 0x0, 0xfa, 0x7, 0x17, + 0x3d, 0x70, 0x67, 0x21, 0x7f, 0x0, 0x7d, 0x0, 0xff, 0x1, 0x2, 0x3, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, + 0x7f, 0x0, 0x7f, 0x0, 0x7f, 0x0, 0x54, 0x0}; static const Image fox_logo_image = {256, 64, 2432, fox_logo_data}; const VariantAnimation fox_logo = { 21, { - {0, 0, 25, 0, &fox_logo_image}, - {0, 0, 25, 5, &fox_logo_image}, - {0, 0, 25, 10, &fox_logo_image}, - {0, 0, 25, 15, &fox_logo_image}, - {0, 0, 25, 20, &fox_logo_image}, - {0, 0, 25, 25, &fox_logo_image}, - {0, 0, 25, 30, &fox_logo_image}, - {0, 0, 25, 35, &fox_logo_image}, - {0, 0, 25, 40, &fox_logo_image}, - {0, 0, 25, 45, &fox_logo_image}, - {0, 0, 25, 50, &fox_logo_image}, - {0, 0, 25, 55, &fox_logo_image}, - {0, 0, 25, 60, &fox_logo_image}, - {0, 0, 25, 65, &fox_logo_image}, - {0, 0, 25, 70, &fox_logo_image}, - {0, 0, 25, 75, &fox_logo_image}, - {0, 0, 25, 80, &fox_logo_image}, - {0, 0, 25, 85, &fox_logo_image}, - {0, 0, 25, 90, &fox_logo_image}, - {0, 0, 25, 95, &fox_logo_image}, + {0, 0, 25, 0, &fox_logo_image}, {0, 0, 25, 5, &fox_logo_image}, + {0, 0, 25, 10, &fox_logo_image}, {0, 0, 25, 15, &fox_logo_image}, + {0, 0, 25, 20, &fox_logo_image}, {0, 0, 25, 25, &fox_logo_image}, + {0, 0, 25, 30, &fox_logo_image}, {0, 0, 25, 35, &fox_logo_image}, + {0, 0, 25, 40, &fox_logo_image}, {0, 0, 25, 45, &fox_logo_image}, + {0, 0, 25, 50, &fox_logo_image}, {0, 0, 25, 55, &fox_logo_image}, + {0, 0, 25, 60, &fox_logo_image}, {0, 0, 25, 65, &fox_logo_image}, + {0, 0, 25, 70, &fox_logo_image}, {0, 0, 25, 75, &fox_logo_image}, + {0, 0, 25, 80, &fox_logo_image}, {0, 0, 25, 85, &fox_logo_image}, + {0, 0, 25, 90, &fox_logo_image}, {0, 0, 25, 95, &fox_logo_image}, {0, 0, 25, 100, &fox_logo_image}, - } -}; + }}; const VariantAnimation fox_logo_reversed = { 21, { - {0, 0, 25, 100, &fox_logo_image}, - {0, 0, 25, 95, &fox_logo_image}, - {0, 0, 25, 90, &fox_logo_image}, - {0, 0, 25, 85, &fox_logo_image}, - {0, 0, 25, 80, &fox_logo_image}, - {0, 0, 25, 75, &fox_logo_image}, - {0, 0, 25, 70, &fox_logo_image}, - {0, 0, 25, 65, &fox_logo_image}, - {0, 0, 25, 60, &fox_logo_image}, - {0, 0, 25, 55, &fox_logo_image}, - {0, 0, 25, 50, &fox_logo_image}, - {0, 0, 25, 45, &fox_logo_image}, - {0, 0, 25, 40, &fox_logo_image}, - {0, 0, 25, 35, &fox_logo_image}, - {0, 0, 25, 30, &fox_logo_image}, - {0, 0, 25, 25, &fox_logo_image}, - {0, 0, 25, 20, &fox_logo_image}, - {0, 0, 25, 15, &fox_logo_image}, - {0, 0, 25, 10, &fox_logo_image}, - {0, 0, 25, 5, &fox_logo_image}, + {0, 0, 25, 100, &fox_logo_image}, {0, 0, 25, 95, &fox_logo_image}, + {0, 0, 25, 90, &fox_logo_image}, {0, 0, 25, 85, &fox_logo_image}, + {0, 0, 25, 80, &fox_logo_image}, {0, 0, 25, 75, &fox_logo_image}, + {0, 0, 25, 70, &fox_logo_image}, {0, 0, 25, 65, &fox_logo_image}, + {0, 0, 25, 60, &fox_logo_image}, {0, 0, 25, 55, &fox_logo_image}, + {0, 0, 25, 50, &fox_logo_image}, {0, 0, 25, 45, &fox_logo_image}, + {0, 0, 25, 40, &fox_logo_image}, {0, 0, 25, 35, &fox_logo_image}, + {0, 0, 25, 30, &fox_logo_image}, {0, 0, 25, 25, &fox_logo_image}, + {0, 0, 25, 20, &fox_logo_image}, {0, 0, 25, 15, &fox_logo_image}, + {0, 0, 25, 10, &fox_logo_image}, {0, 0, 25, 5, &fox_logo_image}, {0, 0, 25, 0, &fox_logo_image}, - } -}; + }}; -const uint8_t fox_screensaver_data[617] = -{ - 0x5, 0x0, 0xfe, 0xa, 0x7, 0x10, 0x0, 0xfd, 0x1, 0xa, 0x4, 0x4, 0x0, 0xfb, 0x1, 0x23, 0x35, 0x1c, 0x6, 0xc, 0x0, 0xfb, 0x1, 0x11, 0x30, 0x44, 0x13, 0x5, 0x0, 0xf9, 0x1b, 0x50, 0x52, 0x40, 0x24, 0xe, 0x3, 0x7, 0x1, 0xf9, 0x5, 0x16, 0x33, 0x54, 0x65, 0x52, 0xb, 0x5, 0x0, 0xfe, 0x10, 0x51, 0x2, 0x60, 0xfb, 0x59, 0x49, 0x35, 0x26, 0x23, 0x3, 0x1f, 0xf7, 0x23, 0x2a, 0x3d, 0x58, 0x63, 0x64, 0x62, 0x44, 0x6, 0x5, 0x0, 0xfe, 0x9, 0x48, 0x4, 0x60, 0xf6, 0x5f, 0x5b, 0x59, 0x51, 0x4e, 0x54, 0x5a, 0x5d, 0x60, 0x63, 0x3, 0x60, 0xfe, 0x33, 0x2, 0x5, 0x0, 0xfd, 0x4, 0x3b, 0x5e, 0x6, 0x60, 0xfe, 0x5d, 0x5c, 0x7, 0x60, 0xfe, 0x5b, 0x24, 0x6, 0x0, 0xfd, 0x2, 0x2f, 0x5d, 0xf, 0x60, 0xfe, 0x56, 0x18, 0x7, 0x0, 0xfc, 0x22, 0x59, 0x60, 0x5e, 0xb, 0x60, 0xfc, 0x5e, 0x60, 0x4f, 0xe, 0x7, 0x0, 0xfc, 0x1b, 0x56, 0x5a, 0x5c, 0xa, 0x60, 0xfb, 0x5e, 0x5a, 0x5d, 0x41, 0x5, 0x7, 0x0, 0xfd, 0x11, 0x4b, 0x59, 0xc, 0x60, 0xfc, 0x5c, 0x57, 0x2c, 0x3, 0x7, 0x0, 0xfd, 0x1b, 0x54, 0x5f, 0xd, 0x60, 0xfd, 0x59, 0x2c, 0x2, 0x7, 0x0, 0xfe, 0x31, 0x5e, 0xe, 0x60, 0xfd, 0x5f, 0x54, 0x19, 0x6, 0x0, 0xfe, 0x9, 0x47, 0x10, 0x60, 0xfe, 0x64, 0x31, 0x6, 0x0, 0xfe, 0x19, 0x57, 0x10, 0x60, 0xfd, 0x63, 0x4a, 0x8, 0x4, 0x0, 0xfd, 0x1, 0x1e, 0x56, 0xf, 0x60, 0xfc, 0x61, 0x65, 0x4b, 0xc, 0x5, 0x0, 0xfc, 0x4, 0x3b, 0x61, 0x65, 0xc, 0x60, 0xfc, 0x64, 0x5c, 0x39, 0x12, 0x5, 0x0, 0xfc, 0x4, 0x27, 0x54, 0x60, 0x2, 0x64, 0xff, 0x62, 0x8, 0x60, 0xfb, 0x61, 0x62, 0x4e, 0x22, 0x4, 0x5, 0x0, 0xfd, 0x9, 0x3a, 0x5d, 0x4, 0x60, 0xff, 0x5e, 0x7, 0x60, 0x2, 0x63, 0xfe, 0x41, 0x11, 0x6, 0x0, 0xfd, 0xa, 0x3a, 0x62, 0x4, 0x60, 0xfd, 0x5e, 0x57, 0x5c, 0x2, 0x61, 0xf9, 0x80, 0x88, 0x65, 0x64, 0x5b, 0x48, 0x19, 0x6, 0x0, 0xfe, 0x10, 0x3e, 0x2, 0x61, 0x5, 0x60, 0xf5, 0x59, 0x55, 0x61, 0x76, 0xc5, 0xd8, 0x96, 0x5b, 0x49, 0x32, 0x9, 0x5, 0x0, 0xfd, 0xd, 0x46, 0x64, 0x7, 0x60, 0xf6, 0x5e, 0x53, 0x55, 0x89, 0xea, 0xef, 0xbf, 0x54, 0x3c, 0x1f, 0x6, 0x0, 0xfe, 0x1b, 0x5e, 0x8, 0x60, 0xf9, 0x5f, 0x56, 0x50, 0x57, 0xa4, 0xc7, 0x70, 0x2, 0x39, 0xff, 0x12, 0x6, 0x0, 0xfe, 0x1b, 0x5e, 0x9, 0x60, 0xf7, 0x5b, 0x51, 0x4f, 0x5c, 0x60, 0x3d, 0x3f, 0x2e, 0x7, 0x6, 0x0, 0xfe, 0x1b, 0x5e, 0xa, 0x60, 0xff, 0x55, 0x2, 0x50, 0xfc, 0x42, 0x40, 0x3f, 0x1f, 0x7, 0x0, 0xfe, 0x1c, 0x5e, 0x7, 0x60, 0xfc, 0x5d, 0x5e, 0x60, 0x58, 0x2, 0x50, 0xfc, 0x47, 0x40, 0x36, 0xe, 0x7, 0x0, 0xfd, 0x1c, 0x5d, 0x61, 0x5, 0x60, 0xf5, 0x5d, 0x58, 0x55, 0x5a, 0x5b, 0x52, 0x50, 0x47, 0x3f, 0x28, 0x3, 0x7, 0x0, 0xfd, 0x9, 0x40, 0x66, 0x6, 0x60, 0xfc, 0x5f, 0x5b, 0x56, 0x54, 0x2, 0x50, 0xfc, 0x47, 0x3e, 0x19, 0x1, 0x8, 0x0, 0xfd, 0x14, 0x52, 0x64, 0x7, 0x60, 0xf9, 0x5f, 0x5c, 0x6b, 0x5d, 0x43, 0x33, 0xa, 0x9, 0x0, 0xfc, 0x1, 0x29, 0x65, 0x62, 0x6, 0x60, 0xf9, 0x5e, 0x7a, 0xc6, 0xb4, 0x69, 0x25, 0x3, 0xa, 0x0, 0xfd, 0x7, 0x46, 0x64, 0x5, 0x60, 0xfd, 0x5f, 0x6c, 0xb9, 0x2, 0xef, 0xfc, 0xda, 0x8a, 0x35, 0x5, 0xa, 0x0, 0xfd, 0x1b, 0x58, 0x61, 0x4, 0x60, 0xfd, 0x66, 0xa7, 0xe9, 0x3, 0xf0, 0xfc, 0xeb, 0xc4, 0x73, 0x14, 0x9, 0x0, 0xfd, 0x2, 0x35, 0x64, 0x3, 0x60, 0xfd, 0x5e, 0x9a, 0xe2, 0x6, 0xf0, 0xfe, 0xd7, 0x3d, 0xa, 0x0, 0xf9, 0xd, 0x4d, 0x64, 0x60, 0x5d, 0x83, 0xd8, 0x7, 0xf0, 0xfe, 0xde, 0x43, 0xa, 0x0, 0xfa, 0x1, 0x24, 0x5c, 0x61, 0x81, 0xce, 0x8, 0xf0, 0xfe, 0xde, 0x43, 0xb, 0x0, 0xfb, 0x2, 0x37, 0x6e, 0xbc, 0xef, 0x7, 0xf0, 0xfd, 0xef, 0xcd, 0x37, 0xc, 0x0, 0xfa, 0x11, 0x51, 0x9f, 0xc8, 0xe1, 0xef, 0x4, 0xf0, 0xfc, 0xe1, 0xa0, 0x4f, 0x9, 0xd, 0x0, 0xf4, 0x8, 0x1c, 0x3d, 0x6c, 0xa2, 0xce, 0xe7, 0xe4, 0xaf, 0x5c, 0x18, 0x2, 0x11, 0x0, 0xfa, 0x7, 0x17, 0x3d, 0x70, 0x67, 0x21, 0xa, 0x0 -}; +const uint8_t fox_screensaver_data[617] = { + 0x5, 0x0, 0xfe, 0xa, 0x7, 0x10, 0x0, 0xfd, 0x1, 0xa, 0x4, 0x4, + 0x0, 0xfb, 0x1, 0x23, 0x35, 0x1c, 0x6, 0xc, 0x0, 0xfb, 0x1, 0x11, + 0x30, 0x44, 0x13, 0x5, 0x0, 0xf9, 0x1b, 0x50, 0x52, 0x40, 0x24, 0xe, + 0x3, 0x7, 0x1, 0xf9, 0x5, 0x16, 0x33, 0x54, 0x65, 0x52, 0xb, 0x5, + 0x0, 0xfe, 0x10, 0x51, 0x2, 0x60, 0xfb, 0x59, 0x49, 0x35, 0x26, 0x23, + 0x3, 0x1f, 0xf7, 0x23, 0x2a, 0x3d, 0x58, 0x63, 0x64, 0x62, 0x44, 0x6, + 0x5, 0x0, 0xfe, 0x9, 0x48, 0x4, 0x60, 0xf6, 0x5f, 0x5b, 0x59, 0x51, + 0x4e, 0x54, 0x5a, 0x5d, 0x60, 0x63, 0x3, 0x60, 0xfe, 0x33, 0x2, 0x5, + 0x0, 0xfd, 0x4, 0x3b, 0x5e, 0x6, 0x60, 0xfe, 0x5d, 0x5c, 0x7, 0x60, + 0xfe, 0x5b, 0x24, 0x6, 0x0, 0xfd, 0x2, 0x2f, 0x5d, 0xf, 0x60, 0xfe, + 0x56, 0x18, 0x7, 0x0, 0xfc, 0x22, 0x59, 0x60, 0x5e, 0xb, 0x60, 0xfc, + 0x5e, 0x60, 0x4f, 0xe, 0x7, 0x0, 0xfc, 0x1b, 0x56, 0x5a, 0x5c, 0xa, + 0x60, 0xfb, 0x5e, 0x5a, 0x5d, 0x41, 0x5, 0x7, 0x0, 0xfd, 0x11, 0x4b, + 0x59, 0xc, 0x60, 0xfc, 0x5c, 0x57, 0x2c, 0x3, 0x7, 0x0, 0xfd, 0x1b, + 0x54, 0x5f, 0xd, 0x60, 0xfd, 0x59, 0x2c, 0x2, 0x7, 0x0, 0xfe, 0x31, + 0x5e, 0xe, 0x60, 0xfd, 0x5f, 0x54, 0x19, 0x6, 0x0, 0xfe, 0x9, 0x47, + 0x10, 0x60, 0xfe, 0x64, 0x31, 0x6, 0x0, 0xfe, 0x19, 0x57, 0x10, 0x60, + 0xfd, 0x63, 0x4a, 0x8, 0x4, 0x0, 0xfd, 0x1, 0x1e, 0x56, 0xf, 0x60, + 0xfc, 0x61, 0x65, 0x4b, 0xc, 0x5, 0x0, 0xfc, 0x4, 0x3b, 0x61, 0x65, + 0xc, 0x60, 0xfc, 0x64, 0x5c, 0x39, 0x12, 0x5, 0x0, 0xfc, 0x4, 0x27, + 0x54, 0x60, 0x2, 0x64, 0xff, 0x62, 0x8, 0x60, 0xfb, 0x61, 0x62, 0x4e, + 0x22, 0x4, 0x5, 0x0, 0xfd, 0x9, 0x3a, 0x5d, 0x4, 0x60, 0xff, 0x5e, + 0x7, 0x60, 0x2, 0x63, 0xfe, 0x41, 0x11, 0x6, 0x0, 0xfd, 0xa, 0x3a, + 0x62, 0x4, 0x60, 0xfd, 0x5e, 0x57, 0x5c, 0x2, 0x61, 0xf9, 0x80, 0x88, + 0x65, 0x64, 0x5b, 0x48, 0x19, 0x6, 0x0, 0xfe, 0x10, 0x3e, 0x2, 0x61, + 0x5, 0x60, 0xf5, 0x59, 0x55, 0x61, 0x76, 0xc5, 0xd8, 0x96, 0x5b, 0x49, + 0x32, 0x9, 0x5, 0x0, 0xfd, 0xd, 0x46, 0x64, 0x7, 0x60, 0xf6, 0x5e, + 0x53, 0x55, 0x89, 0xea, 0xef, 0xbf, 0x54, 0x3c, 0x1f, 0x6, 0x0, 0xfe, + 0x1b, 0x5e, 0x8, 0x60, 0xf9, 0x5f, 0x56, 0x50, 0x57, 0xa4, 0xc7, 0x70, + 0x2, 0x39, 0xff, 0x12, 0x6, 0x0, 0xfe, 0x1b, 0x5e, 0x9, 0x60, 0xf7, + 0x5b, 0x51, 0x4f, 0x5c, 0x60, 0x3d, 0x3f, 0x2e, 0x7, 0x6, 0x0, 0xfe, + 0x1b, 0x5e, 0xa, 0x60, 0xff, 0x55, 0x2, 0x50, 0xfc, 0x42, 0x40, 0x3f, + 0x1f, 0x7, 0x0, 0xfe, 0x1c, 0x5e, 0x7, 0x60, 0xfc, 0x5d, 0x5e, 0x60, + 0x58, 0x2, 0x50, 0xfc, 0x47, 0x40, 0x36, 0xe, 0x7, 0x0, 0xfd, 0x1c, + 0x5d, 0x61, 0x5, 0x60, 0xf5, 0x5d, 0x58, 0x55, 0x5a, 0x5b, 0x52, 0x50, + 0x47, 0x3f, 0x28, 0x3, 0x7, 0x0, 0xfd, 0x9, 0x40, 0x66, 0x6, 0x60, + 0xfc, 0x5f, 0x5b, 0x56, 0x54, 0x2, 0x50, 0xfc, 0x47, 0x3e, 0x19, 0x1, + 0x8, 0x0, 0xfd, 0x14, 0x52, 0x64, 0x7, 0x60, 0xf9, 0x5f, 0x5c, 0x6b, + 0x5d, 0x43, 0x33, 0xa, 0x9, 0x0, 0xfc, 0x1, 0x29, 0x65, 0x62, 0x6, + 0x60, 0xf9, 0x5e, 0x7a, 0xc6, 0xb4, 0x69, 0x25, 0x3, 0xa, 0x0, 0xfd, + 0x7, 0x46, 0x64, 0x5, 0x60, 0xfd, 0x5f, 0x6c, 0xb9, 0x2, 0xef, 0xfc, + 0xda, 0x8a, 0x35, 0x5, 0xa, 0x0, 0xfd, 0x1b, 0x58, 0x61, 0x4, 0x60, + 0xfd, 0x66, 0xa7, 0xe9, 0x3, 0xf0, 0xfc, 0xeb, 0xc4, 0x73, 0x14, 0x9, + 0x0, 0xfd, 0x2, 0x35, 0x64, 0x3, 0x60, 0xfd, 0x5e, 0x9a, 0xe2, 0x6, + 0xf0, 0xfe, 0xd7, 0x3d, 0xa, 0x0, 0xf9, 0xd, 0x4d, 0x64, 0x60, 0x5d, + 0x83, 0xd8, 0x7, 0xf0, 0xfe, 0xde, 0x43, 0xa, 0x0, 0xfa, 0x1, 0x24, + 0x5c, 0x61, 0x81, 0xce, 0x8, 0xf0, 0xfe, 0xde, 0x43, 0xb, 0x0, 0xfb, + 0x2, 0x37, 0x6e, 0xbc, 0xef, 0x7, 0xf0, 0xfd, 0xef, 0xcd, 0x37, 0xc, + 0x0, 0xfa, 0x11, 0x51, 0x9f, 0xc8, 0xe1, 0xef, 0x4, 0xf0, 0xfc, 0xe1, + 0xa0, 0x4f, 0x9, 0xd, 0x0, 0xf4, 0x8, 0x1c, 0x3d, 0x6c, 0xa2, 0xce, + 0xe7, 0xe4, 0xaf, 0x5c, 0x18, 0x2, 0x11, 0x0, 0xfa, 0x7, 0x17, 0x3d, + 0x70, 0x67, 0x21, 0xa, 0x0}; static const Image fox_screensaver_image = {26, 38, 617, fox_screensaver_data}; const VariantAnimation fox_screensaver = { @@ -549,8 +776,7 @@ const VariantAnimation fox_screensaver = { {113, 13, 125, 100, &fox_screensaver_image}, {114, 13, 125, 100, &fox_screensaver_image}, {115, 13, 125, 100, &fox_screensaver_image}, - } -}; + }}; VariantInfo fox_svi __attribute__((section("variant_info"))) = { .version = 1, @@ -558,5 +784,4 @@ VariantInfo fox_svi __attribute__((section("variant_info"))) = { .logo = &fox_logo, .logo_reversed = &fox_logo_reversed, .screensaver_timeout = ONE_SEC * 60 * 10, - .screensaver = &fox_screensaver -}; + .screensaver = &fox_screensaver}; diff --git a/tools/variant/kaspersky.c b/tools/variant/kaspersky.c index 0195ee32e..e019e13b8 100644 --- a/tools/variant/kaspersky.c +++ b/tools/variant/kaspersky.c @@ -21,11 +21,303 @@ #include "keepkey/board/timer.h" - -const uint8_t kaspersky_logo_data[3548] = -{ - 0x34, 0x0, 0xfd, 0x8b, 0x9d, 0x8, 0x4a, 0x0, 0xfd, 0x51, 0xc5, 0x1b, 0x77, 0x0, 0xff, 0x5f, 0x2, 0xff, 0xfe, 0xcb, 0x1d, 0x48, 0x0, 0xfb, 0x2c, 0xf6, 0xff, 0xe8, 0x3e, 0x75, 0x0, 0xfe, 0x28, 0xf4, 0x3, 0xff, 0xfe, 0xeb, 0x41, 0x46, 0x0, 0xfe, 0x9, 0xd5, 0x3, 0xff, 0xfe, 0xfb, 0x6f, 0x73, 0x0, 0xfe, 0x1, 0xc4, 0x4, 0xff, 0xfe, 0xfd, 0x5a, 0x46, 0x0, 0xff, 0x88, 0x5, 0xff, 0xff, 0x94, 0x73, 0x0, 0xff, 0x5e, 0x5, 0xff, 0xff, 0x79, 0x46, 0x0, 0xfe, 0x27, 0xfa, 0x4, 0xff, 0xfe, 0xb4, 0x2, 0x72, 0x0, 0xfe, 0x6, 0xe4, 0x4, 0xff, 0xfe, 0xba, 0x1, 0x46, 0x0, 0xff, 0xae, 0x4, 0xff, 0xfe, 0xe8, 0x10, 0x65, 0x0, 0xff, 0x5, 0xd, 0x0, 0xff, 0x62, 0x4, 0xff, 0xfe, 0xf7, 0x21, 0x46, 0x0, 0xfe, 0x24, 0xfe, 0x4, 0xff, 0xff, 0x54, 0x44, 0x0, 0x5, 0x20, 0xff, 0x6, 0x8, 0x0, 0xff, 0x7, 0x5, 0x20, 0xff, 0x1c, 0xc, 0x0, 0xfe, 0x9, 0xa1, 0xd, 0x0, 0xff, 0xc5, 0x4, 0xff, 0xff, 0x91, 0x8, 0x0, 0xff, 0x8, 0x6, 0x20, 0xfd, 0x1b, 0x10, 0x1, 0xb, 0x0, 0xff, 0x1c, 0xf, 0x20, 0xff, 0xa, 0x3, 0x0, 0xff, 0x1a, 0x6, 0x20, 0xfe, 0x12, 0x9, 0xd, 0x0, 0xff, 0x88, 0x4, 0xff, 0xff, 0xca, 0x9, 0x0, 0x5, 0x20, 0xff, 0x6, 0x8, 0x0, 0xff, 0x6, 0x5, 0x20, 0xfe, 0x1c, 0x1e, 0x4, 0x20, 0xff, 0x9, 0xb, 0x0, 0xff, 0x8, 0x4, 0x20, 0xff, 0x1e, 0xa, 0x0, 0xfe, 0x15, 0x11, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, 0xff, 0x9f, 0x5, 0xff, 0xff, 0x7c, 0xc, 0x0, 0xfd, 0x69, 0xff, 0x34, 0xb, 0x0, 0xfe, 0x19, 0xfe, 0x4, 0xff, 0xff, 0x23, 0x8, 0x0, 0xff, 0x40, 0x8, 0xff, 0xfb, 0xfa, 0xd6, 0xa1, 0x54, 0x6, 0x7, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x8, 0xff, 0xfc, 0xe9, 0xbd, 0x78, 0x22, 0x9, 0x0, 0xff, 0xda, 0x4, 0xff, 0xff, 0x60, 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, 0xff, 0x98, 0x5, 0xff, 0xfe, 0x84, 0xa1, 0x4, 0xff, 0xff, 0x99, 0xb, 0x0, 0xff, 0x98, 0x4, 0xff, 0xff, 0xa4, 0x7, 0x0, 0xfd, 0x13, 0x96, 0xee, 0x2, 0xff, 0xfc, 0xe8, 0x8b, 0xe, 0x0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xff, 0x54, 0x5, 0xff, 0xfe, 0xc5, 0x3, 0xb, 0x0, 0xfc, 0x4, 0xde, 0xff, 0xac, 0xb, 0x0, 0xff, 0x58, 0x4, 0xff, 0xff, 0xd1, 0x9, 0x0, 0xff, 0x40, 0xc, 0xff, 0xfe, 0xe2, 0x5a, 0x6, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xb, 0xff, 0xfd, 0xfc, 0xa1, 0x15, 0x6, 0x0, 0xff, 0x1a, 0x4, 0xff, 0xfe, 0xfe, 0x11, 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xff, 0x4d, 0x5, 0xff, 0xfc, 0xca, 0x5, 0x19, 0xf3, 0x3, 0xff, 0xfe, 0xfe, 0x31, 0x9, 0x0, 0xfe, 0x30, 0xfd, 0x3, 0xff, 0xfe, 0xf3, 0x1a, 0x6, 0x0, 0xfe, 0x12, 0xdb, 0x6, 0xff, 0xfe, 0xd0, 0xd, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x1c, 0xee, 0x4, 0xff, 0xfe, 0xf2, 0x20, 0xc, 0x0, 0xff, 0x5b, 0x2, 0xff, 0xfe, 0xfe, 0x28, 0xa, 0x0, 0xff, 0x86, 0x4, 0xff, 0xff, 0x9b, 0x9, 0x0, 0xff, 0x40, 0xe, 0xff, 0xfe, 0x9c, 0x3, 0x4, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xd, 0xff, 0xfe, 0xe5, 0x2d, 0x5, 0x0, 0xff, 0x49, 0x4, 0xff, 0xff, 0xd7, 0xa, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x17, 0xeb, 0x4, 0xff, 0xfe, 0xf4, 0x24, 0x2, 0x0, 0xff, 0x76, 0x4, 0xff, 0xfe, 0xc3, 0x1, 0x7, 0x0, 0xfe, 0x1, 0xc2, 0x4, 0xff, 0xff, 0x78, 0x7, 0x0, 0xff, 0x96, 0x3, 0xff, 0xfe, 0xd1, 0xd4, 0x3, 0xff, 0xff, 0x88, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x2, 0xbd, 0x5, 0xff, 0xff, 0x5c, 0xc, 0x0, 0xfe, 0x1, 0xd3, 0x3, 0xff, 0xff, 0x9e, 0xa, 0x0, 0xff, 0xa2, 0x4, 0xff, 0xff, 0x7d, 0x9, 0x0, 0xff, 0x40, 0xf, 0xff, 0xff, 0x8d, 0x4, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xe, 0xff, 0xfe, 0xe7, 0x1b, 0x4, 0x0, 0xff, 0x66, 0x4, 0xff, 0xff, 0xba, 0xa, 0x0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x1, 0xb7, 0x5, 0xff, 0xff, 0x64, 0x3, 0x0, 0xfe, 0x6, 0xda, 0x4, 0xff, 0xff, 0x5a, 0x7, 0x0, 0xff, 0x58, 0x4, 0xff, 0xfe, 0xdc, 0x7, 0x7, 0x0, 0xfc, 0xee, 0xff, 0xfc, 0x46, 0x2, 0x0, 0xfc, 0x4f, 0xfe, 0xff, 0xe4, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xff, 0x75, 0x5, 0xff, 0xff, 0xa7, 0xd, 0x0, 0xff, 0x4c, 0x4, 0xff, 0xfe, 0xfa, 0x1e, 0x9, 0x0, 0xff, 0xa2, 0x4, 0xff, 0xff, 0x80, 0x9, 0x0, 0xff, 0x40, 0x10, 0xff, 0xff, 0x3c, 0x3, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xf, 0xff, 0xff, 0xac, 0x4, 0x0, 0xff, 0x6f, 0x4, 0xff, 0xff, 0xbd, 0xa, 0x0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xff, 0x6d, 0x5, 0xff, 0xff, 0xae, 0x5, 0x0, 0xff, 0x4a, 0x4, 0xff, 0xfe, 0xe5, 0xb, 0x5, 0x0, 0xfe, 0xa, 0xe3, 0x4, 0xff, 0xff, 0x4d, 0x7, 0x0, 0xff, 0xd, 0x2, 0xff, 0xff, 0xb6, 0x4, 0x0, 0xff, 0xbf, 0x7, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0x31, 0xf9, 0x4, 0xff, 0xfe, 0xe1, 0x10, 0xd, 0x0, 0xff, 0xc6, 0x5, 0xff, 0xff, 0x90, 0x9, 0x0, 0xff, 0x9b, 0x4, 0xff, 0xff, 0x9b, 0x9, 0x0, 0xff, 0x40, 0x4, 0xff, 0xf9, 0xf0, 0x0, 0x5, 0x14, 0x32, 0x6f, 0xd9, 0x5, 0xff, 0xff, 0xb3, 0x3, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xf9, 0x60, 0x0, 0xd, 0x21, 0x50, 0xa4, 0xfd, 0x5, 0xff, 0xff, 0x29, 0x3, 0x0, 0xff, 0x5c, 0x4, 0xff, 0xff, 0xd8, 0xa, 0x0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0x2b, 0xf8, 0x4, 0xff, 0xfe, 0xe5, 0x13, 0x6, 0x0, 0xff, 0xb6, 0x4, 0xff, 0xff, 0x86, 0x5, 0x0, 0xff, 0x83, 0x4, 0xff, 0xff, 0xb7, 0x9, 0x0, 0xfd, 0xee, 0xff, 0xb9, 0x4, 0x0, 0xfd, 0xbf, 0xff, 0xe5, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x9, 0xd6, 0x4, 0xff, 0xfe, 0xfd, 0x3f, 0xd, 0x0, 0xff, 0x3e, 0x6, 0xff, 0xfe, 0xf4, 0x14, 0x8, 0x0, 0xff, 0x7a, 0x4, 0xff, 0xff, 0xd1, 0x9, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x5, 0x0, 0xfe, 0x8, 0xb6, 0x4, 0xff, 0xfe, 0xfb, 0xc, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0x4c, 0xfd, 0x4, 0xff, 0xff, 0x7a, 0x3, 0x0, 0xff, 0x3f, 0x4, 0xff, 0xfe, 0xfc, 0x12, 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x7, 0xd1, 0x5, 0xff, 0xff, 0x44, 0x7, 0x0, 0xfe, 0x25, 0xfa, 0x3, 0xff, 0xfe, 0xf8, 0x22, 0x3, 0x0, 0xfe, 0x21, 0xf8, 0x3, 0xff, 0xfe, 0xfa, 0x27, 0x9, 0x0, 0xfc, 0x85, 0xff, 0xfd, 0x50, 0x2, 0x0, 0xfc, 0x54, 0xfe, 0xff, 0x7a, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xff, 0x96, 0x5, 0xff, 0xff, 0x87, 0xe, 0x0, 0xff, 0xb8, 0x7, 0xff, 0xff, 0x82, 0x8, 0x0, 0xff, 0x42, 0x5, 0xff, 0xff, 0x27, 0x8, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x6, 0x0, 0xfe, 0x20, 0xfe, 0x4, 0xff, 0xff, 0x3b, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0xab, 0x4, 0xff, 0xff, 0xb0, 0x3, 0x0, 0xfe, 0xb, 0xfa, 0x4, 0xff, 0xff, 0x66, 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xff, 0x8e, 0x5, 0xff, 0xff, 0x8d, 0x9, 0x0, 0xff, 0x89, 0x4, 0xff, 0xff, 0xb1, 0x3, 0x0, 0xff, 0xaf, 0x4, 0xff, 0xff, 0x8c, 0x5, 0x0, 0xff, 0xd2, 0x4, 0xe0, 0xff, 0xe3, 0x3, 0xff, 0xfe, 0xdb, 0xdf, 0x2, 0xff, 0xfe, 0xfb, 0x85, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xff, 0x4b, 0x5, 0xff, 0xfe, 0xcc, 0x5, 0xd, 0x0, 0xff, 0x31, 0x8, 0xff, 0xfe, 0xee, 0xc, 0x7, 0x0, 0xfe, 0x7, 0xef, 0x4, 0xff, 0xff, 0x9c, 0x8, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x7, 0x0, 0xff, 0xe6, 0x4, 0xff, 0xff, 0x52, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0x72, 0x4, 0xff, 0xff, 0xc6, 0x4, 0x0, 0xff, 0xba, 0x4, 0xff, 0xfe, 0xd6, 0x3, 0x8, 0x0, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xff, 0x45, 0x5, 0xff, 0xfe, 0xd1, 0x7, 0x9, 0x0, 0xfe, 0xd, 0xe7, 0x4, 0xff, 0xfd, 0x47, 0x0, 0x44, 0x4, 0xff, 0xfe, 0xe9, 0xe, 0x5, 0x0, 0xff, 0xf0, 0xd, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x16, 0xea, 0x4, 0xff, 0xfe, 0xf5, 0x26, 0xe, 0x0, 0xff, 0xa8, 0x4, 0xff, 0xff, 0xfd, 0x4, 0xff, 0xff, 0x74, 0x8, 0x0, 0xff, 0x8f, 0x4, 0xff, 0xfe, 0xfd, 0x35, 0x7, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x7, 0x0, 0xff, 0xe9, 0x4, 0xff, 0xff, 0x52, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0x6, 0x0, 0xff, 0x14, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0x75, 0x4, 0xff, 0xff, 0xc6, 0x4, 0x0, 0xff, 0x51, 0x5, 0xff, 0xff, 0x6f, 0x8, 0x0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x13, 0xe5, 0x4, 0xff, 0xfe, 0xf8, 0x2b, 0xb, 0x0, 0xff, 0x5f, 0x4, 0xff, 0xfd, 0xd7, 0x9, 0xd5, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0xe1, 0xd, 0xf0, 0xff, 0xa5, 0x5, 0xff, 0xfd, 0x30, 0x1, 0xb5, 0x5, 0xff, 0xff, 0x66, 0xe, 0x0, 0xfe, 0x24, 0xfe, 0x3, 0xff, 0xfe, 0xfa, 0x69, 0x4, 0xff, 0xfe, 0xe6, 0x6, 0x7, 0x0, 0xfe, 0x1b, 0xf4, 0x4, 0xff, 0xfe, 0xd1, 0x5, 0x6, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x6, 0x0, 0xff, 0x32, 0x5, 0xff, 0xff, 0x36, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0x4, 0x0, 0xfd, 0x31, 0xb0, 0xaf, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0xbe, 0x4, 0xff, 0xff, 0xaa, 0x4, 0x0, 0xfe, 0x2, 0xcf, 0x4, 0xff, 0xfe, 0xf4, 0x21, 0x7, 0x0, 0x5, 0xff, 0xfd, 0x30, 0x0, 0xae, 0x5, 0xff, 0xff, 0x6c, 0xc, 0x0, 0xfe, 0x1, 0xc7, 0x4, 0xff, 0xff, 0xc9, 0x4, 0xff, 0xfe, 0xc9, 0x1, 0x15, 0x0, 0x5, 0xff, 0xfe, 0x30, 0x6a, 0x5, 0xff, 0xff, 0xb1, 0xf, 0x0, 0xff, 0x9a, 0x4, 0xff, 0xfd, 0x9d, 0x1, 0xd2, 0x4, 0xff, 0xff, 0x65, 0x8, 0x0, 0xff, 0x77, 0x5, 0xff, 0xff, 0x80, 0x6, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x5, 0x0, 0xfe, 0x16, 0xd2, 0x4, 0xff, 0xfe, 0xf4, 0x8, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0x2, 0x0, 0xfe, 0x37, 0xb0, 0x2, 0xff, 0xff, 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0x73, 0x5, 0xff, 0xff, 0x70, 0x5, 0x0, 0xff, 0x3c, 0x5, 0xff, 0xfe, 0xbe, 0x1, 0x6, 0x0, 0x5, 0xff, 0xfe, 0x30, 0x64, 0x5, 0xff, 0xfe, 0xb7, 0x1, 0xd, 0x0, 0xfe, 0x35, 0xfe, 0x8, 0xff, 0xff, 0x37, 0xc, 0x0, 0xff, 0x24, 0x8, 0x30, 0xff, 0x21, 0x5, 0xff, 0xfe, 0x5a, 0xf7, 0x4, 0xff, 0xfe, 0xe7, 0x14, 0xe, 0x0, 0xfe, 0x1a, 0xfa, 0x3, 0xff, 0xfc, 0xfe, 0x27, 0x0, 0x5a, 0x4, 0xff, 0xfe, 0xdc, 0x2, 0x7, 0x0, 0xfe, 0x5, 0xd0, 0x4, 0xff, 0xfe, 0xf7, 0x1f, 0x5, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x3, 0x0, 0xfd, 0x17, 0x71, 0xe7, 0x5, 0xff, 0xff, 0x9e, 0x3, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xfd, 0x50, 0x38, 0xb8, 0x4, 0xff, 0xff, 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x2, 0x0, 0xfd, 0x3, 0x42, 0xb3, 0x5, 0xff, 0xfe, 0xfa, 0x19, 0x6, 0x0, 0xff, 0x98, 0x5, 0xff, 0xff, 0x54, 0x6, 0x0, 0x5, 0xff, 0xfe, 0x55, 0xf4, 0x4, 0xff, 0xfe, 0xeb, 0x17, 0xf, 0x0, 0xff, 0x9d, 0x7, 0xff, 0xff, 0xa0, 0xd, 0x0, 0xff, 0xc0, 0x8, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xff, 0xb6, 0x5, 0xff, 0xff, 0x96, 0xf, 0x0, 0xff, 0x8c, 0x4, 0xff, 0xff, 0xac, 0x2, 0x0, 0xfe, 0x4, 0xdd, 0x4, 0xff, 0xff, 0x57, 0x8, 0x0, 0xff, 0x38, 0x5, 0xff, 0xff, 0x9f, 0x5, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfc, 0xf0, 0x7c, 0xc1, 0xdf, 0x7, 0xff, 0xfe, 0xf7, 0x23, 0x3, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xfe, 0x72, 0xe2, 0x5, 0xff, 0xff, 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xfc, 0x8b, 0xb8, 0xcd, 0xf6, 0x7, 0xff, 0xff, 0x8e, 0x7, 0x0, 0xfe, 0xf, 0xea, 0x4, 0xff, 0xfe, 0xdc, 0x2, 0x5, 0x0, 0x5, 0xff, 0xff, 0xaf, 0x5, 0xff, 0xff, 0x9c, 0x10, 0x0, 0xfe, 0x17, 0xf1, 0x5, 0xff, 0xfe, 0xf2, 0x17, 0xd, 0x0, 0xff, 0xc0, 0x8, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xfe, 0x3c, 0xda, 0x4, 0xff, 0xfe, 0xfc, 0x3a, 0xd, 0x0, 0xfe, 0x12, 0xf4, 0x4, 0xff, 0xff, 0x33, 0x3, 0x0, 0xff, 0x68, 0x4, 0xff, 0xfe, 0xcf, 0x1, 0x8, 0x0, 0xff, 0xa3, 0x4, 0xff, 0xfe, 0xfa, 0x1a, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfd, 0xf0, 0x27, 0xf5, 0x8, 0xff, 0xff, 0x65, 0x4, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xfc, 0x50, 0x6, 0x60, 0xdc, 0x3, 0xff, 0xff, 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xfe, 0x60, 0xa8, 0x8, 0xff, 0xfe, 0xce, 0xa, 0x8, 0x0, 0xff, 0x6a, 0x5, 0xff, 0xff, 0x50, 0x5, 0x0, 0x5, 0xff, 0xfe, 0x39, 0xd6, 0x4, 0xff, 0xfe, 0xfd, 0x3f, 0x10, 0x0, 0xff, 0x72, 0x5, 0xff, 0xff, 0x74, 0xe, 0x0, 0xf6, 0x7e, 0xfc, 0xff, 0xfa, 0xb6, 0xb9, 0xfc, 0xff, 0xfa, 0x73, 0x5, 0xff, 0xfd, 0x30, 0x35, 0xfb, 0x4, 0xff, 0xfe, 0xde, 0xd, 0xc, 0x0, 0xff, 0x7e, 0x4, 0xff, 0xff, 0xba, 0x4, 0x0, 0xfe, 0x9, 0xe7, 0x4, 0xff, 0xff, 0x48, 0x8, 0x0, 0xfe, 0x24, 0xfc, 0x4, 0xff, 0xff, 0x78, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfd, 0xf0, 0x0, 0x66, 0x6, 0xff, 0xfe, 0xfd, 0x72, 0x5, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0x2, 0x0, 0xfb, 0x4, 0x60, 0xdc, 0xff, 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xfd, 0x60, 0x10, 0xe2, 0x6, 0xff, 0xfe, 0xce, 0x15, 0x9, 0x0, 0xfe, 0x6, 0xdd, 0x4, 0xff, 0xff, 0xb4, 0x5, 0x0, 0x5, 0xff, 0xfd, 0x30, 0x2f, 0xf9, 0x4, 0xff, 0xfe, 0xe2, 0x10, 0xf, 0x0, 0xfe, 0x5, 0xd7, 0x3, 0xff, 0xfe, 0xd9, 0x6, 0xe, 0x0, 0xfc, 0x91, 0xff, 0xfa, 0x34, 0x2, 0x0, 0xfc, 0x3a, 0xfa, 0xff, 0x8e, 0x5, 0xff, 0xfd, 0x30, 0x0, 0x7a, 0x5, 0xff, 0xff, 0xa1, 0xb, 0x0, 0xfe, 0xc, 0xec, 0x4, 0xff, 0xff, 0x41, 0x5, 0x0, 0xff, 0x77, 0x4, 0xff, 0xff, 0xc1, 0x9, 0x0, 0xff, 0xae, 0x4, 0xff, 0xff, 0xcb, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x2, 0x0, 0xff, 0xb1, 0x4, 0xff, 0xfe, 0xd7, 0x40, 0x6, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0x4, 0x0, 0xfd, 0x4, 0x5f, 0x87, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xfc, 0x60, 0x0, 0x3f, 0xfd, 0x4, 0xff, 0xfe, 0xf3, 0x10, 0xb, 0x0, 0xff, 0x71, 0x4, 0xff, 0xfe, 0xf9, 0xd, 0x4, 0x0, 0x5, 0xff, 0xfd, 0x30, 0x0, 0x74, 0x5, 0xff, 0xff, 0xa8, 0x10, 0x0, 0xff, 0x47, 0x3, 0xff, 0xff, 0x49, 0xf, 0x0, 0xfd, 0xf1, 0xff, 0xb4, 0x4, 0x0, 0xfd, 0xbb, 0xff, 0xec, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x3, 0xc3, 0x5, 0xff, 0xff, 0x56, 0xa, 0x0, 0xff, 0x70, 0x4, 0xff, 0xff, 0xcb, 0x6, 0x40, 0xfe, 0x4a, 0xf0, 0x4, 0xff, 0xff, 0x3a, 0x8, 0x0, 0xff, 0x4d, 0x4, 0xff, 0xfe, 0xfd, 0xb, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x2, 0x0, 0xfa, 0x14, 0xe7, 0xf5, 0xb0, 0x52, 0x4, 0x7, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x2, 0x0, 0xff, 0x87, 0x5, 0xff, 0xff, 0x94, 0xb, 0x0, 0xfe, 0x14, 0xfd, 0x4, 0xff, 0xff, 0x45, 0x4, 0x0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x1, 0xbd, 0x5, 0xff, 0xff, 0x5d, 0x10, 0x0, 0xfd, 0xb1, 0xff, 0xb3, 0xf, 0x0, 0xff, 0x8, 0x2, 0xff, 0xff, 0xb9, 0x4, 0x0, 0xff, 0xc1, 0x7, 0xff, 0xff, 0x30, 0x2, 0x0, 0xfe, 0x1f, 0xf1, 0x4, 0xff, 0xfe, 0xef, 0x1d, 0x8, 0x0, 0xfe, 0x6, 0xe2, 0x4, 0xff, 0xfe, 0x53, 0xdc, 0x5, 0xff, 0xfe, 0xad, 0x85, 0x4, 0xff, 0xff, 0xb3, 0x8, 0x0, 0xfe, 0x9, 0xfb, 0x4, 0xff, 0xff, 0x36, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x3, 0x0, 0xfe, 0x14, 0x4, 0xa, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x2, 0x0, 0xfe, 0x5, 0xcc, 0x5, 0xff, 0xff, 0x4b, 0xb, 0x0, 0xff, 0xc6, 0x4, 0xff, 0xff, 0x73, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xfe, 0x1b, 0xed, 0x4, 0xff, 0xfe, 0xf2, 0x21, 0xf, 0x0, 0xfd, 0x23, 0xf1, 0x24, 0x10, 0x0, 0xfc, 0xe5, 0xff, 0xfe, 0x5d, 0x2, 0x1, 0xff, 0x65, 0x2, 0xff, 0xff, 0xe1, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xff, 0x5a, 0x5, 0xff, 0xfe, 0xbf, 0x2, 0x7, 0x0, 0xff, 0x62, 0x4, 0xff, 0xfd, 0xd6, 0x1, 0x60, 0x4, 0xff, 0xfc, 0xfe, 0x2a, 0x15, 0xf7, 0x4, 0xff, 0xff, 0x2d, 0x8, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x4f, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x3, 0x0, 0xfe, 0x27, 0xf5, 0x4, 0xff, 0xfe, 0xe9, 0x16, 0xa, 0x0, 0xff, 0x95, 0x4, 0xff, 0xff, 0x8b, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xff, 0x53, 0x5, 0xff, 0xfe, 0xc5, 0x3, 0xf, 0x0, 0xff, 0x41, 0x11, 0x0, 0xff, 0x84, 0x3, 0xff, 0xfe, 0xe4, 0xe5, 0x3, 0xff, 0xff, 0x84, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xff, 0xa5, 0x5, 0xff, 0xff, 0x77, 0x6, 0x0, 0xfe, 0x2, 0xd8, 0x4, 0xff, 0xfc, 0x5e, 0x0, 0x4, 0xdc, 0x3, 0xff, 0xff, 0xa8, 0x2, 0x0, 0xff, 0x93, 0x4, 0xff, 0xff, 0xa5, 0x8, 0x0, 0xff, 0xbc, 0x4, 0xff, 0xff, 0x54, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x4, 0x0, 0xff, 0x67, 0x5, 0xff, 0xfe, 0xb4, 0x1, 0x9, 0x0, 0xff, 0x80, 0x4, 0xff, 0xff, 0x90, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xff, 0x9d, 0x5, 0xff, 0xff, 0x7e, 0xe, 0x0, 0xfd, 0xc, 0xd8, 0xc, 0x10, 0x0, 0xfe, 0x8, 0xc3, 0x6, 0xff, 0xfe, 0xc5, 0x9, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0xf, 0xe0, 0x4, 0xff, 0xfe, 0xfa, 0x32, 0x5, 0x0, 0xff, 0x54, 0x4, 0xff, 0xfe, 0xe2, 0x4, 0x2, 0x0, 0xff, 0x5e, 0x2, 0xff, 0xfe, 0xfe, 0x2a, 0x2, 0x0, 0xfe, 0x1e, 0xfb, 0x3, 0xff, 0xfe, 0xfc, 0x22, 0x7, 0x0, 0xff, 0xc4, 0x4, 0xff, 0xff, 0x4c, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x87, 0xa, 0x50, 0xff, 0x19, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0xb1, 0x5, 0xff, 0xff, 0x6a, 0x9, 0x0, 0xff, 0x86, 0x4, 0xff, 0xff, 0x8a, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, 0xc, 0xdc, 0x4, 0xff, 0xfe, 0xfc, 0x38, 0xd, 0x0, 0xfd, 0x78, 0xff, 0x78, 0x11, 0x0, 0xf7, 0x6, 0x78, 0xd6, 0xfd, 0xfe, 0xd4, 0x75, 0x6, 0x0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x3d, 0xfd, 0x4, 0xff, 0xfe, 0xd8, 0xa, 0x4, 0x0, 0xff, 0xcc, 0x4, 0xff, 0xff, 0x6c, 0x3, 0x0, 0xfc, 0x2, 0xd6, 0xff, 0xa8, 0x4, 0x0, 0xff, 0xa1, 0x4, 0xff, 0xff, 0x97, 0x6, 0x0, 0xfe, 0x1, 0xee, 0x4, 0xff, 0xff, 0x2a, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0x14, 0xe7, 0x4, 0xff, 0xfe, 0xf6, 0x29, 0x8, 0x0, 0xff, 0xb3, 0x4, 0xff, 0xff, 0x67, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x37, 0xfc, 0x4, 0xff, 0xfe, 0xdc, 0xc, 0xb, 0x0, 0xfb, 0xc, 0xec, 0xff, 0xec, 0x10, 0x13, 0x0, 0xfe, 0x2, 0x1, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xff, 0x84, 0x5, 0xff, 0xff, 0x98, 0x3, 0x0, 0xff, 0x45, 0x4, 0xff, 0xfe, 0xeb, 0x9, 0x4, 0x0, 0xfd, 0x58, 0xfc, 0x27, 0x4, 0x0, 0xfe, 0x2a, 0xfe, 0x3, 0xff, 0xfe, 0xf7, 0x19, 0x5, 0x0, 0xff, 0x3a, 0x4, 0xff, 0xfe, 0xf3, 0x4, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0x47, 0x5, 0xff, 0xfe, 0xcf, 0x7, 0x6, 0x0, 0xfe, 0xa, 0xf4, 0x4, 0xff, 0xff, 0x34, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xff, 0x7c, 0x5, 0xff, 0xff, 0x9e, 0xb, 0x0, 0xff, 0x7c, 0x3, 0xff, 0xff, 0x80, 0xa, 0x0, 0xff, 0xf, 0xd, 0x10, 0xff, 0xb, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x5, 0xca, 0x5, 0xff, 0xff, 0x4d, 0x2, 0x0, 0xff, 0xbe, 0x4, 0xff, 0xff, 0x7a, 0x5, 0x0, 0xfe, 0x2, 0x76, 0x6, 0x0, 0xff, 0xaf, 0x4, 0xff, 0xff, 0x88, 0x5, 0x0, 0xff, 0xa8, 0x4, 0xff, 0xff, 0xaf, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x7, 0x0, 0xff, 0x91, 0x5, 0xff, 0xff, 0x8a, 0x6, 0x0, 0xff, 0x70, 0x4, 0xff, 0xfe, 0xea, 0x2, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x3, 0xc5, 0x5, 0xff, 0xff, 0x54, 0x9, 0x0, 0xfe, 0x10, 0xf0, 0x3, 0xff, 0xfe, 0xf0, 0x10, 0x9, 0x0, 0xff, 0xf0, 0xd, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xfe, 0x25, 0xf4, 0x4, 0xff, 0xfd, 0xeb, 0x17, 0x37, 0x4, 0xff, 0xfe, 0xf2, 0x10, 0xd, 0x0, 0xff, 0x37, 0x4, 0xff, 0xfe, 0xf1, 0x10, 0x3, 0x0, 0xff, 0x3f, 0x5, 0xff, 0xff, 0x50, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x7, 0x0, 0xfe, 0x8, 0xd3, 0x4, 0xff, 0xfe, 0xfe, 0x42, 0x4, 0x0, 0xfe, 0x15, 0xeb, 0x4, 0xff, 0xff, 0x8d, 0x5, 0x0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xfe, 0x20, 0xf2, 0x4, 0xff, 0xfe, 0xee, 0x1b, 0x8, 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x80, 0x9, 0x0, 0xff, 0xf0, 0xd, 0xff, 0xff, 0xb0, 0x5, 0xd0, 0xff, 0x27, 0x8, 0x0, 0xff, 0x5f, 0x5, 0xd0, 0xfe, 0x87, 0x85, 0x4, 0xd0, 0xff, 0x78, 0xf, 0x0, 0xff, 0xa3, 0x4, 0xd0, 0xff, 0x59, 0x2, 0x0, 0xfe, 0x12, 0xe0, 0x4, 0xff, 0xfe, 0xda, 0x3, 0x4, 0x0, 0xff, 0x34, 0x4, 0xd0, 0xff, 0xc3, 0xf, 0x0, 0xff, 0xb6, 0xf, 0xd0, 0xff, 0x41, 0x3, 0x0, 0xff, 0xa9, 0x4, 0xd0, 0xff, 0x4e, 0x8, 0x0, 0xfe, 0x2e, 0xcf, 0x4, 0xd0, 0xfe, 0xb4, 0x5, 0x2, 0x0, 0xfe, 0x1, 0xb4, 0x4, 0xff, 0xfe, 0xfa, 0x21, 0x5, 0x0, 0x5, 0xd0, 0xff, 0x27, 0x8, 0x0, 0xff, 0x59, 0x5, 0xd0, 0xff, 0x8c, 0x7, 0x0, 0xfe, 0x6, 0xc0, 0x5, 0xd0, 0xfe, 0xc0, 0x6, 0x8, 0x0, 0xff, 0xc3, 0xd, 0xd0, 0xff, 0x8f, 0x31, 0x0, 0xfe, 0x7, 0xc0, 0x5, 0xff, 0xff, 0x53, 0x46, 0x0, 0xff, 0x8c, 0x5, 0xff, 0xff, 0x91, 0x72, 0x0, 0xfe, 0x6, 0xb2, 0x5, 0xff, 0xff, 0xb0, 0x46, 0x0, 0xff, 0x7b, 0x5, 0xff, 0xfe, 0xe2, 0xe, 0x71, 0x0, 0xfe, 0xe, 0xbb, 0x5, 0xff, 0xfe, 0xe4, 0x17, 0x44, 0x0, 0xfe, 0x1, 0x8d, 0x5, 0xff, 0xfe, 0xfa, 0x3d, 0x72, 0x0, 0xff, 0xb6, 0x5, 0xff, 0xfe, 0xf6, 0x35, 0x45, 0x0, 0xff, 0x7a, 0x6, 0xff, 0xff, 0x69, 0x73, 0x0, 0xff, 0x72, 0x4, 0xff, 0xfe, 0xfa, 0x47, 0x46, 0x0, 0xff, 0x35, 0x5, 0xff, 0xff, 0x7d, 0x74, 0x0, 0xfe, 0xc, 0xee, 0x2, 0xff, 0xfe, 0xf6, 0x4b, 0x48, 0x0, 0xff, 0xbd, 0x3, 0xff, 0xff, 0x7f, 0x76, 0x0, 0xfc, 0x84, 0xff, 0xeb, 0x3a, 0x49, 0x0, 0xfc, 0x46, 0xff, 0xfb, 0x66, 0x77, 0x0, 0xfd, 0x15, 0xc4, 0x1f, 0x4b, 0x0, 0xfe, 0xba, 0x40, 0x48, 0x0 -}; +const uint8_t kaspersky_logo_data[3548] = { + 0x34, 0x0, 0xfd, 0x8b, 0x9d, 0x8, 0x4a, 0x0, 0xfd, 0x51, 0xc5, 0x1b, + 0x77, 0x0, 0xff, 0x5f, 0x2, 0xff, 0xfe, 0xcb, 0x1d, 0x48, 0x0, 0xfb, + 0x2c, 0xf6, 0xff, 0xe8, 0x3e, 0x75, 0x0, 0xfe, 0x28, 0xf4, 0x3, 0xff, + 0xfe, 0xeb, 0x41, 0x46, 0x0, 0xfe, 0x9, 0xd5, 0x3, 0xff, 0xfe, 0xfb, + 0x6f, 0x73, 0x0, 0xfe, 0x1, 0xc4, 0x4, 0xff, 0xfe, 0xfd, 0x5a, 0x46, + 0x0, 0xff, 0x88, 0x5, 0xff, 0xff, 0x94, 0x73, 0x0, 0xff, 0x5e, 0x5, + 0xff, 0xff, 0x79, 0x46, 0x0, 0xfe, 0x27, 0xfa, 0x4, 0xff, 0xfe, 0xb4, + 0x2, 0x72, 0x0, 0xfe, 0x6, 0xe4, 0x4, 0xff, 0xfe, 0xba, 0x1, 0x46, + 0x0, 0xff, 0xae, 0x4, 0xff, 0xfe, 0xe8, 0x10, 0x65, 0x0, 0xff, 0x5, + 0xd, 0x0, 0xff, 0x62, 0x4, 0xff, 0xfe, 0xf7, 0x21, 0x46, 0x0, 0xfe, + 0x24, 0xfe, 0x4, 0xff, 0xff, 0x54, 0x44, 0x0, 0x5, 0x20, 0xff, 0x6, + 0x8, 0x0, 0xff, 0x7, 0x5, 0x20, 0xff, 0x1c, 0xc, 0x0, 0xfe, 0x9, + 0xa1, 0xd, 0x0, 0xff, 0xc5, 0x4, 0xff, 0xff, 0x91, 0x8, 0x0, 0xff, + 0x8, 0x6, 0x20, 0xfd, 0x1b, 0x10, 0x1, 0xb, 0x0, 0xff, 0x1c, 0xf, + 0x20, 0xff, 0xa, 0x3, 0x0, 0xff, 0x1a, 0x6, 0x20, 0xfe, 0x12, 0x9, + 0xd, 0x0, 0xff, 0x88, 0x4, 0xff, 0xff, 0xca, 0x9, 0x0, 0x5, 0x20, + 0xff, 0x6, 0x8, 0x0, 0xff, 0x6, 0x5, 0x20, 0xfe, 0x1c, 0x1e, 0x4, + 0x20, 0xff, 0x9, 0xb, 0x0, 0xff, 0x8, 0x4, 0x20, 0xff, 0x1e, 0xa, + 0x0, 0xfe, 0x15, 0x11, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, + 0xff, 0x9f, 0x5, 0xff, 0xff, 0x7c, 0xc, 0x0, 0xfd, 0x69, 0xff, 0x34, + 0xb, 0x0, 0xfe, 0x19, 0xfe, 0x4, 0xff, 0xff, 0x23, 0x8, 0x0, 0xff, + 0x40, 0x8, 0xff, 0xfb, 0xfa, 0xd6, 0xa1, 0x54, 0x6, 0x7, 0x0, 0xff, + 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x8, 0xff, 0xfc, + 0xe9, 0xbd, 0x78, 0x22, 0x9, 0x0, 0xff, 0xda, 0x4, 0xff, 0xff, 0x60, + 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x8, 0x0, 0xff, 0x98, 0x5, 0xff, + 0xfe, 0x84, 0xa1, 0x4, 0xff, 0xff, 0x99, 0xb, 0x0, 0xff, 0x98, 0x4, + 0xff, 0xff, 0xa4, 0x7, 0x0, 0xfd, 0x13, 0x96, 0xee, 0x2, 0xff, 0xfc, + 0xe8, 0x8b, 0xe, 0x0, 0x5, 0xff, 0xff, 0x30, 0x7, 0x0, 0xff, 0x54, + 0x5, 0xff, 0xfe, 0xc5, 0x3, 0xb, 0x0, 0xfc, 0x4, 0xde, 0xff, 0xac, + 0xb, 0x0, 0xff, 0x58, 0x4, 0xff, 0xff, 0xd1, 0x9, 0x0, 0xff, 0x40, + 0xc, 0xff, 0xfe, 0xe2, 0x5a, 0x6, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, + 0x50, 0x3, 0x0, 0xff, 0xd0, 0xb, 0xff, 0xfd, 0xfc, 0xa1, 0x15, 0x6, + 0x0, 0xff, 0x1a, 0x4, 0xff, 0xfe, 0xfe, 0x11, 0x9, 0x0, 0x5, 0xff, + 0xff, 0x30, 0x7, 0x0, 0xff, 0x4d, 0x5, 0xff, 0xfc, 0xca, 0x5, 0x19, + 0xf3, 0x3, 0xff, 0xfe, 0xfe, 0x31, 0x9, 0x0, 0xfe, 0x30, 0xfd, 0x3, + 0xff, 0xfe, 0xf3, 0x1a, 0x6, 0x0, 0xfe, 0x12, 0xdb, 0x6, 0xff, 0xfe, + 0xd0, 0xd, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x1c, 0xee, 0x4, + 0xff, 0xfe, 0xf2, 0x20, 0xc, 0x0, 0xff, 0x5b, 0x2, 0xff, 0xfe, 0xfe, + 0x28, 0xa, 0x0, 0xff, 0x86, 0x4, 0xff, 0xff, 0x9b, 0x9, 0x0, 0xff, + 0x40, 0xe, 0xff, 0xfe, 0x9c, 0x3, 0x4, 0x0, 0xff, 0xe0, 0xf, 0xff, + 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xd, 0xff, 0xfe, 0xe5, 0x2d, 0x5, + 0x0, 0xff, 0x49, 0x4, 0xff, 0xff, 0xd7, 0xa, 0x0, 0x5, 0xff, 0xff, + 0x30, 0x6, 0x0, 0xfe, 0x17, 0xeb, 0x4, 0xff, 0xfe, 0xf4, 0x24, 0x2, + 0x0, 0xff, 0x76, 0x4, 0xff, 0xfe, 0xc3, 0x1, 0x7, 0x0, 0xfe, 0x1, + 0xc2, 0x4, 0xff, 0xff, 0x78, 0x7, 0x0, 0xff, 0x96, 0x3, 0xff, 0xfe, + 0xd1, 0xd4, 0x3, 0xff, 0xff, 0x88, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, + 0xfe, 0x2, 0xbd, 0x5, 0xff, 0xff, 0x5c, 0xc, 0x0, 0xfe, 0x1, 0xd3, + 0x3, 0xff, 0xff, 0x9e, 0xa, 0x0, 0xff, 0xa2, 0x4, 0xff, 0xff, 0x7d, + 0x9, 0x0, 0xff, 0x40, 0xf, 0xff, 0xff, 0x8d, 0x4, 0x0, 0xff, 0xe0, + 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xe, 0xff, 0xfe, 0xe7, + 0x1b, 0x4, 0x0, 0xff, 0x66, 0x4, 0xff, 0xff, 0xba, 0xa, 0x0, 0x5, + 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x1, 0xb7, 0x5, 0xff, 0xff, 0x64, + 0x3, 0x0, 0xfe, 0x6, 0xda, 0x4, 0xff, 0xff, 0x5a, 0x7, 0x0, 0xff, + 0x58, 0x4, 0xff, 0xfe, 0xdc, 0x7, 0x7, 0x0, 0xfc, 0xee, 0xff, 0xfc, + 0x46, 0x2, 0x0, 0xfc, 0x4f, 0xfe, 0xff, 0xe4, 0x5, 0xff, 0xff, 0x30, + 0x5, 0x0, 0xff, 0x75, 0x5, 0xff, 0xff, 0xa7, 0xd, 0x0, 0xff, 0x4c, + 0x4, 0xff, 0xfe, 0xfa, 0x1e, 0x9, 0x0, 0xff, 0xa2, 0x4, 0xff, 0xff, + 0x80, 0x9, 0x0, 0xff, 0x40, 0x10, 0xff, 0xff, 0x3c, 0x3, 0x0, 0xff, + 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0xf, 0xff, 0xff, + 0xac, 0x4, 0x0, 0xff, 0x6f, 0x4, 0xff, 0xff, 0xbd, 0xa, 0x0, 0x5, + 0xff, 0xff, 0x30, 0x5, 0x0, 0xff, 0x6d, 0x5, 0xff, 0xff, 0xae, 0x5, + 0x0, 0xff, 0x4a, 0x4, 0xff, 0xfe, 0xe5, 0xb, 0x5, 0x0, 0xfe, 0xa, + 0xe3, 0x4, 0xff, 0xff, 0x4d, 0x7, 0x0, 0xff, 0xd, 0x2, 0xff, 0xff, + 0xb6, 0x4, 0x0, 0xff, 0xbf, 0x7, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, + 0x31, 0xf9, 0x4, 0xff, 0xfe, 0xe1, 0x10, 0xd, 0x0, 0xff, 0xc6, 0x5, + 0xff, 0xff, 0x90, 0x9, 0x0, 0xff, 0x9b, 0x4, 0xff, 0xff, 0x9b, 0x9, + 0x0, 0xff, 0x40, 0x4, 0xff, 0xf9, 0xf0, 0x0, 0x5, 0x14, 0x32, 0x6f, + 0xd9, 0x5, 0xff, 0xff, 0xb3, 0x3, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, + 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xf9, 0x60, 0x0, 0xd, 0x21, + 0x50, 0xa4, 0xfd, 0x5, 0xff, 0xff, 0x29, 0x3, 0x0, 0xff, 0x5c, 0x4, + 0xff, 0xff, 0xd8, 0xa, 0x0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xfe, + 0x2b, 0xf8, 0x4, 0xff, 0xfe, 0xe5, 0x13, 0x6, 0x0, 0xff, 0xb6, 0x4, + 0xff, 0xff, 0x86, 0x5, 0x0, 0xff, 0x83, 0x4, 0xff, 0xff, 0xb7, 0x9, + 0x0, 0xfd, 0xee, 0xff, 0xb9, 0x4, 0x0, 0xfd, 0xbf, 0xff, 0xe5, 0x5, + 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x9, 0xd6, 0x4, 0xff, 0xfe, 0xfd, + 0x3f, 0xd, 0x0, 0xff, 0x3e, 0x6, 0xff, 0xfe, 0xf4, 0x14, 0x8, 0x0, + 0xff, 0x7a, 0x4, 0xff, 0xff, 0xd1, 0x9, 0x0, 0xff, 0x40, 0x4, 0xff, + 0xff, 0xf0, 0x5, 0x0, 0xfe, 0x8, 0xb6, 0x4, 0xff, 0xfe, 0xfb, 0xc, + 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, + 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0x4c, 0xfd, 0x4, 0xff, 0xff, + 0x7a, 0x3, 0x0, 0xff, 0x3f, 0x4, 0xff, 0xfe, 0xfc, 0x12, 0x9, 0x0, + 0x5, 0xff, 0xff, 0x30, 0x3, 0x0, 0xfe, 0x7, 0xd1, 0x5, 0xff, 0xff, + 0x44, 0x7, 0x0, 0xfe, 0x25, 0xfa, 0x3, 0xff, 0xfe, 0xf8, 0x22, 0x3, + 0x0, 0xfe, 0x21, 0xf8, 0x3, 0xff, 0xfe, 0xfa, 0x27, 0x9, 0x0, 0xfc, + 0x85, 0xff, 0xfd, 0x50, 0x2, 0x0, 0xfc, 0x54, 0xfe, 0xff, 0x7a, 0x5, + 0xff, 0xff, 0x30, 0x3, 0x0, 0xff, 0x96, 0x5, 0xff, 0xff, 0x87, 0xe, + 0x0, 0xff, 0xb8, 0x7, 0xff, 0xff, 0x82, 0x8, 0x0, 0xff, 0x42, 0x5, + 0xff, 0xff, 0x27, 0x8, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x6, + 0x0, 0xfe, 0x20, 0xfe, 0x4, 0xff, 0xff, 0x3b, 0x2, 0x0, 0xff, 0xe0, + 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, + 0x6, 0x0, 0xff, 0xab, 0x4, 0xff, 0xff, 0xb0, 0x3, 0x0, 0xfe, 0xb, + 0xfa, 0x4, 0xff, 0xff, 0x66, 0x9, 0x0, 0x5, 0xff, 0xff, 0x30, 0x3, + 0x0, 0xff, 0x8e, 0x5, 0xff, 0xff, 0x8d, 0x9, 0x0, 0xff, 0x89, 0x4, + 0xff, 0xff, 0xb1, 0x3, 0x0, 0xff, 0xaf, 0x4, 0xff, 0xff, 0x8c, 0x5, + 0x0, 0xff, 0xd2, 0x4, 0xe0, 0xff, 0xe3, 0x3, 0xff, 0xfe, 0xdb, 0xdf, + 0x2, 0xff, 0xfe, 0xfb, 0x85, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xff, + 0x4b, 0x5, 0xff, 0xfe, 0xcc, 0x5, 0xd, 0x0, 0xff, 0x31, 0x8, 0xff, + 0xfe, 0xee, 0xc, 0x7, 0x0, 0xfe, 0x7, 0xef, 0x4, 0xff, 0xff, 0x9c, + 0x8, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x7, 0x0, 0xff, 0xe6, + 0x4, 0xff, 0xff, 0x52, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, + 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0x72, + 0x4, 0xff, 0xff, 0xc6, 0x4, 0x0, 0xff, 0xba, 0x4, 0xff, 0xfe, 0xd6, + 0x3, 0x8, 0x0, 0x5, 0xff, 0xff, 0x30, 0x2, 0x0, 0xff, 0x45, 0x5, + 0xff, 0xfe, 0xd1, 0x7, 0x9, 0x0, 0xfe, 0xd, 0xe7, 0x4, 0xff, 0xfd, + 0x47, 0x0, 0x44, 0x4, 0xff, 0xfe, 0xe9, 0xe, 0x5, 0x0, 0xff, 0xf0, + 0xd, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x16, 0xea, 0x4, + 0xff, 0xfe, 0xf5, 0x26, 0xe, 0x0, 0xff, 0xa8, 0x4, 0xff, 0xff, 0xfd, + 0x4, 0xff, 0xff, 0x74, 0x8, 0x0, 0xff, 0x8f, 0x4, 0xff, 0xfe, 0xfd, + 0x35, 0x7, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x7, 0x0, 0xff, + 0xe9, 0x4, 0xff, 0xff, 0x52, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, + 0x50, 0x6, 0x0, 0xff, 0x14, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, + 0x60, 0x6, 0x0, 0xff, 0x75, 0x4, 0xff, 0xff, 0xc6, 0x4, 0x0, 0xff, + 0x51, 0x5, 0xff, 0xff, 0x6f, 0x8, 0x0, 0x5, 0xff, 0xfc, 0x30, 0x0, + 0x13, 0xe5, 0x4, 0xff, 0xfe, 0xf8, 0x2b, 0xb, 0x0, 0xff, 0x5f, 0x4, + 0xff, 0xfd, 0xd7, 0x9, 0xd5, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, + 0xe1, 0xd, 0xf0, 0xff, 0xa5, 0x5, 0xff, 0xfd, 0x30, 0x1, 0xb5, 0x5, + 0xff, 0xff, 0x66, 0xe, 0x0, 0xfe, 0x24, 0xfe, 0x3, 0xff, 0xfe, 0xfa, + 0x69, 0x4, 0xff, 0xfe, 0xe6, 0x6, 0x7, 0x0, 0xfe, 0x1b, 0xf4, 0x4, + 0xff, 0xfe, 0xd1, 0x5, 0x6, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, + 0x6, 0x0, 0xff, 0x32, 0x5, 0xff, 0xff, 0x36, 0x2, 0x0, 0xff, 0xe0, + 0x4, 0xff, 0xff, 0x50, 0x4, 0x0, 0xfd, 0x31, 0xb0, 0xaf, 0x7, 0x0, + 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0xbe, 0x4, 0xff, + 0xff, 0xaa, 0x4, 0x0, 0xfe, 0x2, 0xcf, 0x4, 0xff, 0xfe, 0xf4, 0x21, + 0x7, 0x0, 0x5, 0xff, 0xfd, 0x30, 0x0, 0xae, 0x5, 0xff, 0xff, 0x6c, + 0xc, 0x0, 0xfe, 0x1, 0xc7, 0x4, 0xff, 0xff, 0xc9, 0x4, 0xff, 0xfe, + 0xc9, 0x1, 0x15, 0x0, 0x5, 0xff, 0xfe, 0x30, 0x6a, 0x5, 0xff, 0xff, + 0xb1, 0xf, 0x0, 0xff, 0x9a, 0x4, 0xff, 0xfd, 0x9d, 0x1, 0xd2, 0x4, + 0xff, 0xff, 0x65, 0x8, 0x0, 0xff, 0x77, 0x5, 0xff, 0xff, 0x80, 0x6, + 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x5, 0x0, 0xfe, 0x16, 0xd2, + 0x4, 0xff, 0xfe, 0xf4, 0x8, 0x2, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, + 0x50, 0x2, 0x0, 0xfe, 0x37, 0xb0, 0x2, 0xff, 0xff, 0xb0, 0x7, 0x0, + 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0x73, 0x5, 0xff, + 0xff, 0x70, 0x5, 0x0, 0xff, 0x3c, 0x5, 0xff, 0xfe, 0xbe, 0x1, 0x6, + 0x0, 0x5, 0xff, 0xfe, 0x30, 0x64, 0x5, 0xff, 0xfe, 0xb7, 0x1, 0xd, + 0x0, 0xfe, 0x35, 0xfe, 0x8, 0xff, 0xff, 0x37, 0xc, 0x0, 0xff, 0x24, + 0x8, 0x30, 0xff, 0x21, 0x5, 0xff, 0xfe, 0x5a, 0xf7, 0x4, 0xff, 0xfe, + 0xe7, 0x14, 0xe, 0x0, 0xfe, 0x1a, 0xfa, 0x3, 0xff, 0xfc, 0xfe, 0x27, + 0x0, 0x5a, 0x4, 0xff, 0xfe, 0xdc, 0x2, 0x7, 0x0, 0xfe, 0x5, 0xd0, + 0x4, 0xff, 0xfe, 0xf7, 0x1f, 0x5, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, + 0xf0, 0x3, 0x0, 0xfd, 0x17, 0x71, 0xe7, 0x5, 0xff, 0xff, 0x9e, 0x3, + 0x0, 0xff, 0xe0, 0x4, 0xff, 0xfd, 0x50, 0x38, 0xb8, 0x4, 0xff, 0xff, + 0xb0, 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x2, 0x0, 0xfd, + 0x3, 0x42, 0xb3, 0x5, 0xff, 0xfe, 0xfa, 0x19, 0x6, 0x0, 0xff, 0x98, + 0x5, 0xff, 0xff, 0x54, 0x6, 0x0, 0x5, 0xff, 0xfe, 0x55, 0xf4, 0x4, + 0xff, 0xfe, 0xeb, 0x17, 0xf, 0x0, 0xff, 0x9d, 0x7, 0xff, 0xff, 0xa0, + 0xd, 0x0, 0xff, 0xc0, 0x8, 0xff, 0xff, 0xb0, 0x5, 0xff, 0xff, 0xb6, + 0x5, 0xff, 0xff, 0x96, 0xf, 0x0, 0xff, 0x8c, 0x4, 0xff, 0xff, 0xac, + 0x2, 0x0, 0xfe, 0x4, 0xdd, 0x4, 0xff, 0xff, 0x57, 0x8, 0x0, 0xff, + 0x38, 0x5, 0xff, 0xff, 0x9f, 0x5, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfc, + 0xf0, 0x7c, 0xc1, 0xdf, 0x7, 0xff, 0xfe, 0xf7, 0x23, 0x3, 0x0, 0xff, + 0xe0, 0x4, 0xff, 0xfe, 0x72, 0xe2, 0x5, 0xff, 0xff, 0xb0, 0x7, 0x0, + 0xff, 0xd0, 0x4, 0xff, 0xfc, 0x8b, 0xb8, 0xcd, 0xf6, 0x7, 0xff, 0xff, + 0x8e, 0x7, 0x0, 0xfe, 0xf, 0xea, 0x4, 0xff, 0xfe, 0xdc, 0x2, 0x5, + 0x0, 0x5, 0xff, 0xff, 0xaf, 0x5, 0xff, 0xff, 0x9c, 0x10, 0x0, 0xfe, + 0x17, 0xf1, 0x5, 0xff, 0xfe, 0xf2, 0x17, 0xd, 0x0, 0xff, 0xc0, 0x8, + 0xff, 0xff, 0xb0, 0x5, 0xff, 0xfe, 0x3c, 0xda, 0x4, 0xff, 0xfe, 0xfc, + 0x3a, 0xd, 0x0, 0xfe, 0x12, 0xf4, 0x4, 0xff, 0xff, 0x33, 0x3, 0x0, + 0xff, 0x68, 0x4, 0xff, 0xfe, 0xcf, 0x1, 0x8, 0x0, 0xff, 0xa3, 0x4, + 0xff, 0xfe, 0xfa, 0x1a, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfd, 0xf0, + 0x27, 0xf5, 0x8, 0xff, 0xff, 0x65, 0x4, 0x0, 0xff, 0xe0, 0x4, 0xff, + 0xfc, 0x50, 0x6, 0x60, 0xdc, 0x3, 0xff, 0xff, 0xb0, 0x7, 0x0, 0xff, + 0xd0, 0x4, 0xff, 0xfe, 0x60, 0xa8, 0x8, 0xff, 0xfe, 0xce, 0xa, 0x8, + 0x0, 0xff, 0x6a, 0x5, 0xff, 0xff, 0x50, 0x5, 0x0, 0x5, 0xff, 0xfe, + 0x39, 0xd6, 0x4, 0xff, 0xfe, 0xfd, 0x3f, 0x10, 0x0, 0xff, 0x72, 0x5, + 0xff, 0xff, 0x74, 0xe, 0x0, 0xf6, 0x7e, 0xfc, 0xff, 0xfa, 0xb6, 0xb9, + 0xfc, 0xff, 0xfa, 0x73, 0x5, 0xff, 0xfd, 0x30, 0x35, 0xfb, 0x4, 0xff, + 0xfe, 0xde, 0xd, 0xc, 0x0, 0xff, 0x7e, 0x4, 0xff, 0xff, 0xba, 0x4, + 0x0, 0xfe, 0x9, 0xe7, 0x4, 0xff, 0xff, 0x48, 0x8, 0x0, 0xfe, 0x24, + 0xfc, 0x4, 0xff, 0xff, 0x78, 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xfd, + 0xf0, 0x0, 0x66, 0x6, 0xff, 0xfe, 0xfd, 0x72, 0x5, 0x0, 0xff, 0xe0, + 0x4, 0xff, 0xff, 0x50, 0x2, 0x0, 0xfb, 0x4, 0x60, 0xdc, 0xff, 0xb0, + 0x7, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xfd, 0x60, 0x10, 0xe2, 0x6, 0xff, + 0xfe, 0xce, 0x15, 0x9, 0x0, 0xfe, 0x6, 0xdd, 0x4, 0xff, 0xff, 0xb4, + 0x5, 0x0, 0x5, 0xff, 0xfd, 0x30, 0x2f, 0xf9, 0x4, 0xff, 0xfe, 0xe2, + 0x10, 0xf, 0x0, 0xfe, 0x5, 0xd7, 0x3, 0xff, 0xfe, 0xd9, 0x6, 0xe, + 0x0, 0xfc, 0x91, 0xff, 0xfa, 0x34, 0x2, 0x0, 0xfc, 0x3a, 0xfa, 0xff, + 0x8e, 0x5, 0xff, 0xfd, 0x30, 0x0, 0x7a, 0x5, 0xff, 0xff, 0xa1, 0xb, + 0x0, 0xfe, 0xc, 0xec, 0x4, 0xff, 0xff, 0x41, 0x5, 0x0, 0xff, 0x77, + 0x4, 0xff, 0xff, 0xc1, 0x9, 0x0, 0xff, 0xae, 0x4, 0xff, 0xff, 0xcb, + 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0x2, 0x0, 0xff, 0xb1, + 0x4, 0xff, 0xfe, 0xd7, 0x40, 0x6, 0x0, 0xff, 0xe0, 0x4, 0xff, 0xff, + 0x50, 0x4, 0x0, 0xfd, 0x4, 0x5f, 0x87, 0x7, 0x0, 0xff, 0xd0, 0x4, + 0xff, 0xfc, 0x60, 0x0, 0x3f, 0xfd, 0x4, 0xff, 0xfe, 0xf3, 0x10, 0xb, + 0x0, 0xff, 0x71, 0x4, 0xff, 0xfe, 0xf9, 0xd, 0x4, 0x0, 0x5, 0xff, + 0xfd, 0x30, 0x0, 0x74, 0x5, 0xff, 0xff, 0xa8, 0x10, 0x0, 0xff, 0x47, + 0x3, 0xff, 0xff, 0x49, 0xf, 0x0, 0xfd, 0xf1, 0xff, 0xb4, 0x4, 0x0, + 0xfd, 0xbb, 0xff, 0xec, 0x5, 0xff, 0xfc, 0x30, 0x0, 0x3, 0xc3, 0x5, + 0xff, 0xff, 0x56, 0xa, 0x0, 0xff, 0x70, 0x4, 0xff, 0xff, 0xcb, 0x6, + 0x40, 0xfe, 0x4a, 0xf0, 0x4, 0xff, 0xff, 0x3a, 0x8, 0x0, 0xff, 0x4d, + 0x4, 0xff, 0xfe, 0xfd, 0xb, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, + 0xf0, 0x2, 0x0, 0xfa, 0x14, 0xe7, 0xf5, 0xb0, 0x52, 0x4, 0x7, 0x0, + 0xff, 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, + 0xff, 0x60, 0x2, 0x0, 0xff, 0x87, 0x5, 0xff, 0xff, 0x94, 0xb, 0x0, + 0xfe, 0x14, 0xfd, 0x4, 0xff, 0xff, 0x45, 0x4, 0x0, 0x5, 0xff, 0xfc, + 0x30, 0x0, 0x1, 0xbd, 0x5, 0xff, 0xff, 0x5d, 0x10, 0x0, 0xfd, 0xb1, + 0xff, 0xb3, 0xf, 0x0, 0xff, 0x8, 0x2, 0xff, 0xff, 0xb9, 0x4, 0x0, + 0xff, 0xc1, 0x7, 0xff, 0xff, 0x30, 0x2, 0x0, 0xfe, 0x1f, 0xf1, 0x4, + 0xff, 0xfe, 0xef, 0x1d, 0x8, 0x0, 0xfe, 0x6, 0xe2, 0x4, 0xff, 0xfe, + 0x53, 0xdc, 0x5, 0xff, 0xfe, 0xad, 0x85, 0x4, 0xff, 0xff, 0xb3, 0x8, + 0x0, 0xfe, 0x9, 0xfb, 0x4, 0xff, 0xff, 0x36, 0x3, 0x0, 0xff, 0x40, + 0x4, 0xff, 0xff, 0xf0, 0x3, 0x0, 0xfe, 0x14, 0x4, 0xa, 0x0, 0xff, + 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, + 0x60, 0x2, 0x0, 0xfe, 0x5, 0xcc, 0x5, 0xff, 0xff, 0x4b, 0xb, 0x0, + 0xff, 0xc6, 0x4, 0xff, 0xff, 0x73, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, + 0x2, 0x0, 0xfe, 0x1b, 0xed, 0x4, 0xff, 0xfe, 0xf2, 0x21, 0xf, 0x0, + 0xfd, 0x23, 0xf1, 0x24, 0x10, 0x0, 0xfc, 0xe5, 0xff, 0xfe, 0x5d, 0x2, + 0x1, 0xff, 0x65, 0x2, 0xff, 0xff, 0xe1, 0x5, 0xff, 0xff, 0x30, 0x3, + 0x0, 0xff, 0x5a, 0x5, 0xff, 0xfe, 0xbf, 0x2, 0x7, 0x0, 0xff, 0x62, + 0x4, 0xff, 0xfd, 0xd6, 0x1, 0x60, 0x4, 0xff, 0xfc, 0xfe, 0x2a, 0x15, + 0xf7, 0x4, 0xff, 0xff, 0x2d, 0x8, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, + 0x4f, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, + 0xe0, 0x4, 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, + 0x60, 0x3, 0x0, 0xfe, 0x27, 0xf5, 0x4, 0xff, 0xfe, 0xe9, 0x16, 0xa, + 0x0, 0xff, 0x95, 0x4, 0xff, 0xff, 0x8b, 0x4, 0x0, 0x5, 0xff, 0xff, + 0x30, 0x3, 0x0, 0xff, 0x53, 0x5, 0xff, 0xfe, 0xc5, 0x3, 0xf, 0x0, + 0xff, 0x41, 0x11, 0x0, 0xff, 0x84, 0x3, 0xff, 0xfe, 0xe4, 0xe5, 0x3, + 0xff, 0xff, 0x84, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, 0xff, 0xa5, 0x5, + 0xff, 0xff, 0x77, 0x6, 0x0, 0xfe, 0x2, 0xd8, 0x4, 0xff, 0xfc, 0x5e, + 0x0, 0x4, 0xdc, 0x3, 0xff, 0xff, 0xa8, 0x2, 0x0, 0xff, 0x93, 0x4, + 0xff, 0xff, 0xa5, 0x8, 0x0, 0xff, 0xbc, 0x4, 0xff, 0xff, 0x54, 0x3, + 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0x4, + 0xff, 0xff, 0x50, 0xe, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x4, + 0x0, 0xff, 0x67, 0x5, 0xff, 0xfe, 0xb4, 0x1, 0x9, 0x0, 0xff, 0x80, + 0x4, 0xff, 0xff, 0x90, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x4, 0x0, + 0xff, 0x9d, 0x5, 0xff, 0xff, 0x7e, 0xe, 0x0, 0xfd, 0xc, 0xd8, 0xc, + 0x10, 0x0, 0xfe, 0x8, 0xc3, 0x6, 0xff, 0xfe, 0xc5, 0x9, 0x5, 0xff, + 0xff, 0x30, 0x4, 0x0, 0xfe, 0xf, 0xe0, 0x4, 0xff, 0xfe, 0xfa, 0x32, + 0x5, 0x0, 0xff, 0x54, 0x4, 0xff, 0xfe, 0xe2, 0x4, 0x2, 0x0, 0xff, + 0x5e, 0x2, 0xff, 0xfe, 0xfe, 0x2a, 0x2, 0x0, 0xfe, 0x1e, 0xfb, 0x3, + 0xff, 0xfe, 0xfc, 0x22, 0x7, 0x0, 0xff, 0xc4, 0x4, 0xff, 0xff, 0x4c, + 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, + 0x4, 0xff, 0xff, 0x87, 0xa, 0x50, 0xff, 0x19, 0x3, 0x0, 0xff, 0xd0, + 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xff, 0xb1, 0x5, 0xff, 0xff, 0x6a, + 0x9, 0x0, 0xff, 0x86, 0x4, 0xff, 0xff, 0x8a, 0x4, 0x0, 0x5, 0xff, + 0xff, 0x30, 0x4, 0x0, 0xfe, 0xc, 0xdc, 0x4, 0xff, 0xfe, 0xfc, 0x38, + 0xd, 0x0, 0xfd, 0x78, 0xff, 0x78, 0x11, 0x0, 0xf7, 0x6, 0x78, 0xd6, + 0xfd, 0xfe, 0xd4, 0x75, 0x6, 0x0, 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, + 0xfe, 0x3d, 0xfd, 0x4, 0xff, 0xfe, 0xd8, 0xa, 0x4, 0x0, 0xff, 0xcc, + 0x4, 0xff, 0xff, 0x6c, 0x3, 0x0, 0xfc, 0x2, 0xd6, 0xff, 0xa8, 0x4, + 0x0, 0xff, 0xa1, 0x4, 0xff, 0xff, 0x97, 0x6, 0x0, 0xfe, 0x1, 0xee, + 0x4, 0xff, 0xff, 0x2a, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, + 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, + 0x4, 0xff, 0xff, 0x60, 0x5, 0x0, 0xfe, 0x14, 0xe7, 0x4, 0xff, 0xfe, + 0xf6, 0x29, 0x8, 0x0, 0xff, 0xb3, 0x4, 0xff, 0xff, 0x67, 0x4, 0x0, + 0x5, 0xff, 0xff, 0x30, 0x5, 0x0, 0xfe, 0x37, 0xfc, 0x4, 0xff, 0xfe, + 0xdc, 0xc, 0xb, 0x0, 0xfb, 0xc, 0xec, 0xff, 0xec, 0x10, 0x13, 0x0, + 0xfe, 0x2, 0x1, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xff, + 0x84, 0x5, 0xff, 0xff, 0x98, 0x3, 0x0, 0xff, 0x45, 0x4, 0xff, 0xfe, + 0xeb, 0x9, 0x4, 0x0, 0xfd, 0x58, 0xfc, 0x27, 0x4, 0x0, 0xfe, 0x2a, + 0xfe, 0x3, 0xff, 0xfe, 0xf7, 0x19, 0x5, 0x0, 0xff, 0x3a, 0x4, 0xff, + 0xfe, 0xf3, 0x4, 0x3, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, + 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, + 0xff, 0xff, 0x60, 0x6, 0x0, 0xff, 0x47, 0x5, 0xff, 0xfe, 0xcf, 0x7, + 0x6, 0x0, 0xfe, 0xa, 0xf4, 0x4, 0xff, 0xff, 0x34, 0x4, 0x0, 0x5, + 0xff, 0xff, 0x30, 0x6, 0x0, 0xff, 0x7c, 0x5, 0xff, 0xff, 0x9e, 0xb, + 0x0, 0xff, 0x7c, 0x3, 0xff, 0xff, 0x80, 0xa, 0x0, 0xff, 0xf, 0xd, + 0x10, 0xff, 0xb, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x5, 0xca, + 0x5, 0xff, 0xff, 0x4d, 0x2, 0x0, 0xff, 0xbe, 0x4, 0xff, 0xff, 0x7a, + 0x5, 0x0, 0xfe, 0x2, 0x76, 0x6, 0x0, 0xff, 0xaf, 0x4, 0xff, 0xff, + 0x88, 0x5, 0x0, 0xff, 0xa8, 0x4, 0xff, 0xff, 0xaf, 0x4, 0x0, 0xff, + 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, 0xf, 0xff, 0xff, + 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, 0x7, 0x0, 0xff, + 0x91, 0x5, 0xff, 0xff, 0x8a, 0x6, 0x0, 0xff, 0x70, 0x4, 0xff, 0xfe, + 0xea, 0x2, 0x4, 0x0, 0x5, 0xff, 0xff, 0x30, 0x6, 0x0, 0xfe, 0x3, + 0xc5, 0x5, 0xff, 0xff, 0x54, 0x9, 0x0, 0xfe, 0x10, 0xf0, 0x3, 0xff, + 0xfe, 0xf0, 0x10, 0x9, 0x0, 0xff, 0xf0, 0xd, 0xff, 0xff, 0xb0, 0x5, + 0xff, 0xff, 0x30, 0x7, 0x0, 0xfe, 0x25, 0xf4, 0x4, 0xff, 0xfd, 0xeb, + 0x17, 0x37, 0x4, 0xff, 0xfe, 0xf2, 0x10, 0xd, 0x0, 0xff, 0x37, 0x4, + 0xff, 0xfe, 0xf1, 0x10, 0x3, 0x0, 0xff, 0x3f, 0x5, 0xff, 0xff, 0x50, + 0x4, 0x0, 0xff, 0x40, 0x4, 0xff, 0xff, 0xf0, 0xf, 0x0, 0xff, 0xe0, + 0xf, 0xff, 0xff, 0x50, 0x3, 0x0, 0xff, 0xd0, 0x4, 0xff, 0xff, 0x60, + 0x7, 0x0, 0xfe, 0x8, 0xd3, 0x4, 0xff, 0xfe, 0xfe, 0x42, 0x4, 0x0, + 0xfe, 0x15, 0xeb, 0x4, 0xff, 0xff, 0x8d, 0x5, 0x0, 0x5, 0xff, 0xff, + 0x30, 0x7, 0x0, 0xfe, 0x20, 0xf2, 0x4, 0xff, 0xfe, 0xee, 0x1b, 0x8, + 0x0, 0xff, 0x80, 0x5, 0xff, 0xff, 0x80, 0x9, 0x0, 0xff, 0xf0, 0xd, + 0xff, 0xff, 0xb0, 0x5, 0xd0, 0xff, 0x27, 0x8, 0x0, 0xff, 0x5f, 0x5, + 0xd0, 0xfe, 0x87, 0x85, 0x4, 0xd0, 0xff, 0x78, 0xf, 0x0, 0xff, 0xa3, + 0x4, 0xd0, 0xff, 0x59, 0x2, 0x0, 0xfe, 0x12, 0xe0, 0x4, 0xff, 0xfe, + 0xda, 0x3, 0x4, 0x0, 0xff, 0x34, 0x4, 0xd0, 0xff, 0xc3, 0xf, 0x0, + 0xff, 0xb6, 0xf, 0xd0, 0xff, 0x41, 0x3, 0x0, 0xff, 0xa9, 0x4, 0xd0, + 0xff, 0x4e, 0x8, 0x0, 0xfe, 0x2e, 0xcf, 0x4, 0xd0, 0xfe, 0xb4, 0x5, + 0x2, 0x0, 0xfe, 0x1, 0xb4, 0x4, 0xff, 0xfe, 0xfa, 0x21, 0x5, 0x0, + 0x5, 0xd0, 0xff, 0x27, 0x8, 0x0, 0xff, 0x59, 0x5, 0xd0, 0xff, 0x8c, + 0x7, 0x0, 0xfe, 0x6, 0xc0, 0x5, 0xd0, 0xfe, 0xc0, 0x6, 0x8, 0x0, + 0xff, 0xc3, 0xd, 0xd0, 0xff, 0x8f, 0x31, 0x0, 0xfe, 0x7, 0xc0, 0x5, + 0xff, 0xff, 0x53, 0x46, 0x0, 0xff, 0x8c, 0x5, 0xff, 0xff, 0x91, 0x72, + 0x0, 0xfe, 0x6, 0xb2, 0x5, 0xff, 0xff, 0xb0, 0x46, 0x0, 0xff, 0x7b, + 0x5, 0xff, 0xfe, 0xe2, 0xe, 0x71, 0x0, 0xfe, 0xe, 0xbb, 0x5, 0xff, + 0xfe, 0xe4, 0x17, 0x44, 0x0, 0xfe, 0x1, 0x8d, 0x5, 0xff, 0xfe, 0xfa, + 0x3d, 0x72, 0x0, 0xff, 0xb6, 0x5, 0xff, 0xfe, 0xf6, 0x35, 0x45, 0x0, + 0xff, 0x7a, 0x6, 0xff, 0xff, 0x69, 0x73, 0x0, 0xff, 0x72, 0x4, 0xff, + 0xfe, 0xfa, 0x47, 0x46, 0x0, 0xff, 0x35, 0x5, 0xff, 0xff, 0x7d, 0x74, + 0x0, 0xfe, 0xc, 0xee, 0x2, 0xff, 0xfe, 0xf6, 0x4b, 0x48, 0x0, 0xff, + 0xbd, 0x3, 0xff, 0xff, 0x7f, 0x76, 0x0, 0xfc, 0x84, 0xff, 0xeb, 0x3a, + 0x49, 0x0, 0xfc, 0x46, 0xff, 0xfb, 0x66, 0x77, 0x0, 0xfd, 0x15, 0xc4, + 0x1f, 0x4b, 0x0, 0xfe, 0xba, 0x40, 0x48, 0x0}; static const Image kaspersky_logo_image = {200, 43, 3548, kaspersky_logo_data}; const VariantAnimation kaspersky_logo = { @@ -52,8 +344,7 @@ const VariantAnimation kaspersky_logo = { {28, 11, 25, 90, &kaspersky_logo_image}, {28, 11, 25, 95, &kaspersky_logo_image}, {28, 11, 25, 100, &kaspersky_logo_image}, - } -}; + }}; const VariantAnimation kaspersky_logo_reversed = { 21, { @@ -78,9 +369,7 @@ const VariantAnimation kaspersky_logo_reversed = { {28, 11, 25, 10, &kaspersky_logo_image}, {28, 11, 25, 5, &kaspersky_logo_image}, {28, 11, 25, 0, &kaspersky_logo_image}, - } -}; - + }}; const VariantAnimation kaspersky_screensaver = { 112, @@ -197,8 +486,7 @@ const VariantAnimation kaspersky_screensaver = { {26, 11, 125, 60, &kaspersky_logo_image}, {27, 11, 125, 60, &kaspersky_logo_image}, {28, 11, 125, 60, &kaspersky_logo_image}, - } -}; + }}; VariantInfo kaspersky_svi __attribute__((section("variant_info"))) = { .version = 1, @@ -206,5 +494,4 @@ VariantInfo kaspersky_svi __attribute__((section("variant_info"))) = { .logo = &kaspersky_logo, .logo_reversed = &kaspersky_logo_reversed, .screensaver_timeout = ONE_SEC * 60 * 10, - .screensaver = &kaspersky_screensaver -}; + .screensaver = &kaspersky_screensaver}; diff --git a/tools/variant/keepkey.c b/tools/variant/keepkey.c index 3cc39d0cc..85ee61532 100644 --- a/tools/variant/keepkey.c +++ b/tools/variant/keepkey.c @@ -3,6 +3,5 @@ #include "keepkey/board/timer.h" #include "keepkey/board/variant.h" -VariantInfo keepkey_svi __attribute__((section("variant_info"))) = { - VARIANTINFO_KEEPKEY -}; +VariantInfo keepkey_svi + __attribute__((section("variant_info"))) = {VARIANTINFO_KEEPKEY}; diff --git a/tools/variant/salt.c b/tools/variant/salt.c index ebbf765b2..e15134d0b 100644 --- a/tools/variant/salt.c +++ b/tools/variant/salt.c @@ -3,6 +3,5 @@ #include "keepkey/board/timer.h" #include "keepkey/board/variant.h" -VariantInfo salt_svi __attribute__((section("variant_info"))) = { - VARIANTINFO_SALT -}; +VariantInfo salt_svi + __attribute__((section("variant_info"))) = {VARIANTINFO_SALT}; diff --git a/unittests/board/board.cpp b/unittests/board/board.cpp index 5b65f7c7c..ec27b5acb 100644 --- a/unittests/board/board.cpp +++ b/unittests/board/board.cpp @@ -5,5 +5,5 @@ extern "C" { #include "gtest/gtest.h" TEST(Board, Shutdown) { - EXPECT_EXIT(shutdown(), ::testing::ExitedWithCode(1), ""); + EXPECT_EXIT(shutdown(), ::testing::ExitedWithCode(1), ""); } diff --git a/unittests/board/memcmp_s.cpp b/unittests/board/memcmp_s.cpp index f52ec2ba0..763629d82 100644 --- a/unittests/board/memcmp_s.cpp +++ b/unittests/board/memcmp_s.cpp @@ -11,24 +11,25 @@ TEST(Board, Memcmps) { size_t len; int expected; } vec[] = { - { "A1234567890123456789012345678901", - "A1234567890123456789012345678901", 32, 0 }, - { "B123456789012345678901234567890101234567890123456789012345678901", - "B123456789012345678901234567890101234567890123456789012345678901", 63, 0 }, - { "C1234567890123456789012345678901", - "C123456789012345678901234567890A", 32, 1 }, - { "D ", - "D F", 32, 1 }, - { "E ", - "E ", 32, 0 }, + {"A1234567890123456789012345678901", "A1234567890123456789012345678901", + 32, 0}, + {"B123456789012345678901234567890101234567890123456789012345678901", + "B123456789012345678901234567890101234567890123456789012345678901", 63, + 0}, + {"C1234567890123456789012345678901", "C123456789012345678901234567890A", + 32, 1}, + {"D ", "D F", + 32, 1}, + {"E ", "E ", + 32, 0}, }; for (const auto &v : vec) { for (size_t i = 0; i < 1000; i++) { ASSERT_EQ(memcmp_s(v.lhs, v.rhs, v.len), v.expected) - << "lhs: " << v.lhs << "\n" - << "rhs: " << v.rhs << "\n" - << "len: " << v.len << "\n"; + << "lhs: " << v.lhs << "\n" + << "rhs: " << v.rhs << "\n" + << "len: " << v.len << "\n"; } } } diff --git a/unittests/crypto/rand.cpp b/unittests/crypto/rand.cpp index 7746fb4da..8686d0ecd 100644 --- a/unittests/crypto/rand.cpp +++ b/unittests/crypto/rand.cpp @@ -5,33 +5,33 @@ extern "C" { #include "gtest/gtest.h" TEST(Crypto, PermuteChar) { - char arr[4]; - for (size_t i = 0; i < sizeof(arr); i++) { - arr[i] = i; - } - random_permute_char(arr, sizeof(arr)); - char count[sizeof(arr)]; - memset(count, 0, sizeof(count)); - for (size_t i = 0; i < sizeof(arr); i++) { - count[arr[i]]++; - } - for (size_t i = 0; i < sizeof(arr); i++) { - ASSERT_EQ(count[i], (char)1); - } + char arr[4]; + for (size_t i = 0; i < sizeof(arr); i++) { + arr[i] = i; + } + random_permute_char(arr, sizeof(arr)); + char count[sizeof(arr)]; + memset(count, 0, sizeof(count)); + for (size_t i = 0; i < sizeof(arr); i++) { + count[arr[i]]++; + } + for (size_t i = 0; i < sizeof(arr); i++) { + ASSERT_EQ(count[i], (char)1); + } } TEST(Crypto, PermuteU16) { - uint16_t arr[4]; - for (size_t i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { - arr[i] = i; - } - random_permute_u16(arr, sizeof(arr)/sizeof(arr[0])); - uint16_t count[sizeof(arr)/sizeof(arr[0])]; - memset(count, 0, sizeof(count)); - for (size_t i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { - count[arr[i]]++; - } - for (size_t i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { - ASSERT_EQ(count[i], 1u); - } + uint16_t arr[4]; + for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { + arr[i] = i; + } + random_permute_u16(arr, sizeof(arr) / sizeof(arr[0])); + uint16_t count[sizeof(arr) / sizeof(arr[0])]; + memset(count, 0, sizeof(count)); + for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { + count[arr[i]]++; + } + for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { + ASSERT_EQ(count[i], 1u); + } } diff --git a/unittests/crypto/vuln1845.cpp b/unittests/crypto/vuln1845.cpp index a1dd3010f..9abe4a6a4 100644 --- a/unittests/crypto/vuln1845.cpp +++ b/unittests/crypto/vuln1845.cpp @@ -12,28 +12,30 @@ extern "C" { #include #include - TEST(Vuln1845, Bech32Decode) { - std::string input = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg"; - std::vector hrp(input.size() - 6); - std::vector data(input.size() - 8); - - size_t data_len; - ASSERT_NE(1, bech32_decode(&hrp[0], &data[0], &data_len, input.c_str())); + std::string input = + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst" + "uvwxyzabcdefg"; + std::vector hrp(input.size() - 6); + std::vector data(input.size() - 8); + + size_t data_len; + ASSERT_NE(1, bech32_decode(&hrp[0], &data[0], &data_len, input.c_str())); } TEST(Vuln1845, CashAddrDecode) { - std::vector addr_raw(MAX_ADDR_RAW_SIZE); - size_t len; - - ASSERT_FALSE(cash_addr_decode(&addr_raw[0], &len, "bitcoincash:", - "\x53\x74\x32\x63\x74\x79\x70\x63\x45\x74\x53\x49\x3a\x4d\x63\x4e" - "\x53\x74\x36\x63\x74\x65\x63\x43\x43\x43\x43\x43\x43\x4a\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" - "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x61\x00\x61\x61" - "\x28")); + std::vector addr_raw(MAX_ADDR_RAW_SIZE); + size_t len; + + ASSERT_FALSE(cash_addr_decode( + &addr_raw[0], &len, "bitcoincash:", + "\x53\x74\x32\x63\x74\x79\x70\x63\x45\x74\x53\x49\x3a\x4d\x63\x4e" + "\x53\x74\x36\x63\x74\x65\x63\x43\x43\x43\x43\x43\x43\x4a\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43" + "\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x61\x00\x61\x61" + "\x28")); } diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index e1bbbe4cf..682c4a088 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -11,202 +11,203 @@ extern "C" { static const int MaxLength = 256; -template static std::string arrayToStr(const uint32_t (&address_n)[size]) { - std::string str; - std::stringstream OS(str); - OS << "{"; - for (int i = 0; i < size; ++i) { - OS << address_n[i]; - if (i + 1 != size) - OS << ", "; - } - OS << "}"; - return OS.str(); +template +static std::string arrayToStr(const uint32_t (&address_n)[size]) { + std::string str; + std::stringstream OS(str); + OS << "{"; + for (int i = 0; i < size; ++i) { + OS << address_n[i]; + if (i + 1 != size) OS << ", "; + } + OS << "}"; + return OS.str(); } TEST(Coins, Bip32PathToString) { - struct { - uint32_t address_n[10]; - size_t address_n_count; - std::string expected; - } vector[] = { - {{ 0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 0, 0 }, 5, "m/44'/0'/0'/0/0"}, - {{ 0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0 }, 3, "m/44'/0'/0'"}, - {{ }, 0, "m/"}, - {{ 0 }, 1, "m/0"}, - {{ 0,0,0,0,0,0,0,0,0,0 }, 10, "m/0/0/0/0/0/0/0/0/0/0" }, - {{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, 10, - "m/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'"}, - }; - - for (const auto &vec : vector) { - // Check that we get it right when provided with exactly enough characters. - std::vector exact_len(vec.expected.size() + 1); - ASSERT_TRUE(bip32_path_to_string(&exact_len[0], exact_len.size(), &vec.address_n[0], vec.address_n_count)) - << vec.expected; - ASSERT_EQ(&exact_len[0], vec.expected) + struct { + uint32_t address_n[10]; + size_t address_n_count; + std::string expected; + } vector[] = { + {{0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 0, 0}, + 5, + "m/44'/0'/0'/0/0"}, + {{0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0}, 3, "m/44'/0'/0'"}, + {{}, 0, "m/"}, + {{0}, 1, "m/0"}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, "m/0/0/0/0/0/0/0/0/0/0"}, + {{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, + 10, + "m/2147483647'/2147483647'/2147483647'/2147483647'/2147483647'/" + "2147483647'/2147483647'/2147483647'/2147483647'/2147483647'"}, + }; + + for (const auto &vec : vector) { + // Check that we get it right when provided with exactly enough characters. + std::vector exact_len(vec.expected.size() + 1); + ASSERT_TRUE(bip32_path_to_string(&exact_len[0], exact_len.size(), + &vec.address_n[0], vec.address_n_count)) + << vec.expected; + ASSERT_EQ(&exact_len[0], vec.expected) + << "address_n: " << arrayToStr(vec.address_n) << "\n" + << "address_n_count: " << vec.address_n_count << "\n"; + + // Check that we report success iff we were able to write the whole string. + for (int i = 0; i < MaxLength; ++i) { + char str[MaxLength]; + memset(str, 0, sizeof(str)); + if (bip32_path_to_string(&str[0], i, &vec.address_n[0], + vec.address_n_count)) { + ASSERT_EQ(&str[0], vec.expected) << "address_n: " << arrayToStr(vec.address_n) << "\n" - << "address_n_count: " << vec.address_n_count << "\n"; - - // Check that we report success iff we were able to write the whole string. - for (int i = 0; i < MaxLength; ++i) { - char str[MaxLength]; - memset(str, 0, sizeof(str)); - if (bip32_path_to_string(&str[0], i, &vec.address_n[0], vec.address_n_count)) { - ASSERT_EQ(&str[0], vec.expected) - << "address_n: " << arrayToStr(vec.address_n) << "\n" - << "address_n_count: " << vec.address_n_count << "\n" - << "i: " << i << "\n"; - } - } + << "address_n_count: " << vec.address_n_count << "\n" + << "i: " << i << "\n"; + } } + } } TEST(Coins, TableSanity) { - for (int i = 0; i < COINS_COUNT; ++i) { - const auto &coin = coins[i]; - - if (!coin.has_contract_address) - continue; - - const TokenType *token; - if (!tokenByTicker(1, coin.coin_shortcut, &token)) { - EXPECT_TRUE(false) - << "Can't uniquely find " << coin.coin_shortcut; - continue; - } - - EXPECT_TRUE(memcmp(coin.contract_address.bytes, token->address, - coin.contract_address.size) == 0) - << "Contract address mismatch for " << coin.coin_shortcut; + for (int i = 0; i < COINS_COUNT; ++i) { + const auto &coin = coins[i]; + + if (!coin.has_contract_address) continue; + + const TokenType *token; + if (!tokenByTicker(1, coin.coin_shortcut, &token)) { + EXPECT_TRUE(false) << "Can't uniquely find " << coin.coin_shortcut; + continue; } + + EXPECT_TRUE(memcmp(coin.contract_address.bytes, token->address, + coin.contract_address.size) == 0) + << "Contract address mismatch for " << coin.coin_shortcut; + } } TEST(Coins, BIP32AccountName) { - struct { - const char *coin_name; - uint32_t address_n[10]; - size_t address_n_count; - bool expected; - std::string text; - } vector[] = { - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|0, 0, 0 }, - 5, true, "Bitcoin Account #0\nAddress #0" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|0, 0, 1 }, - 5, true, "Bitcoin Account #0\nAddress #1" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|0, 1, 0 }, - 5, true, "Bitcoin Account #0\nChange Address #0" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|0, 1, 1 }, - 5, true, "Bitcoin Account #0\nChange Address #1" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|1, 2, 0 }, - 5, false, "" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|1, 2, 1 }, - 5, false, "" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|1, 1, 1, 1 }, - 6, false, "" - }, - { - "Bitcoin", - { 0x80000000|44, 0x80000000|0, 0x80000000|1, 1, 1 }, - 5, true, "Bitcoin Account #1\nChange Address #1" - }, - { - "Ethereum", - { 0x80000000|44, 0x80000000|60, 0x80000000|1, 0, 0 }, - 5, true, "Ethereum Account #1" - }, - { - "SALT", - { 0x80000000|44, 0x80000000|60, 0x80000000|1, 0, 0 }, - 5, true, "Ethereum Account #1" - }, - { - "Ethereum", - { 0x80000000|44, 0x80000000|60, 0x80000000|1, 1, 0 }, - 5, false, "" - }, - { - "Ethereum", - { 0x80000000|44, 0x80000000|60, 0x80000000|1, 0, 1 }, - 5, false, "" - }, - { - "EOS", - { 0x80000000|44, 0x80000000|194, 0x80000000|0, 0, 0 }, - 5, true, "EOS Account #0" - }, - { - "EOS", - { 0x80000000|44, 0x80000000|194, 0x80000000|42, 0, 0 }, - 5, true, "EOS Account #42" - }, - { - "Cosmos", - { 0x80000000|44, 0x80000000|118, 0x80000000|9, 0, 0 }, - 5, true, "Cosmos Account #9" - } - }; - - for (const auto &vec : vector) { - char node_str[NODE_STRING_LENGTH]; - memset(node_str, 0, sizeof(node_str)); - ASSERT_EQ(bip32_node_to_string(node_str, sizeof(node_str), - coinByName(vec.coin_name), - vec.address_n, - vec.address_n_count, - /*whole_account=*/false, - /*show_addridx=*/true), - vec.expected) - << "element: " << (&vec - &vector[0]) << "\n" - << "coin: " << vec.coin_name << "\n" - << "expected: " << vec.expected << "\n" - << "text: \"" << vec.text << "\n" - << "node_str: \"" << node_str << "\n"; - if (vec.expected) { - EXPECT_EQ(vec.text, node_str); - } + struct { + const char *coin_name; + uint32_t address_n[10]; + size_t address_n_count; + bool expected; + std::string text; + } vector[] = {{"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 0, 0}, + 5, + true, + "Bitcoin Account #0\nAddress #0"}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 0, 1}, + 5, + true, + "Bitcoin Account #0\nAddress #1"}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 1, 0}, + 5, + true, + "Bitcoin Account #0\nChange Address #0"}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 0, 1, 1}, + 5, + true, + "Bitcoin Account #0\nChange Address #1"}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 1, 2, 0}, + 5, + false, + ""}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 1, 2, 1}, + 5, + false, + ""}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 1, 1, 1, 1}, + 6, + false, + ""}, + {"Bitcoin", + {0x80000000 | 44, 0x80000000 | 0, 0x80000000 | 1, 1, 1}, + 5, + true, + "Bitcoin Account #1\nChange Address #1"}, + {"Ethereum", + {0x80000000 | 44, 0x80000000 | 60, 0x80000000 | 1, 0, 0}, + 5, + true, + "Ethereum Account #1"}, + {"SALT", + {0x80000000 | 44, 0x80000000 | 60, 0x80000000 | 1, 0, 0}, + 5, + true, + "Ethereum Account #1"}, + {"Ethereum", + {0x80000000 | 44, 0x80000000 | 60, 0x80000000 | 1, 1, 0}, + 5, + false, + ""}, + {"Ethereum", + {0x80000000 | 44, 0x80000000 | 60, 0x80000000 | 1, 0, 1}, + 5, + false, + ""}, + {"EOS", + {0x80000000 | 44, 0x80000000 | 194, 0x80000000 | 0, 0, 0}, + 5, + true, + "EOS Account #0"}, + {"EOS", + {0x80000000 | 44, 0x80000000 | 194, 0x80000000 | 42, 0, 0}, + 5, + true, + "EOS Account #42"}, + {"Cosmos", + {0x80000000 | 44, 0x80000000 | 118, 0x80000000 | 9, 0, 0}, + 5, + true, + "Cosmos Account #9"}}; + + for (const auto &vec : vector) { + char node_str[NODE_STRING_LENGTH]; + memset(node_str, 0, sizeof(node_str)); + ASSERT_EQ(bip32_node_to_string(node_str, sizeof(node_str), + coinByName(vec.coin_name), vec.address_n, + vec.address_n_count, + /*whole_account=*/false, + /*show_addridx=*/true), + vec.expected) + << "element: " << (&vec - &vector[0]) << "\n" + << "coin: " << vec.coin_name << "\n" + << "expected: " << vec.expected << "\n" + << "text: \"" << vec.text << "\n" + << "node_str: \"" << node_str << "\n"; + if (vec.expected) { + EXPECT_EQ(vec.text, node_str); } + } } TEST(Coins, CoinByNameOrTicker) { - const CoinType *ticker = coinByNameOrTicker("ZRX"); - const CoinType *name = coinByNameOrTicker("0x"); - ASSERT_NE(ticker, nullptr); - ASSERT_NE(name, nullptr); - ASSERT_EQ(name, ticker); - EXPECT_EQ(ticker->coin_name, std::string("0x")); + const CoinType *ticker = coinByNameOrTicker("ZRX"); + const CoinType *name = coinByNameOrTicker("0x"); + ASSERT_NE(ticker, nullptr); + ASSERT_NE(name, nullptr); + ASSERT_EQ(name, ticker); + EXPECT_EQ(ticker->coin_name, std::string("0x")); } TEST(Coins, CoinByChainAddress) { - const CoinType *zrx = coinByChainAddress(1, (const uint8_t*)"\xE4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6D\xaF\xA5\xeb\xDe\x1F\x46\x99\xF4\x98"); - ASSERT_NE(zrx, nullptr); - EXPECT_EQ(zrx->coin_name, std::string("0x")); - EXPECT_EQ(zrx->coin_shortcut, std::string("ZRX")); + const CoinType *zrx = coinByChainAddress(1, (const uint8_t*)"\xE4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6D\xaF\xA5\xeb\xDe\x1F\x46\x99\xF4\x98"); + ASSERT_NE(zrx, nullptr); + EXPECT_EQ(zrx->coin_name, std::string("0x")); + EXPECT_EQ(zrx->coin_shortcut, std::string("ZRX")); } TEST(Coins, TokenByChainAddress) { - const TokenType *zrx = tokenByChainAddress(1, (const uint8_t*)"\xE4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6D\xaF\xA5\xeb\xDe\x1F\x46\x99\xF4\x98"); - ASSERT_NE(zrx, nullptr); - EXPECT_EQ(zrx->ticker, std::string(" ZRX")); + const TokenType *zrx = tokenByChainAddress(1, (const uint8_t*)"\xE4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6D\xaF\xA5\xeb\xDe\x1F\x46\x99\xF4\x98"); + ASSERT_NE(zrx, nullptr); + EXPECT_EQ(zrx->ticker, std::string(" ZRX")); } diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index 8361cbfab..64c128f8a 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -8,51 +8,66 @@ extern "C" { #include "gtest/gtest.h" #include -TEST(Cosmos, CosmosGetAddress) -{ - HDNode node = { - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0x03, 0xb7, 0x32, 0x9f, 0x67, 0x8e, 0x0a, 0xc1, 0x21, 0x4b, 0x77, 0x23, 0x57, 0x54, 0x66, 0x21, 0x9c, 0x77, 0xfe, 0xdb, 0xdd, 0x95, 0x5c, 0x33, 0x29, 0x1a, 0x74, 0xf1, 0x8b, 0xf5, 0xc8, 0xa4, 0xe2}, - &secp256k1_info}; - char addr[46]; - ASSERT_TRUE(tendermint_getAddress(&node, "cosmos", addr)); - EXPECT_EQ(std::string("cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); +TEST(Cosmos, CosmosGetAddress) { + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x03, 0xb7, 0x32, 0x9f, 0x67, 0x8e, 0x0a, 0xc1, 0x21, 0x4b, 0x77, + 0x23, 0x57, 0x54, 0x66, 0x21, 0x9c, 0x77, 0xfe, 0xdb, 0xdd, 0x95, + 0x5c, 0x33, 0x29, 0x1a, 0x74, 0xf1, 0x8b, 0xf5, 0xc8, 0xa4, 0xe2}, + &secp256k1_info}; + char addr[46]; + ASSERT_TRUE(tendermint_getAddress(&node, "cosmos", addr)); + EXPECT_EQ(std::string("cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); } -TEST(Cosmos, CosmosSignTx) -{ - HDNode node = { - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76 }, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - &secp256k1_info - }; - hdnode_fill_public_key(&node); +TEST(Cosmos, CosmosSignTx) { + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, + 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, + 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + &secp256k1_info}; + hdnode_fill_public_key(&node); - const CosmosSignTx msg = { - 5, {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}, // address_n - true, 0, // account_number - true, "cosmoshub-2", // chain_id - true, 5000, // fee_amount - true, 200000, // gas - true, "", // memo - true, 0, // sequence - true, 1 // msg_count - }; - ASSERT_TRUE(cosmos_signTxInit(&node, &msg)); + const CosmosSignTx msg = { + 5, {0x80000000 | 44, 0x80000000 | 118, 0x80000000, 0, 0}, // address_n + true, 0, // account_number + true, "cosmoshub-2", // chain_id + true, 5000, // fee_amount + true, 200000, // gas + true, "", // memo + true, 0, // sequence + true, 1 // msg_count + }; + ASSERT_TRUE(cosmos_signTxInit(&node, &msg)); - ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + ASSERT_TRUE(cosmos_signTxUpdateMsgSend( + 100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); - uint8_t public_key[33]; - uint8_t signature[64]; - ASSERT_TRUE(cosmos_signTxFinalize(public_key, signature)); + uint8_t public_key[33]; + uint8_t signature[64]; + ASSERT_TRUE(cosmos_signTxFinalize(public_key, signature)); - EXPECT_TRUE(memcmp(signature, (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39", 64) == 0); + EXPECT_TRUE( + memcmp(signature, + (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a" + "\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e" + "\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51" + "\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e" + "\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39", + 64) == 0); } diff --git a/unittests/firmware/eos.cpp b/unittests/firmware/eos.cpp index 192958d74..c15f220e1 100644 --- a/unittests/firmware/eos.cpp +++ b/unittests/firmware/eos.cpp @@ -8,98 +8,100 @@ extern "C" { #include TEST(EOS, FormatNameVec) { - struct { - uint64_t value; - const char *name; - bool ret; - } vec[] = { - { 0x5530ea0000000000, "eosio", true }, - { 0x0000000000ea3055, nullptr, true }, - { 0x5530ea031ec65520, "eosio.system", true }, - { 0xb68d3cbb3e000000, "quantity", true }, - { 0x9ab864229a9e4000, "newaccount", true }, - { EOS_Transfer, "transfer", true }, - { 0xcdcd3c2d57000000, "transfer", true }, - { 0xd4d2a8a986ca8fc0, "undelegatebw", true }, - { 0xc2b263b800000000, "setabi", true }, - { 0xa726ab8000000000, "owner", true }, - { EOS_Owner, "owner", true }, - { 0x3232eda800000000, "active", true }, - { EOS_Active, "active", true }, - { 0x5530002eea526920, "eos..freedom", true }, - { 0x5530412eea526920, "eos42freedom", true }, - { 0x0, "", true }, - }; + struct { + uint64_t value; + const char *name; + bool ret; + } vec[] = { + {0x5530ea0000000000, "eosio", true}, + {0x0000000000ea3055, nullptr, true}, + {0x5530ea031ec65520, "eosio.system", true}, + {0xb68d3cbb3e000000, "quantity", true}, + {0x9ab864229a9e4000, "newaccount", true}, + {EOS_Transfer, "transfer", true}, + {0xcdcd3c2d57000000, "transfer", true}, + {0xd4d2a8a986ca8fc0, "undelegatebw", true}, + {0xc2b263b800000000, "setabi", true}, + {0xa726ab8000000000, "owner", true}, + {EOS_Owner, "owner", true}, + {0x3232eda800000000, "active", true}, + {EOS_Active, "active", true}, + {0x5530002eea526920, "eos..freedom", true}, + {0x5530412eea526920, "eos42freedom", true}, + {0x0, "", true}, + }; - for (const auto &v : vec) { - char str[EOS_NAME_STR_SIZE]; - ASSERT_EQ(v.ret, eos_formatName(v.value, str)); - if (v.name) - ASSERT_EQ(v.name, std::string(str)); - } + for (const auto &v : vec) { + char str[EOS_NAME_STR_SIZE]; + ASSERT_EQ(v.ret, eos_formatName(v.value, str)); + if (v.name) ASSERT_EQ(v.name, std::string(str)); + } } TEST(EOS, FormatAssetVec) { - struct { - int64_t amount; - uint64_t symbol; - std::string expected; - bool ret; - } vec[] = { - { 7654321L, 0x000000534f4504L, "765.4321 EOS", true }, - { 42L, 0x004e45584f4600L, "42 FOXEN", true }, - { 42L, 0x004e45584f4601L, "4.2 FOXEN", true }, - { 42L, 0x004e45584f4602L, "0.42 FOXEN", true }, - { 42L, 0x004e45584f4603L, "0.042 FOXEN", true }, - { 42L, 0x004e45584f4604L, "0.0042 FOXEN", true }, - { 42L, 0x004e45584f4605L, "0.00042 FOXEN", true }, - { 42L, 0x004e45584f4606L, "0.000042 FOXEN", true }, - { 42L, 0x004e45584f4607L, "0.0000042 FOXEN", true }, - { 42L, 0x004e45584f4608L, "0.00000042 FOXEN", true }, - { 42L, 0x004e45584f4609L, "0.000000042 FOXEN", true }, - { -10L, 0x00000053595305L, "-0.00010 SYS", true }, - { INT64_MIN, 0x00000053595303L, "-9223372036854775.808 SYS", true }, - { 20000L, 0x000000534f4504L, "2.0000 EOS", true }, - { 200000L, 0x000000534f4504L, "20.0000 EOS", true }, - { 2000000L, 0x000000534f4504L, "200.0000 EOS", true }, - { 20000000L, 0x000000534f4504L, "2000.0000 EOS", true }, - { 200000000L, 0x000000534f4504L, "20000.0000 EOS", true }, - { 2000000000L, 0x000000534f4504L, "200000.0000 EOS", true }, - { 20000000000L, 0x000000534f4504L, "2000000.0000 EOS", true }, - { 200000000000L, 0x000000534f4504L, "20000000.0000 EOS", true }, - { 2000000000000L, 0x000000534f4504L, "200000000.0000 EOS", true }, - { 20000000000000L, 0x000000534f4504L, "2000000000.0000 EOS", true }, - { 10000L, 0x000000534f4504L, "1.0000 EOS", true }, - { 100000L, 0x000000534f4504L, "10.0000 EOS", true }, - { 1000000L, 0x000000534f4504L, "100.0000 EOS", true }, - { 10000000L, 0x000000534f4504L, "1000.0000 EOS", true }, - { 100000000L, 0x000000534f4504L, "10000.0000 EOS", true }, - { 1000000000L, 0x000000534f4504L, "100000.0000 EOS", true }, - { 10000000000L, 0x000000534f4504L, "1000000.0000 EOS", true }, - { 100000000000L, 0x000000534f4504L, "10000000.0000 EOS", true }, - { 1000000000000L, 0x000000534f4504L, "100000000.0000 EOS", true }, - { 10000000000000L, 0x000000534f4504L, "1000000000.0000 EOS", true }, - }; + struct { + int64_t amount; + uint64_t symbol; + std::string expected; + bool ret; + } vec[] = { + {7654321L, 0x000000534f4504L, "765.4321 EOS", true}, + {42L, 0x004e45584f4600L, "42 FOXEN", true}, + {42L, 0x004e45584f4601L, "4.2 FOXEN", true}, + {42L, 0x004e45584f4602L, "0.42 FOXEN", true}, + {42L, 0x004e45584f4603L, "0.042 FOXEN", true}, + {42L, 0x004e45584f4604L, "0.0042 FOXEN", true}, + {42L, 0x004e45584f4605L, "0.00042 FOXEN", true}, + {42L, 0x004e45584f4606L, "0.000042 FOXEN", true}, + {42L, 0x004e45584f4607L, "0.0000042 FOXEN", true}, + {42L, 0x004e45584f4608L, "0.00000042 FOXEN", true}, + {42L, 0x004e45584f4609L, "0.000000042 FOXEN", true}, + {-10L, 0x00000053595305L, "-0.00010 SYS", true}, + {INT64_MIN, 0x00000053595303L, "-9223372036854775.808 SYS", true}, + {20000L, 0x000000534f4504L, "2.0000 EOS", true}, + {200000L, 0x000000534f4504L, "20.0000 EOS", true}, + {2000000L, 0x000000534f4504L, "200.0000 EOS", true}, + {20000000L, 0x000000534f4504L, "2000.0000 EOS", true}, + {200000000L, 0x000000534f4504L, "20000.0000 EOS", true}, + {2000000000L, 0x000000534f4504L, "200000.0000 EOS", true}, + {20000000000L, 0x000000534f4504L, "2000000.0000 EOS", true}, + {200000000000L, 0x000000534f4504L, "20000000.0000 EOS", true}, + {2000000000000L, 0x000000534f4504L, "200000000.0000 EOS", true}, + {20000000000000L, 0x000000534f4504L, "2000000000.0000 EOS", true}, + {10000L, 0x000000534f4504L, "1.0000 EOS", true}, + {100000L, 0x000000534f4504L, "10.0000 EOS", true}, + {1000000L, 0x000000534f4504L, "100.0000 EOS", true}, + {10000000L, 0x000000534f4504L, "1000.0000 EOS", true}, + {100000000L, 0x000000534f4504L, "10000.0000 EOS", true}, + {1000000000L, 0x000000534f4504L, "100000.0000 EOS", true}, + {10000000000L, 0x000000534f4504L, "1000000.0000 EOS", true}, + {100000000000L, 0x000000534f4504L, "10000000.0000 EOS", true}, + {1000000000000L, 0x000000534f4504L, "100000000.0000 EOS", true}, + {10000000000000L, 0x000000534f4504L, "1000000000.0000 EOS", true}, + }; - for (const auto &v : vec) { - char str[EOS_ASSET_STR_SIZE]; - EosAsset asset; - asset.has_amount = true; - asset.amount = v.amount; - asset.has_symbol = true; - asset.symbol = v.symbol; - EXPECT_EQ(v.ret, eos_formatAsset(&asset, str)); - EXPECT_EQ(v.expected, str); - } + for (const auto &v : vec) { + char str[EOS_ASSET_STR_SIZE]; + EosAsset asset; + asset.has_amount = true; + asset.amount = v.amount; + asset.has_symbol = true; + asset.symbol = v.symbol; + EXPECT_EQ(v.ret, eos_formatAsset(&asset, str)); + EXPECT_EQ(v.expected, str); + } } TEST(EOS, PublicKeyToWIF) { - uint8_t public_key[33]; - memset(public_key, 0, sizeof(public_key)); - char pubkey[64]; - memset(pubkey, 0, sizeof(pubkey)); - ASSERT_FALSE(eos_publicKeyToWif(public_key, (EosPublicKeyKind)42, pubkey, sizeof(pubkey))); + uint8_t public_key[33]; + memset(public_key, 0, sizeof(public_key)); + char pubkey[64]; + memset(pubkey, 0, sizeof(pubkey)); + ASSERT_FALSE(eos_publicKeyToWif(public_key, (EosPublicKeyKind)42, pubkey, + sizeof(pubkey))); - ASSERT_TRUE(eos_publicKeyToWif(public_key, EosPublicKeyKind_EOS_K1, pubkey, sizeof(pubkey))); - ASSERT_EQ(pubkey, std::string("EOS_K1_1111111111111111111111111111111114T1Anm")); + ASSERT_TRUE(eos_publicKeyToWif(public_key, EosPublicKeyKind_EOS_K1, pubkey, + sizeof(pubkey))); + ASSERT_EQ(pubkey, + std::string("EOS_K1_1111111111111111111111111111111114T1Anm")); } diff --git a/unittests/firmware/ethereum.cpp b/unittests/firmware/ethereum.cpp index ec6e68f1c..f8329a416 100644 --- a/unittests/firmware/ethereum.cpp +++ b/unittests/firmware/ethereum.cpp @@ -7,39 +7,34 @@ extern "C" { #include static uint8_t bin_from_ascii(char c) { - if ('a' <= c && c <= 'f') - return c - 'a' + 0xa; + if ('a' <= c && c <= 'f') return c - 'a' + 0xa; - if ('A' <= c && c <= 'F') - return c - 'A' + 0xA; + if ('A' <= c && c <= 'F') return c - 'A' + 0xA; - if ('0' <= c && c <= '9') - return c - '0' + 0x0; + if ('0' <= c && c <= '9') return c - '0' + 0x0; - __builtin_unreachable(); + __builtin_unreachable(); } static void test_checksum(const std::string &addr) { uint8_t addr_bin[20]; - for (size_t i = 0; i < addr.size(); i+=2) { - addr_bin[i/2] = bin_from_ascii(addr[i+1]) | - bin_from_ascii(addr[i ]) << 4; + for (size_t i = 0; i < addr.size(); i += 2) { + addr_bin[i / 2] = bin_from_ascii(addr[i + 1]) | bin_from_ascii(addr[i]) + << 4; } char formatted[41]; ethereum_address_checksum(addr_bin, formatted, false, 0); - ASSERT_EQ(formatted[40], '\0') - << "Must be null terminated"; + ASSERT_EQ(formatted[40], '\0') << "Must be null terminated"; - ASSERT_EQ(addr, std::string(formatted)) - << "Checksum mismatch"; + ASSERT_EQ(addr, std::string(formatted)) << "Checksum mismatch"; } TEST(Ethereum, AddressChecksum) { - // Testcases from: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - test_checksum("5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"); - test_checksum("fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"); - test_checksum("dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"); - test_checksum("D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"); + // Testcases from: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md + test_checksum("5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"); + test_checksum("fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"); + test_checksum("dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"); + test_checksum("D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"); } diff --git a/unittests/firmware/nano.cpp b/unittests/firmware/nano.cpp index 44638eaed..37e0c9482 100644 --- a/unittests/firmware/nano.cpp +++ b/unittests/firmware/nano.cpp @@ -6,14 +6,11 @@ extern "C" { #include "gtest/gtest.h" #include -static void test_truncateAddress( - const CoinType *coin, - const std::string &addr, - const std::string &expected) -{ +static void test_truncateAddress(const CoinType *coin, const std::string &addr, + const std::string &expected) { char value[100]; strncpy(value, addr.c_str(), sizeof(value)); - value[sizeof(value)-1] = '\0'; + value[sizeof(value) - 1] = '\0'; nano_truncateAddress(coin, value); @@ -21,8 +18,11 @@ static void test_truncateAddress( } TEST(Nano, GetKnownRepName) { - EXPECT_EQ(std::string("Official Rep 1 "), nano_getKnownRepName("xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4")); - EXPECT_EQ(nullptr, nano_getKnownRepName("xrb_notarealrepresentative")); + EXPECT_EQ( + std::string("Official Rep 1 "), + nano_getKnownRepName( + "xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4")); + EXPECT_EQ(nullptr, nano_getKnownRepName("xrb_notarealrepresentative")); } TEST(Nano, TruncateAddress) { @@ -31,30 +31,28 @@ TEST(Nano, TruncateAddress) { strcpy(coin.nanoaddr_prefix, "xrb_"); test_truncateAddress( - &coin, - "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3", - "xrb_3t6k3..uohr3"); + &coin, "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3", + "xrb_3t6k3..uohr3"); test_truncateAddress(&coin, "xrb_3t6k35gi95", "xrb_3t6k35gi95"); test_truncateAddress(&coin, "", ""); strcpy(coin.nanoaddr_prefix, "nano_"); test_truncateAddress( - &coin, - "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", - "nano_1nano..zffeg"); + &coin, + "nano_1nanode8ngaakzbck8smq6ru9bethqwyehomf79sae1k7xd47dkidjqzffeg", + "nano_1nano..zffeg"); } -static std::string bytes_to_hex(const uint8_t *buf, const size_t size) -{ - static const char *ALPHABET = "0123456789ABCDEF"; - std::string hex; - hex.reserve(2 * size); - for (size_t i = 0; i < size; i++) { - const uint8_t b = buf[i]; - hex.push_back(ALPHABET[b >> 4]); - hex.push_back(ALPHABET[b & 15]); - } - return hex; +static std::string bytes_to_hex(const uint8_t *buf, const size_t size) { + static const char *ALPHABET = "0123456789ABCDEF"; + std::string hex; + hex.reserve(2 * size); + for (size_t i = 0; i < size; i++) { + const uint8_t b = buf[i]; + hex.push_back(ALPHABET[b >> 4]); + hex.push_back(ALPHABET[b & 15]); + } + return hex; } static uint8_t byte_from_hex_char(const unsigned char c) { @@ -69,12 +67,12 @@ static uint8_t byte_from_hex_char(const unsigned char c) { } } -static void bytes_from_hex(uint8_t *buf, const std::string &hex, const size_t buf_size) -{ +static void bytes_from_hex(uint8_t *buf, const std::string &hex, + const size_t buf_size) { for (size_t i = 0; i < buf_size; i++) { - if (2*i + 1 < hex.size()) { - buf[i] = (byte_from_hex_char(hex[2*i]) << 4); - buf[i] |= byte_from_hex_char(hex[2*i + 1]); + if (2 * i + 1 < hex.size()) { + buf[i] = (byte_from_hex_char(hex[2 * i]) << 4); + buf[i] |= byte_from_hex_char(hex[2 * i + 1]); } else { buf[i] = 0; } @@ -82,67 +80,67 @@ static void bytes_from_hex(uint8_t *buf, const std::string &hex, const size_t bu } #define BYTES_FROM_HEX(buf_name, buf_size) \ - uint8_t buf_name[buf_size]; \ + uint8_t buf_name[buf_size]; \ bytes_from_hex(buf_name, buf_name##_hex, buf_size); -static void test_block_hashing( - const std::string &account_pk_hex, - const std::string &parent_hash_hex, - const std::string &link_hex, - const std::string &representative_pk_hex, - const std::string &balance_hex, - const std::string &expected_hash_hex) -{ - BYTES_FROM_HEX(account_pk, 32); - BYTES_FROM_HEX(parent_hash, 32); - BYTES_FROM_HEX(link, 32); +static void test_block_hashing(const std::string &account_pk_hex, + const std::string &parent_hash_hex, + const std::string &link_hex, + const std::string &representative_pk_hex, + const std::string &balance_hex, + const std::string &expected_hash_hex) { + BYTES_FROM_HEX(account_pk, 32); + BYTES_FROM_HEX(parent_hash, 32); + BYTES_FROM_HEX(link, 32); BYTES_FROM_HEX(representative_pk, 32); - BYTES_FROM_HEX(balance, 16); + BYTES_FROM_HEX(balance, 16); uint8_t hash[32]; - nano_hash_block_data(account_pk, parent_hash, link, - representative_pk, balance, - hash); + nano_hash_block_data(account_pk, parent_hash, link, representative_pk, + balance, hash); ASSERT_EQ(expected_hash_hex, bytes_to_hex(hash, sizeof(hash))); } TEST(Nano, BlockHashing) { test_block_hashing( - "C798CFF4F1131204F65C4D22C3E6316F26F380EE0616AADBABEA1268FD75FB05", - "50DE35601F5BD5B0AAEAD0BCCFE028A98BD1DA4B2022ABD77DD7889DBFFCCEC1", - "7DD26DF85B130A7B55B1130F4DF04366542CE588D98524D4519713E0A0FCBED4", - "C798CFF4F1131204F65C4D22C3E6316F26F380EE0616AADBABEA1268FD75FB05", - "03572D26B79A28EBB63E62EBB6B011D6", - "F8FBAD162C5911405364035D620B0AEDB4F7D882513F8DD4BC47637C594F7CD0"); + "C798CFF4F1131204F65C4D22C3E6316F26F380EE0616AADBABEA1268FD75FB05", + "50DE35601F5BD5B0AAEAD0BCCFE028A98BD1DA4B2022ABD77DD7889DBFFCCEC1", + "7DD26DF85B130A7B55B1130F4DF04366542CE588D98524D4519713E0A0FCBED4", + "C798CFF4F1131204F65C4D22C3E6316F26F380EE0616AADBABEA1268FD75FB05", + "03572D26B79A28EBB63E62EBB6B011D6", + "F8FBAD162C5911405364035D620B0AEDB4F7D882513F8DD4BC47637C594F7CD0"); } TEST(Nano, Bip32ToString) { const CoinType *coin = coinByName("Nano"); struct { - uint32_t address_n[5]; - uint32_t address_n_count; - bool expected_ok; - const char *expected_string; + uint32_t address_n[5]; + uint32_t address_n_count; + bool expected_ok; + const char *expected_string; } vec[] = { - { { 0x80000000 | 44, 0x80000000 | 165, 0x80000000 | 12 }, 3, true, "Nano Account #12" }, - { { 0x80000000 | 44, 0x80000000 | 100, 0x80000000 | 12 }, 3, false, "" }, - { { 0x80000000 | 44, 0x80000000 | 165, 0x80000000 | 0, 0x80000000 | 12 }, 4, false, "" }, + {{0x80000000 | 44, 0x80000000 | 165, 0x80000000 | 12}, + 3, + true, + "Nano Account #12"}, + {{0x80000000 | 44, 0x80000000 | 100, 0x80000000 | 12}, 3, false, ""}, + {{0x80000000 | 44, 0x80000000 | 165, 0x80000000 | 0, 0x80000000 | 12}, + 4, + false, + ""}, }; for (const auto &v : vec) { - char out_string[200]; memset(out_string, 0, sizeof(out_string)); - bool ok = nano_bip32_to_string( - out_string, sizeof(out_string), - coin, v.address_n, v.address_n_count); + bool ok = nano_bip32_to_string(out_string, sizeof(out_string), coin, + v.address_n, v.address_n_count); - ASSERT_EQ(v.expected_ok, ok) - << "Unexpected success value"; + ASSERT_EQ(v.expected_ok, ok) << "Unexpected success value"; ASSERT_EQ(v.expected_string, std::string(out_string)) - << "Unexpected string result"; + << "Unexpected string result"; } } diff --git a/unittests/firmware/recovery.cpp b/unittests/firmware/recovery.cpp index 94d4e8990..654891c28 100644 --- a/unittests/firmware/recovery.cpp +++ b/unittests/firmware/recovery.cpp @@ -8,38 +8,37 @@ extern "C" { #include TEST(Recovery, ExactStrMatch) { - char LHS[] = "allow\0"; - char RHS[] = "all\0"; + char LHS[] = "allow\0"; + char RHS[] = "all\0"; - ASSERT_TRUE(exact_str_match(LHS, RHS, 1)); - ASSERT_TRUE(exact_str_match(LHS, RHS, 2)); - ASSERT_TRUE(exact_str_match(LHS, RHS, 3)); - ASSERT_FALSE(exact_str_match(LHS, RHS, 4)); + ASSERT_TRUE(exact_str_match(LHS, RHS, 1)); + ASSERT_TRUE(exact_str_match(LHS, RHS, 2)); + ASSERT_TRUE(exact_str_match(LHS, RHS, 3)); + ASSERT_FALSE(exact_str_match(LHS, RHS, 4)); } bool attempt_auto_complete(char *partial_word); TEST(Recovery, AutoComplete) { - char partial_word[] = "all\0\0\0\0\0"; - ASSERT_TRUE(attempt_auto_complete(partial_word)); - ASSERT_TRUE(memcmp(partial_word, "all\0\0\0\0\0", sizeof(partial_word)) == 0); + char partial_word[] = "all\0\0\0\0\0"; + ASSERT_TRUE(attempt_auto_complete(partial_word)); + ASSERT_TRUE(memcmp(partial_word, "all\0\0\0\0\0", sizeof(partial_word)) == 0); - memcpy(partial_word, "allo\0\0\0\0", sizeof(partial_word)); - ASSERT_TRUE(attempt_auto_complete(partial_word)); - ASSERT_TRUE(memcmp(partial_word, "allow\0\0\0", sizeof(partial_word)) == 0); + memcpy(partial_word, "allo\0\0\0\0", sizeof(partial_word)); + ASSERT_TRUE(attempt_auto_complete(partial_word)); + ASSERT_TRUE(memcmp(partial_word, "allow\0\0\0", sizeof(partial_word)) == 0); - memcpy(partial_word, "allways\0", sizeof(partial_word)); - ASSERT_FALSE(attempt_auto_complete(partial_word)); - ASSERT_TRUE(memcmp(partial_word, "allways\0", sizeof(partial_word)) == 0); + memcpy(partial_word, "allways\0", sizeof(partial_word)); + ASSERT_FALSE(attempt_auto_complete(partial_word)); + ASSERT_TRUE(memcmp(partial_word, "allways\0", sizeof(partial_word)) == 0); } TEST(Recovery, WordlistLengths) { - for (int i = 0; wordlist[i]; i++) { - const char *word = wordlist[i]; - size_t len = strlen(word); - for (int c = len; c <= BIP39_MAX_WORD_LEN; c++) { - ASSERT_EQ(word[c], '\0') - << "bip39 word list must be padded"; - } + for (int i = 0; wordlist[i]; i++) { + const char *word = wordlist[i]; + size_t len = strlen(word); + for (int c = len; c <= BIP39_MAX_WORD_LEN; c++) { + ASSERT_EQ(word[c], '\0') << "bip39 word list must be padded"; } + } } diff --git a/unittests/firmware/ripple.cpp b/unittests/firmware/ripple.cpp index c6d8abae9..155d057aa 100644 --- a/unittests/firmware/ripple.cpp +++ b/unittests/firmware/ripple.cpp @@ -10,87 +10,93 @@ extern "C" { #include TEST(Ripple, AddressEncodeDecode) { - // https://xrpl.org/accounts.html#address-encoding - uint8_t public_key[33 + 1] = - "\xED\x94\x34\x79\x92\x26\x37\x49\x26\xED" - "\xA3\xB5\x4B\x1B\x46\x1B\x4A\xBF\x72\x37" - "\x96\x2E\xAE\x18\x52\x8F\xEA\x67\x59\x53" - "\x97\xFA\x32"; - - uint8_t buff[64]; - memset(buff, 0, sizeof(buff)); - - Hasher hasher; - hasher_Init(&hasher, HASHER_SHA2_RIPEMD); - hasher_Update(&hasher, public_key, 33); - hasher_Final(&hasher, buff + 1); - - EXPECT_TRUE(memcmp(buff, "\x00\x88\xa5\xa5\x7c\x82\x9f\x40\xf2\x5e" - "\xa8\x33\x85\xbb\xde\x6c\x3d\x8b\x4c\xa0\x82", 21) == 0); - - char address[56]; - ASSERT_TRUE(ripple_encode_check(buff, 21, HASHER_SHA2D, - address, MAX_ADDR_SIZE)); - - EXPECT_EQ(std::string(address), "rDTXLQ7ZKZVKz33zJbHjgVShjsBnqMBhmN"); - - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - memset(addr_raw, 0, sizeof(addr_raw)); - uint32_t addr_raw_len = ripple_decode_check(address, HASHER_SHA2D, - addr_raw, MAX_ADDR_RAW_SIZE); - EXPECT_EQ(addr_raw_len, 21); - - EXPECT_TRUE(memcmp(buff, addr_raw, 21) == 0); - - EXPECT_TRUE(memcmp(addr_raw, "\x00\x88\xa5\xa5\x7c\x82\x9f\x40\xf2\x5e" - "\xa8\x33\x85\xbb\xde\x6c\x3d\x8b\x4c\xa0\x82", 21) == 0); + // https://xrpl.org/accounts.html#address-encoding + uint8_t public_key[33 + 1] = + "\xED\x94\x34\x79\x92\x26\x37\x49\x26\xED" + "\xA3\xB5\x4B\x1B\x46\x1B\x4A\xBF\x72\x37" + "\x96\x2E\xAE\x18\x52\x8F\xEA\x67\x59\x53" + "\x97\xFA\x32"; + + uint8_t buff[64]; + memset(buff, 0, sizeof(buff)); + + Hasher hasher; + hasher_Init(&hasher, HASHER_SHA2_RIPEMD); + hasher_Update(&hasher, public_key, 33); + hasher_Final(&hasher, buff + 1); + + EXPECT_TRUE(memcmp(buff, + "\x00\x88\xa5\xa5\x7c\x82\x9f\x40\xf2\x5e" + "\xa8\x33\x85\xbb\xde\x6c\x3d\x8b\x4c\xa0\x82", + 21) == 0); + + char address[56]; + ASSERT_TRUE( + ripple_encode_check(buff, 21, HASHER_SHA2D, address, MAX_ADDR_SIZE)); + + EXPECT_EQ(std::string(address), "rDTXLQ7ZKZVKz33zJbHjgVShjsBnqMBhmN"); + + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + memset(addr_raw, 0, sizeof(addr_raw)); + uint32_t addr_raw_len = + ripple_decode_check(address, HASHER_SHA2D, addr_raw, MAX_ADDR_RAW_SIZE); + EXPECT_EQ(addr_raw_len, 21); + + EXPECT_TRUE(memcmp(buff, addr_raw, 21) == 0); + + EXPECT_TRUE(memcmp(addr_raw, + "\x00\x88\xa5\xa5\x7c\x82\x9f\x40\xf2\x5e" + "\xa8\x33\x85\xbb\xde\x6c\x3d\x8b\x4c\xa0\x82", + 21) == 0); } TEST(Ripple, SerializeAddress) { - uint8_t buffer[22]; - memset(buffer, 0, sizeof(buffer)); + uint8_t buffer[22]; + memset(buffer, 0, sizeof(buffer)); - uint8_t *buf = buffer; - bool ok = true; - ripple_serializeAddress(&ok, &buf, buf + sizeof(buffer), &RFM_account, - "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H"); + uint8_t *buf = buffer; + bool ok = true; + ripple_serializeAddress(&ok, &buf, buf + sizeof(buffer), &RFM_account, + "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H"); - ASSERT_TRUE(ok); + ASSERT_TRUE(ok); - EXPECT_TRUE(memcmp(buffer, "\x81\x14\x8f\xb4\x0e\x1f\xfa\x5d\x55\x7c\xe9" - "\x85\x1a\x53\x5a\xf9\x49\x65\xe0\xdd\x09\x88", 22) == 0); + EXPECT_TRUE(memcmp(buffer, + "\x81\x14\x8f\xb4\x0e\x1f\xfa\x5d\x55\x7c\xe9" + "\x85\x1a\x53\x5a\xf9\x49\x65\xe0\xdd\x09\x88", + 22) == 0); } TEST(Ripple, Serialize) { - RippleSignTx tx; - memset(&tx, 0, sizeof(tx)); + RippleSignTx tx; + memset(&tx, 0, sizeof(tx)); - tx.address_n_count = 0; + tx.address_n_count = 0; - tx.has_fee = true; - tx.fee = 100000; + tx.has_fee = true; + tx.fee = 100000; - tx.has_flags = true; - tx.flags = 0x80000000; + tx.has_flags = true; + tx.flags = 0x80000000; - tx.has_sequence = true; - tx.sequence = 25; + tx.has_sequence = true; + tx.sequence = 25; - tx.has_payment = true; - tx.payment.has_amount = true; - tx.payment.amount = 100000000ULL; - tx.payment.has_destination = true; - strcpy(tx.payment.destination, "rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws"); + tx.has_payment = true; + tx.payment.has_amount = true; + tx.payment.amount = 100000000ULL; + tx.payment.has_destination = true; + strcpy(tx.payment.destination, "rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws"); - uint8_t serialized[183]; - memset(serialized, 0, sizeof(serialized)); + uint8_t serialized[183]; + memset(serialized, 0, sizeof(serialized)); - const uint8_t *public_key = (const uint8_t*) + const uint8_t *public_key = (const uint8_t*) "\x02\x13\x1f\xac\xd1\xea\xb7\x48\xd6\xcd\xdc\x49\x2f\x54\xb0\x4e" "\x8c\x35\x65\x88\x94\xf4\xad\xd2\x23\x2e\xbc\x5a\xfe\x75\x21\xdb\xe4"; - const size_t sig_len = 71; - const uint8_t *sig = (const uint8_t*) + const size_t sig_len = 71; + const uint8_t *sig = (const uint8_t*) "\x30" // DER Type "\x45" // Length of rest of payload "\x02" // r value Marker @@ -103,12 +109,12 @@ TEST(Ripple, Serialize) { "\x6c\xa8\xaa\x5e\xaa\xb8\x39\x63\x97\xae\xf6\xd3\x8d\x25\x71\x04" // s value "\x41\xfa\xf7\xc7\x9d\x29\x2e\xe1\xd6\x27\xdf\x15\xad\x93\x46\xc0"; - uint8_t *buf = serialized; - EXPECT_TRUE(ripple_serialize(&buf, buf + sizeof(serialized), &tx, - "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H", - public_key, sig, sig_len)); + uint8_t *buf = serialized; + EXPECT_TRUE(ripple_serialize(&buf, buf + sizeof(serialized), &tx, + "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H", public_key, + sig, sig_len)); - const uint8_t *expected = (const uint8_t*) + const uint8_t *expected = (const uint8_t*) "\x12\x00\x00\x22\x80\x00\x00\x00\x24\x00\x00\x00\x19\x61\x40\x00\x00\x00\x05\xf5" "\xe1\x00\x68\x40\x00\x00\x00\x00\x01\x86\xa0\x73\x21\x02\x13\x1f\xac\xd1\xea\xb7" "\x48\xd6\xcd\xdc\x49\x2f\x54\xb0\x4e\x8c\x35\x65\x88\x94\xf4\xad\xd2\x23\x2e\xbc" @@ -120,5 +126,5 @@ TEST(Ripple, Serialize) { "\x88\x83\x14\x71\x48\xeb\xeb\xf7\x30\x4c\xcd\xf1\x67\x6f\xef\xcf\x97\x34\xcf\x1e" "\x78\x08\x26"; - ASSERT_TRUE(memcmp(serialized, expected, sizeof(serialized)) == 0); + ASSERT_TRUE(memcmp(serialized, expected, sizeof(serialized)) == 0); } diff --git a/unittests/firmware/storage.cpp b/unittests/firmware/storage.cpp index bbf7b27cf..f4c48bbf6 100644 --- a/unittests/firmware/storage.cpp +++ b/unittests/firmware/storage.cpp @@ -17,456 +17,527 @@ extern "C" { using ::testing::ElementsAreArray; TEST(Storage, ReadMeta) { - Metadata dst; - const char src[] = "M1M2u1u2u3u4u5u6S1S2S3S4S5S6S7S8S9SASBSC"; + Metadata dst; + const char src[] = "M1M2u1u2u3u4u5u6S1S2S3S4S5S6S7S8S9SASBSC"; - storage_readMeta(&dst, src, sizeof(src)); + storage_readMeta(&dst, src, sizeof(src)); - ASSERT_TRUE(memcmp(dst.magic, "M1M2", 4) == 0); - ASSERT_TRUE(memcmp(dst.uuid, "u1u2u3u4u5u6", 12) == 0); - ASSERT_TRUE(memcmp(dst.uuid_str, "S1S2S3S4S5S6S7S8S9SASBSC", 24) == 0); + ASSERT_TRUE(memcmp(dst.magic, "M1M2", 4) == 0); + ASSERT_TRUE(memcmp(dst.uuid, "u1u2u3u4u5u6", 12) == 0); + ASSERT_TRUE(memcmp(dst.uuid_str, "S1S2S3S4S5S6S7S8S9SASBSC", 24) == 0); - for (size_t i = 0; i < sizeof(src); i++) { - ASSERT_EQ(src[i], ((char *)&dst)[i]) << "i: " << i; - } + for (size_t i = 0; i < sizeof(src); i++) { + ASSERT_EQ(src[i], ((char *)&dst)[i]) << "i: " << i; + } } TEST(Storage, WriteMeta) { - Metadata src; - memcpy(&src.magic[0], "M1M", sizeof(src.magic)); - memcpy(&src.uuid[0], "u1u2u3u4u5u", sizeof(src.uuid)); - memcpy(&src.uuid_str[0], "S1S2S3S4S5S6S7S8S9SASBS\0", sizeof(src.uuid_str)); + Metadata src; + memcpy(&src.magic[0], "M1M", sizeof(src.magic)); + memcpy(&src.uuid[0], "u1u2u3u4u5u", sizeof(src.uuid)); + memcpy(&src.uuid_str[0], "S1S2S3S4S5S6S7S8S9SASBS\0", sizeof(src.uuid_str)); - char dst[41]; - memset(dst, 0, sizeof(dst)); + char dst[41]; + memset(dst, 0, sizeof(dst)); - storage_writeMeta(&dst[0], sizeof(dst), &src); + storage_writeMeta(&dst[0], sizeof(dst), &src); - ASSERT_TRUE(memcmp(dst, "M1M\0u1u2u3u4u5u\0S1S2S3S4S5S6S7S8S9SASBS\0", sizeof(dst)) == 0); + ASSERT_TRUE(memcmp(dst, "M1M\0u1u2u3u4u5u\0S1S2S3S4S5S6S7S8S9SASBS\0", + sizeof(dst)) == 0); } TEST(Storage, ReadPolicyV1) { - PolicyType dst; - const char src[] = "\x01N1N2N3N4N5N6N7N\x01\x01"; + PolicyType dst; + const char src[] = "\x01N1N2N3N4N5N6N7N\x01\x01"; - storage_readPolicyV1(&dst, src, sizeof(src)); + storage_readPolicyV1(&dst, src, sizeof(src)); - ASSERT_EQ(dst.has_policy_name, true); - ASSERT_TRUE(memcmp(dst.policy_name, "N1N2N3N4N5N6N7N8N", 15) == 0); - ASSERT_EQ(dst.has_enabled, true); - ASSERT_EQ(dst.enabled, true); + ASSERT_EQ(dst.has_policy_name, true); + ASSERT_TRUE(memcmp(dst.policy_name, "N1N2N3N4N5N6N7N8N", 15) == 0); + ASSERT_EQ(dst.has_enabled, true); + ASSERT_EQ(dst.enabled, true); } TEST(Storage, WritePolicyV1) { - PolicyType src; - src.has_policy_name = true; - memcpy(&src.policy_name[0], "0123456789ABCD", 15); - src.has_enabled = true; - src.enabled = true; + PolicyType src; + src.has_policy_name = true; + memcpy(&src.policy_name[0], "0123456789ABCD", 15); + src.has_enabled = true; + src.enabled = true; - char dst[18]; - memset(dst, 0, sizeof(dst)); + char dst[18]; + memset(dst, 0, sizeof(dst)); - storage_writePolicyV1(&dst[0], sizeof(dst), &src); + storage_writePolicyV1(&dst[0], sizeof(dst), &src); - ASSERT_TRUE(memcmp(dst, "\x01""0123456789ABCD\0\x01\x01", sizeof(dst)) == 0); + ASSERT_TRUE(memcmp(dst, + "\x01" + "0123456789ABCD\0\x01\x01", + sizeof(dst)) == 0); } TEST(Storage, ReadStorageV1) { - const char src[559] = - /* 0 */ "\x0a\x00\x00\x00" // version - /* 4 */ "\x01" // has_node - "\x00\x00\x00" // reserved - /* 8 */ "\x03\x00\x00\x00" // depth - /* 12 */ "\x2a\x00\x00\x00" // fingerprint - /* 16 */ "\x11\x00\x00\x00" // child_num - /* 20 */ "\x20\x00\x00\x00" // chain_code.size - /* 24 */ "\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58" // chain_code.bytes - "\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x00" // chain_code.bytes - /* 56 */ "\x01" // has_private_key - "\x00\x00\x00" // reserved - /* 60 */ "\x20\x00\x00\x00" // private_key.size - /* 64 */ "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x59" // private_key.bytes - "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x00" // private_key.bytes - /* 96 */ "\x01" // has_public_key - "\x00\x00\x00" // reserved - /* 100 */ "\x21\x00\x00\x00" // public_key.size - /* 104 */ "\x57\x68\x6f\x20\x69\x73\x20\x53\x61\x74\x6f\x73\x68\x69\x20\x4e" // public_key.bytes - "\x61\x6b\x6f\x6d\x6f\x74\x6f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f" // public_key.bytes - /* 136 */ "\x00" // public_key.bytes - /* 137 */ "\x00\x00\x00" // reserved - /* 140 */ "\x01" // has_mnemonic - /* 141 */ "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic - "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic - "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x77\x72\x6f\x6e" // menmonic - "\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00" // mnemonic - /* 382 */ "\x00" // reserved - /* 383 */ "\x00" // passphrase_protection - /* 384 */ "\x01" // has_pin_failed_attempts - "\x00\x00\x00" // reserved - /* 388 */ "\x2a\x00\x00\x00" // pin_failed_attempts - /* 392 */ "\x01" // has_pin - /* 393 */ "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x00" // pin - /* 403 */ "\x01" // has_language - /* 404 */ "\x65\x73\x70\x65\x72\x61\x6e\x74\x6f\x00\x00\x00\x00\x00\x00\x00" // language - "\x00" // language - /* 421 */ "\x01" // has_label - /* 422 */ "\x4d\x65\x6e\x6f\x73\x4d\x61\x72\x78\x4d\x61\x69\x73\x4d\x69\x73" // label - "\x65\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // label - "\x00" // label - /* 455 */ "\x01" // reserved - /* 456 */ "\x00" // imported - /* 457 */ "\x00\x00\x00" // reserved - /* 460 */ "\x01\x00\x00\x00" // policies_count - /* 464 */ "\x01" // policies[0].has_policy_name - /* 465 */ "\x53\x68\x61\x70\x65\x53\x68\x69\x66\x74\x00\x00\x00\x00\x00" // policies[0].policy_name - /* 481 */ "\x01" // policies[0].has_enabled - /* 482 */ "\x01" // policies[0].enabled - /* 483 */ "\x00" // reserved - /* 484 */ "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" // cache - "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30" // cache - "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" // cache - "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" // cache - "\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31\x00"; // cache - - Storage dst; - memset(&dst, 0xCC, sizeof(dst)); - - SessionState session; - memset(&session, 0, sizeof(session)); - - storage_readStorageV1(&session, &dst, &src[0], sizeof(src)); - - // Check that the secret area of storage remains cleared. - EXPECT_EQ(dst.sec.node.depth, 0); - - // Decrypt upgraded storage. - uint8_t wrapping_key[64]; - storage_deriveWrappingKey("123456789", wrapping_key, dst.pub.sca_hardened, dst.pub.random_salt, ""); // strongest pin evar - storage_unwrapStorageKey(wrapping_key, dst.pub.wrapped_storage_key, session.storageKey); - storage_secMigrate(&session, &dst, /*encrypt=*/false); - - // Check that the secret area was correctly unencrypted. - EXPECT_EQ(dst.version, 10); - EXPECT_TRUE(dst.pub.has_node); - EXPECT_EQ(dst.sec.node.depth, 3); - EXPECT_EQ(dst.sec.node.fingerprint, 42); - EXPECT_EQ(dst.sec.node.child_num, 17); - EXPECT_EQ(dst.sec.node.chain_code.size, 32); - EXPECT_TRUE(memcmp(dst.sec.node.chain_code.bytes, "XMRXMRXMRXMRXMRXMRXMRXMRXMRXMRX\0", 32) == 0); - EXPECT_EQ(dst.sec.node.has_private_key, true); - EXPECT_EQ(dst.sec.node.public_key.size, 33); - EXPECT_TRUE(memcmp(dst.sec.node.public_key.bytes, "Who is Satoshi Nakomoto?????????\0", 32) == 0); - EXPECT_EQ(dst.pub.has_mnemonic, true); - - // Check the load path on storage_secMigrate() - char encrypted_sec[sizeof(dst.encrypted_sec)]; - memcpy(encrypted_sec, dst.encrypted_sec, sizeof(encrypted_sec)); - memzero(dst.encrypted_sec, sizeof(encrypted_sec)); - storage_secMigrate(&session, &dst, /*encrypt=*/true); - EXPECT_THAT(dst.encrypted_sec, ElementsAreArray(encrypted_sec)); + const char src[559] = + /* 0 */ + "\x0a\x00\x00\x00" // version + /* 4 */ + "\x01" // has_node + "\x00\x00\x00" // reserved + /* 8 */ + "\x03\x00\x00\x00" // depth + /* 12 */ + "\x2a\x00\x00\x00" // fingerprint + /* 16 */ + "\x11\x00\x00\x00" // child_num + /* 20 */ + "\x20\x00\x00\x00" // chain_code.size + /* 24 */ + "\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58" // chain_code.bytes + "\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x00" // chain_code.bytes + /* 56 */ + "\x01" // has_private_key + "\x00\x00\x00" // reserved + /* 60 */ + "\x20\x00\x00\x00" // private_key.size + /* 64 */ + "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x59" // private_key.bytes + "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x00" // private_key.bytes + /* 96 */ + "\x01" // has_public_key + "\x00\x00\x00" // reserved + /* 100 */ + "\x21\x00\x00\x00" // public_key.size + /* 104 */ + "\x57\x68\x6f\x20\x69\x73\x20\x53\x61\x74\x6f\x73\x68\x69\x20\x4e" // public_key.bytes + "\x61\x6b\x6f\x6d\x6f\x74\x6f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f" // public_key.bytes + /* 136 */ + "\x00" // public_key.bytes + /* 137 */ + "\x00\x00\x00" // reserved + /* 140 */ + "\x01" // has_mnemonic + /* 141 */ + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x77\x72\x6f\x6e" // menmonic + "\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00" // mnemonic + /* 382 */ + "\x00" // reserved + /* 383 */ + "\x00" // passphrase_protection + /* 384 */ + "\x01" // has_pin_failed_attempts + "\x00\x00\x00" // reserved + /* 388 */ + "\x2a\x00\x00\x00" // pin_failed_attempts + /* 392 */ + "\x01" // has_pin + /* 393 */ + "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x00" // pin + /* 403 */ + "\x01" // has_language + /* 404 */ + "\x65\x73\x70\x65\x72\x61\x6e\x74\x6f\x00\x00\x00\x00\x00\x00\x00" // language + "\x00" // language + /* 421 */ + "\x01" // has_label + /* 422 */ + "\x4d\x65\x6e\x6f\x73\x4d\x61\x72\x78\x4d\x61\x69\x73\x4d\x69\x73" // label + "\x65\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // label + "\x00" // label + /* 455 */ + "\x01" // reserved + /* 456 */ + "\x00" // imported + /* 457 */ + "\x00\x00\x00" // reserved + /* 460 */ + "\x01\x00\x00\x00" // policies_count + /* 464 */ + "\x01" // policies[0].has_policy_name + /* 465 */ + "\x53\x68\x61\x70\x65\x53\x68\x69\x66\x74\x00\x00\x00\x00\x00" // policies[0].policy_name + /* 481 */ + "\x01" // policies[0].has_enabled + /* 482 */ + "\x01" // policies[0].enabled + /* 483 */ + "\x00" // reserved + /* 484 */ + "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" // cache + "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30" // cache + "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" // cache + "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" // cache + "\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31\x00"; // cache + + Storage dst; + memset(&dst, 0xCC, sizeof(dst)); + + SessionState session; + memset(&session, 0, sizeof(session)); + + storage_readStorageV1(&session, &dst, &src[0], sizeof(src)); + + // Check that the secret area of storage remains cleared. + EXPECT_EQ(dst.sec.node.depth, 0); + + // Decrypt upgraded storage. + uint8_t wrapping_key[64]; + storage_deriveWrappingKey("123456789", wrapping_key, dst.pub.sca_hardened, + dst.pub.v15_16_trans, + dst.pub.random_salt, ""); // strongest pin evar + storage_unwrapStorageKey(wrapping_key, dst.pub.wrapped_storage_key, + session.storageKey); + storage_secMigrate(&session, &dst, /*encrypt=*/false); + + // Check that the secret area was correctly unencrypted. + EXPECT_EQ(dst.version, 10); + EXPECT_TRUE(dst.pub.has_node); + EXPECT_EQ(dst.sec.node.depth, 3); + EXPECT_EQ(dst.sec.node.fingerprint, 42); + EXPECT_EQ(dst.sec.node.child_num, 17); + EXPECT_EQ(dst.sec.node.chain_code.size, 32); + EXPECT_TRUE(memcmp(dst.sec.node.chain_code.bytes, + "XMRXMRXMRXMRXMRXMRXMRXMRXMRXMRX\0", 32) == 0); + EXPECT_EQ(dst.sec.node.has_private_key, true); + EXPECT_EQ(dst.sec.node.public_key.size, 33); + EXPECT_TRUE(memcmp(dst.sec.node.public_key.bytes, + "Who is Satoshi Nakomoto?????????\0", 32) == 0); + EXPECT_EQ(dst.pub.has_mnemonic, true); + + // Check the load path on storage_secMigrate() + char encrypted_sec[sizeof(dst.encrypted_sec)]; + memcpy(encrypted_sec, dst.encrypted_sec, sizeof(encrypted_sec)); + memzero(dst.encrypted_sec, sizeof(encrypted_sec)); + storage_secMigrate(&session, &dst, /*encrypt=*/true); + EXPECT_THAT(dst.encrypted_sec, ElementsAreArray(encrypted_sec)); } TEST(Storage, WriteCacheV1) { - Cache src; - src.root_seed_cache_status = 42; - memcpy(&src.root_seed_cache[0], "012345678901234567890123456789012345678901234567890123456789012", sizeof(src.root_seed_cache)); - memcpy(&src.root_ecdsa_curve_type[0], "secp256k1", 10); - - char dst[75]; - memset(dst, 0xCC, sizeof(dst)); - - storage_writeCacheV1(&dst[0], sizeof(dst), &src); - - const char expected[76] = "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31"; - - for (int i = 0; i < sizeof(dst); i++) { - ASSERT_EQ(dst[i], expected[i]) << "i: " << i; - ASSERT_EQ(dst[i], ((const char *)&src)[i]) << "i: " << i; - } + Cache src; + src.root_seed_cache_status = 42; + memcpy(&src.root_seed_cache[0], + "012345678901234567890123456789012345678901234567890123456789012", + sizeof(src.root_seed_cache)); + memcpy(&src.root_ecdsa_curve_type[0], "secp256k1", 10); + + char dst[75]; + memset(dst, 0xCC, sizeof(dst)); + + storage_writeCacheV1(&dst[0], sizeof(dst), &src); + + const char expected[76] = + "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" + "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" + "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" + "\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x00\x73\x65\x63\x70\x32\x35\x36" + "\x6b\x31"; + + for (int i = 0; i < sizeof(dst); i++) { + ASSERT_EQ(dst[i], expected[i]) << "i: " << i; + ASSERT_EQ(dst[i], ((const char *)&src)[i]) << "i: " << i; + } } TEST(Storage, ReadCacheV1) { - const char src[76] = "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31"; - - Cache dst; - - storage_readCacheV1(&dst, &src[0], sizeof(src)); - - ASSERT_EQ(dst.root_seed_cache_status, 42); - for (int i = 0; i < 64; i++) { - ASSERT_EQ(dst.root_seed_cache[i], "012345678901234567890123456789012345678901234567890123456789012"[i]) << "i: " << i; - } - ASSERT_TRUE(memcmp(dst.root_ecdsa_curve_type, "secp256k1", 10) == 0); - - for (int i = 0; i < sizeof(src) - 1; ++i) { - ASSERT_EQ(src[i], ((char *)&dst)[i]) << "i: " << i; - } + const char src[76] = + "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" + "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" + "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" + "\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x00\x73\x65\x63\x70\x32\x35\x36" + "\x6b\x31"; + + Cache dst; + + storage_readCacheV1(&dst, &src[0], sizeof(src)); + + ASSERT_EQ(dst.root_seed_cache_status, 42); + for (int i = 0; i < 64; i++) { + ASSERT_EQ( + dst.root_seed_cache[i], + "012345678901234567890123456789012345678901234567890123456789012"[i]) + << "i: " << i; + } + ASSERT_TRUE(memcmp(dst.root_ecdsa_curve_type, "secp256k1", 10) == 0); + + for (int i = 0; i < sizeof(src) - 1; ++i) { + ASSERT_EQ(src[i], ((char *)&dst)[i]) << "i: " << i; + } } TEST(Storage, DumpNode) { - HDNodeType dst; - HDNode src; - src.depth = 42; - src.child_num = 11; - src.chain_code[0] = 1; - src.chain_code[1] = 2; - src.chain_code[3] = 3; - src.chain_code[4] = 4; - src.private_key[0] = 5; - src.private_key[1] = 6; - src.private_key[2] = 7; - src.public_key[0] = 74; - - memset(&dst, 0, sizeof(dst)); - storage_dumpNode(&dst, &src); + HDNodeType dst; + HDNode src; + src.depth = 42; + src.child_num = 11; + src.chain_code[0] = 1; + src.chain_code[1] = 2; + src.chain_code[3] = 3; + src.chain_code[4] = 4; + src.private_key[0] = 5; + src.private_key[1] = 6; + src.private_key[2] = 7; + src.public_key[0] = 74; + + memset(&dst, 0, sizeof(dst)); + storage_dumpNode(&dst, &src); #if !DEBUG_LINK - EXPECT_EQ(dst.depth, 0); - EXPECT_EQ(dst.fingerprint, 0); - EXPECT_EQ(dst.child_num, 0); - EXPECT_EQ(dst.chain_code.size, 0); - EXPECT_EQ(dst.chain_code.bytes[0], 0); - EXPECT_EQ(dst.has_private_key, 0); - EXPECT_EQ(dst.private_key.size, 0); - EXPECT_EQ(dst.private_key.bytes[0], 0); - EXPECT_EQ(dst.has_public_key, 0); - EXPECT_EQ(dst.public_key.size, 0); - EXPECT_EQ(dst.public_key.bytes[0], 0); + EXPECT_EQ(dst.depth, 0); + EXPECT_EQ(dst.fingerprint, 0); + EXPECT_EQ(dst.child_num, 0); + EXPECT_EQ(dst.chain_code.size, 0); + EXPECT_EQ(dst.chain_code.bytes[0], 0); + EXPECT_EQ(dst.has_private_key, 0); + EXPECT_EQ(dst.private_key.size, 0); + EXPECT_EQ(dst.private_key.bytes[0], 0); + EXPECT_EQ(dst.has_public_key, 0); + EXPECT_EQ(dst.public_key.size, 0); + EXPECT_EQ(dst.public_key.bytes[0], 0); #else - EXPECT_EQ(dst.depth, src.depth); - EXPECT_EQ(dst.child_num, src.child_num); - EXPECT_EQ(dst.chain_code.size, 32); - EXPECT_THAT(dst.chain_code.bytes, ElementsAreArray(src.chain_code)); - EXPECT_EQ(dst.has_private_key, true); - EXPECT_EQ(dst.private_key.size, 32); - EXPECT_THAT(dst.private_key.bytes, ElementsAreArray(src.private_key)); - EXPECT_EQ(dst.public_key.size, 33); - EXPECT_THAT(dst.public_key.bytes, ElementsAreArray(src.public_key)); + EXPECT_EQ(dst.depth, src.depth); + EXPECT_EQ(dst.child_num, src.child_num); + EXPECT_EQ(dst.chain_code.size, 32); + EXPECT_THAT(dst.chain_code.bytes, ElementsAreArray(src.chain_code)); + EXPECT_EQ(dst.has_private_key, true); + EXPECT_EQ(dst.private_key.size, 32); + EXPECT_THAT(dst.private_key.bytes, ElementsAreArray(src.private_key)); + EXPECT_EQ(dst.public_key.size, 33); + EXPECT_THAT(dst.public_key.bytes, ElementsAreArray(src.public_key)); #endif } static void check_policyIsSame(const PolicyType *lhs, const PolicyType *rhs) { - EXPECT_EQ(lhs->has_policy_name, rhs->has_policy_name); + EXPECT_EQ(lhs->has_policy_name, rhs->has_policy_name); - if (lhs->has_policy_name) { - EXPECT_EQ(std::string(lhs->policy_name), std::string(rhs->policy_name)); - } + if (lhs->has_policy_name) { + EXPECT_EQ(std::string(lhs->policy_name), std::string(rhs->policy_name)); + } - EXPECT_EQ(lhs->has_enabled, rhs->has_enabled); - EXPECT_EQ(lhs->enabled, rhs->enabled); + EXPECT_EQ(lhs->has_enabled, rhs->has_enabled); + EXPECT_EQ(lhs->enabled, rhs->enabled); } TEST(Storage, ResetPolicies) { - Storage storage; - memset(&storage, 0xCC, sizeof(storage)); + Storage storage; + memset(&storage, 0xCC, sizeof(storage)); - storage_resetPolicies(&storage); + storage_resetPolicies(&storage); - EXPECT_EQ(storage.pub.policies_count, POLICY_COUNT); + EXPECT_EQ(storage.pub.policies_count, POLICY_COUNT); - for (int i = 0; i < POLICY_COUNT; ++i) { - check_policyIsSame(&storage.pub.policies[i], &policies[i]); - } + for (int i = 0; i < POLICY_COUNT; ++i) { + check_policyIsSame(&storage.pub.policies[i], &policies[i]); + } } TEST(Storage, SetPolicy) { - Storage storage; - memset(&storage, 0xCC, sizeof(storage)); + Storage storage; + memset(&storage, 0xCC, sizeof(storage)); - storage_resetPolicies(&storage); + storage_resetPolicies(&storage); - EXPECT_EQ(storage.pub.policies_count, POLICY_COUNT); + EXPECT_EQ(storage.pub.policies_count, POLICY_COUNT); - for (int i = 0; i < POLICY_COUNT; ++i) { - check_policyIsSame(&storage.pub.policies[i], &policies[i]); - } + for (int i = 0; i < POLICY_COUNT; ++i) { + check_policyIsSame(&storage.pub.policies[i], &policies[i]); + } - storage_setPolicy_impl(storage.pub.policies, "ShapeShift", true); - EXPECT_EQ(storage.pub.policies[0].enabled, true); + storage_setPolicy_impl(storage.pub.policies, "ShapeShift", true); + EXPECT_EQ(storage.pub.policies[0].enabled, true); - storage_setPolicy_impl(storage.pub.policies, "AdvancedMode", false); - EXPECT_EQ(storage.pub.policies[3].enabled, false); + storage_setPolicy_impl(storage.pub.policies, "AdvancedMode", false); + EXPECT_EQ(storage.pub.policies[3].enabled, false); - storage_setPolicy_impl(storage.pub.policies, "ShapeShift", false); - EXPECT_EQ(storage.pub.policies[0].enabled, false); + storage_setPolicy_impl(storage.pub.policies, "ShapeShift", false); + EXPECT_EQ(storage.pub.policies[0].enabled, false); - storage_setPolicy_impl(storage.pub.policies, "AdvancedMode", true); - EXPECT_EQ(storage.pub.policies[3].enabled, true); + storage_setPolicy_impl(storage.pub.policies, "AdvancedMode", true); + EXPECT_EQ(storage.pub.policies[3].enabled, true); } TEST(Storage, ResetCache) { - Cache src; - memset(&src, 0xCC, sizeof(src)); + Cache src; + memset(&src, 0xCC, sizeof(src)); - storage_resetCache(&src); + storage_resetCache(&src); - char dst[sizeof(src)]; - memset(&dst[0], 0, sizeof(dst)); + char dst[sizeof(src)]; + memset(&dst[0], 0, sizeof(dst)); - EXPECT_EQ(memcmp(&src, &dst, sizeof(Cache)), 0); + EXPECT_EQ(memcmp(&src, &dst, sizeof(Cache)), 0); } TEST(Storage, StorageUpgrade_Normal) { - const char flash[] = - // Meta - "\x73\x74\x6f\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - - // Storage - "\x08\x00\x00\x00" // version - "\x01" // has_node - "\x00\x00\x00" // reserved - "\x03\x00\x00\x00" // depth - "\x2a\x00\x00\x00" // fingerprint - "\x11\x00\x00\x00" // child_num - "\x20\x00\x00\x00" // chain_code.size - "\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58" // chain_code.bytes - "\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x00" // chain_code.bytes - "\x01" // has_private_key - "\x00\x00\x00" // reserved - "\x20\x00\x00\x00" // private_key.size - "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x59" // private_key.bytes - "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x00" // private_key.bytes - "\x01" // has_public_key - "\x00\x00\x00" // reserved - "\x21\x00\x00\x00" // public_key.size - "\x57\x68\x6f\x20\x69\x73\x20\x53\x61\x74\x6f\x73\x68\x69\x20\x4e" // public_key.bytes - "\x61\x6b\x6f\x6d\x6f\x74\x6f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f" // public_key.bytes - "\x00" // public_key.bytes - "\x00\x00\x00" // reserved - "\x01" // has_mnemonic - "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic - "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic - "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x77\x72\x6f\x6e" // menmonic - "\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic - "\x00" // mnemonic - "\x01" // reserved - "\x00" // passphrase_protection - "\x01" // has_pin_failed_attempts - "\x00\x00\x00" // reserved - "\x2a\x00\x00\x00" // pin_failed_attempts - "\x01" // has_pin - "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x00" // pin - "\x01" // has_language - "\x65\x73\x70\x65\x72\x61\x6e\x74\x6f\x00\x00\x00\x00\x00\x00\x00" // language - "\x00" // language - "\x01" // has_label - "\x4d\x65\x6e\x6f\x73\x4d\x61\x72\x78\x4d\x61\x69\x73\x4d\x69\x73" // label - "\x65\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // label - "\x00" // label - "\x01" // has_imported - "\x00" // imported - "\x00\x00\x00" // reserved - "\x01\x00\x00\x00" // policies_count - "\x01" // policies[0].has_policy_name - "\x53\x68\x61\x70\x65\x53\x68\x69\x66\x74\x00\x00\x00\x00\x00" // policies[0].policy_name - "\x01" // policies[0].has_enabled - "\x01" // policies[0].enabled - - // Cache - "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" - "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30" - "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" - "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" - "\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31\x00\x00"; - - SessionState session; - memset(&session, 0, sizeof(session)); - - ConfigFlash shadow; - ASSERT_EQ(storage_fromFlash(&session, &shadow, flash), SUS_Updated); - - // Decrypt upgraded storage. - uint8_t wrapping_key[64]; - storage_deriveWrappingKey("123456789", wrapping_key, shadow.storage.pub.sca_hardened, shadow.storage.pub.random_salt, ""); // strongest pin evar - storage_unwrapStorageKey(wrapping_key, shadow.storage.pub.wrapped_storage_key, - session.storageKey); - - storage_secMigrate(&session, &shadow.storage, /*encrypt=*/false); - - ConfigFlash shadow2; - memcpy(&shadow2, &shadow, sizeof(shadow2)); - memzero(&shadow2.storage.encrypted_sec, sizeof(shadow2.storage.encrypted_sec)); - ASSERT_TRUE(shadow.storage.has_sec); - shadow2.storage.has_sec = shadow.storage.has_sec; - - storage_secMigrate(&session, &shadow2.storage, /*encrypt=*/true); - - EXPECT_TRUE(memcmp(&shadow.storage.encrypted_sec, - &shadow2.storage.encrypted_sec, - sizeof(shadow.storage.encrypted_sec)) == 0); - - EXPECT_EQ(shadow.storage.version, STORAGE_VERSION); - EXPECT_EQ(shadow.storage.sec.node.depth, 3); - EXPECT_EQ(memcmp(shadow.meta.magic, "stor", 4), 0); - EXPECT_EQ(std::string(shadow.storage.pub.policies[0].policy_name), "ShapeShift"); - EXPECT_EQ(shadow.storage.pub.policies[0].enabled, true); - EXPECT_EQ(std::string(shadow.storage.pub.policies[1].policy_name), "Pin Caching"); - EXPECT_EQ(shadow.storage.pub.policies[1].enabled, true); + const char flash[] = + // Meta + "\x73\x74\x6f\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + // Storage + "\x08\x00\x00\x00" // version + "\x01" // has_node + "\x00\x00\x00" // reserved + "\x03\x00\x00\x00" // depth + "\x2a\x00\x00\x00" // fingerprint + "\x11\x00\x00\x00" // child_num + "\x20\x00\x00\x00" // chain_code.size + "\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58" // chain_code.bytes + "\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x4d\x52\x58\x00" // chain_code.bytes + "\x01" // has_private_key + "\x00\x00\x00" // reserved + "\x20\x00\x00\x00" // private_key.size + "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x59" // private_key.bytes + "\x46\x4f\x58\x59\x4b\x50\x4b\x59\x46\x4f\x58\x59\x4b\x50\x4b\x00" // private_key.bytes + "\x01" // has_public_key + "\x00\x00\x00" // reserved + "\x21\x00\x00\x00" // public_key.size + "\x57\x68\x6f\x20\x69\x73\x20\x53\x61\x74\x6f\x73\x68\x69\x20\x4e" // public_key.bytes + "\x61\x6b\x6f\x6d\x6f\x74\x6f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f" // public_key.bytes + "\x00" // public_key.bytes + "\x00\x00\x00" // reserved + "\x01" // has_mnemonic + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20" // mnemonic + "\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x7a\x6f\x6f\x20\x77\x72\x6f\x6e" // menmonic + "\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mnemonic + "\x00" // mnemonic + "\x01" // reserved + "\x00" // passphrase_protection + "\x01" // has_pin_failed_attempts + "\x00\x00\x00" // reserved + "\x2a\x00\x00\x00" // pin_failed_attempts + "\x01" // has_pin + "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x00" // pin + "\x01" // has_language + "\x65\x73\x70\x65\x72\x61\x6e\x74\x6f\x00\x00\x00\x00\x00\x00\x00" // language + "\x00" // language + "\x01" // has_label + "\x4d\x65\x6e\x6f\x73\x4d\x61\x72\x78\x4d\x61\x69\x73\x4d\x69\x73" // label + "\x65\x73\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // label + "\x00" // label + "\x01" // has_imported + "\x00" // imported + "\x00\x00\x00" // reserved + "\x01\x00\x00\x00" // policies_count + "\x01" // policies[0].has_policy_name + "\x53\x68\x61\x70\x65\x53\x68\x69\x66\x74\x00\x00\x00\x00\x00" // policies[0].policy_name + "\x01" // policies[0].has_enabled + "\x01" // policies[0].enabled + + // Cache + "\x2a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34" + "\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30" + "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36" + "\x37\x38\x39\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x31\x32" + "\x00\x73\x65\x63\x70\x32\x35\x36\x6b\x31\x00\x00"; + + SessionState session; + memset(&session, 0, sizeof(session)); + + ConfigFlash shadow; + ASSERT_EQ(storage_fromFlash(&session, &shadow, flash), SUS_Updated); + + // Decrypt upgraded storage. + uint8_t wrapping_key[64]; + storage_deriveWrappingKey( + "123456789", wrapping_key, shadow.storage.pub.sca_hardened, + shadow.storage.pub.v15_16_trans, + shadow.storage.pub.random_salt, ""); // strongest pin evar + storage_unwrapStorageKey(wrapping_key, shadow.storage.pub.wrapped_storage_key, + session.storageKey); + + storage_secMigrate(&session, &shadow.storage, /*encrypt=*/false); + + ConfigFlash shadow2; + memcpy(&shadow2, &shadow, sizeof(shadow2)); + memzero(&shadow2.storage.encrypted_sec, + sizeof(shadow2.storage.encrypted_sec)); + ASSERT_TRUE(shadow.storage.has_sec); + shadow2.storage.has_sec = shadow.storage.has_sec; + + storage_secMigrate(&session, &shadow2.storage, /*encrypt=*/true); + + EXPECT_TRUE(memcmp(&shadow.storage.encrypted_sec, + &shadow2.storage.encrypted_sec, + sizeof(shadow.storage.encrypted_sec)) == 0); + + EXPECT_EQ(shadow.storage.version, STORAGE_VERSION); + EXPECT_EQ(shadow.storage.sec.node.depth, 3); + EXPECT_EQ(memcmp(shadow.meta.magic, "stor", 4), 0); + EXPECT_EQ(std::string(shadow.storage.pub.policies[0].policy_name), + "ShapeShift"); + EXPECT_EQ(shadow.storage.pub.policies[0].enabled, true); + EXPECT_EQ(std::string(shadow.storage.pub.policies[1].policy_name), + "Pin Caching"); + EXPECT_EQ(shadow.storage.pub.policies[1].enabled, true); } TEST(Storage, StorageRoundTrip) { - ConfigFlash start; - memset(&start, 0xAB, sizeof(start)); - memcpy(start.meta.magic, "stor", 4); - start.storage.version = STORAGE_VERSION; - start.storage.sec.node.fingerprint = 42; - start.storage.pub.has_pin = true; - start.storage.pub.has_language = true; - start.storage.pub.has_label = true; - start.storage.pub.has_auto_lock_delay_ms = true; - start.storage.pub.imported = true; - start.storage.pub.passphrase_protection = true; - start.storage.pub.no_backup = false; - start.storage.pub.has_node = false; - start.storage.pub.has_mnemonic = true; - start.storage.pub.has_u2froot = false; - start.storage.pub.u2froot.has_public_key = false; - start.storage.pub.u2froot.has_private_key = true; - start.storage.pub.sca_hardened = false; - start.storage.has_sec = true; - start.storage.sec.pin[0] = '\0'; - start.storage.sec.cache.root_seed_cache_status = 0xEC; - start.storage.sec.node.has_public_key = true; - start.storage.sec.node.has_private_key = true; - - SessionState session; - memset(&session, 0, sizeof(session)); - - uint8_t wrapping_key[64]; - storage_deriveWrappingKey("", wrapping_key, start.storage.pub.sca_hardened, start.storage.pub.random_salt, ""); - storage_unwrapStorageKey(wrapping_key, start.storage.pub.wrapped_storage_key, session.storageKey); - - storage_secMigrate(&session, &start.storage, /*encrypt=*/true); - - std::vector flash(1024); - - storage_writeV11((char*)&flash[0], flash.size(), &start); + ConfigFlash start; + memset(&start, 0xAB, sizeof(start)); + memcpy(start.meta.magic, "stor", 4); + start.storage.version = STORAGE_VERSION; + start.storage.sec.node.fingerprint = 42; + start.storage.pub.has_pin = true; + start.storage.pub.has_language = true; + start.storage.pub.has_label = true; + start.storage.pub.has_auto_lock_delay_ms = true; + start.storage.pub.imported = true; + start.storage.pub.passphrase_protection = true; + start.storage.pub.no_backup = false; + start.storage.pub.has_node = false; + start.storage.pub.has_mnemonic = true; + start.storage.pub.has_u2froot = false; + start.storage.pub.u2froot.has_public_key = false; + start.storage.pub.u2froot.has_private_key = true; + start.storage.pub.sca_hardened = false; + start.storage.pub.v15_16_trans = false; + start.storage.has_sec = true; + start.storage.sec.pin[0] = '\0'; + start.storage.sec.cache.root_seed_cache_status = 0xEC; + start.storage.sec.node.has_public_key = true; + start.storage.sec.node.has_private_key = true; + + SessionState session; + memset(&session, 0, sizeof(session)); + + uint8_t wrapping_key[64]; + storage_deriveWrappingKey("", wrapping_key, start.storage.pub.sca_hardened, + start.storage.pub.v15_16_trans, + start.storage.pub.random_salt, ""); + storage_unwrapStorageKey(wrapping_key, start.storage.pub.wrapped_storage_key, + session.storageKey); + + storage_secMigrate(&session, &start.storage, /*encrypt=*/true); + + std::vector flash(2048); + + storage_writeV16((char *)&flash[0], flash.size(), &start); #if 0 printf(" "); @@ -483,236 +554,390 @@ TEST(Storage, StorageRoundTrip) { printf("\n"); #endif - const uint8_t expected_flash[] = { - 0x73, 0x74, 0x6f, 0x72, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, STORAGE_VERSION, 0x00, 0x00, 0x00, - 0xff, 0x42, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x20, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x01, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0x68, 0x9a, 0xf4, 0xaa, 0x5f, 0x36, 0xb1, 0x9c, 0x8c, 0x5a, 0xfb, 0xaa, 0x6e, 0xc3, - 0xd9, 0xfb, 0x6c, 0xee, 0x31, 0xed, 0xf2, 0xb3, 0x08, 0x53, 0x19, 0x8b, 0x20, 0xf1, 0x15, 0x02, - 0x73, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, STORAGE_VERSION, 0x00, 0x00, 0x00, - 0xe4, 0x8d, 0xfe, 0xcf, 0xd0, 0x54, 0x71, 0x50, 0xcb, 0x12, 0x84, 0xfa, 0x5f, 0xbf, 0xcb, 0x09, - 0xca, 0x00, 0xf1, 0x37, 0xe4, 0x8f, 0x5e, 0xf9, 0x81, 0x57, 0x26, 0xb6, 0x7b, 0x8e, 0x03, 0x44, - 0x9a, 0x2a, 0x7c, 0xf4, 0x3c, 0x79, 0x87, 0x5d, 0x26, 0xae, 0x9b, 0x4b, 0xb4, 0xd2, 0xc4, 0x67, - 0x97, 0xe7, 0x6b, 0x6c, 0x4c, 0xbe, 0x68, 0x19, 0x4c, 0x28, 0xf0, 0x5d, 0xef, 0xe8, 0x36, 0x20, - 0x0e, 0x4e, 0x0d, 0x5a, 0x9a, 0xc6, 0x09, 0x37, 0x38, 0xcb, 0x70, 0xb1, 0x90, 0x9d, 0xe7, 0x2c, - 0x4b, 0x32, 0x91, 0x41, 0x1d, 0xda, 0x38, 0x8c, 0xc7, 0x7b, 0x24, 0xc2, 0x5f, 0x40, 0xae, 0xfb, - 0xf8, 0xe7, 0xcd, 0x9e, 0xb5, 0x85, 0x29, 0xdb, 0xa3, 0x70, 0xc3, 0x1b, 0x56, 0xf2, 0x03, 0xfb, - 0xf8, 0xbe, 0xf6, 0x0d, 0x08, 0x00, 0xb4, 0xf8, 0x3b, 0x28, 0xdc, 0x9e, 0x56, 0xf4, 0x86, 0x0f, - 0x86, 0xbb, 0x54, 0xb6, 0x0e, 0x03, 0x78, 0x98, 0x53, 0xeb, 0xbc, 0xe7, 0xb4, 0x5f, 0xd6, 0x3a, - 0x7a, 0xc3, 0xfd, 0x7a, 0x1e, 0xe5, 0x8b, 0x55, 0x03, 0x3d, 0x32, 0x9a, 0x9c, 0x1b, 0x58, 0xdd, - 0xca, 0x23, 0x8d, 0x3b, 0x52, 0x71, 0x7c, 0x66, 0x2f, 0x83, 0xaa, 0xc8, 0xc9, 0xb3, 0xcc, 0xb3, - 0x82, 0x88, 0xac, 0x65, 0x1c, 0xf2, 0xe9, 0x0e, 0x94, 0xff, 0xeb, 0xfb, 0xbe, 0x71, 0x3f, 0x53, - 0x79, 0x73, 0x49, 0x9c, 0x25, 0xe5, 0xf1, 0xe4, 0xf6, 0xcf, 0x29, 0x80, 0x17, 0x6f, 0x1e, 0x94, - 0xf3, 0x79, 0x7f, 0xb0, 0x31, 0x75, 0xeb, 0xf6, 0xd3, 0x11, 0xf3, 0xb1, 0xea, 0xbe, 0x7d, 0x7c, - 0x39, 0xd9, 0x59, 0x7a, 0x30, 0x76, 0xce, 0xc5, 0x20, 0x63, 0xc2, 0x42, 0x95, 0xa5, 0xbc, 0xf3, - 0xe6, 0x39, 0x13, 0xd6, 0xea, 0x7a, 0xf5, 0xf3, 0x68, 0xed, 0x34, 0x63, 0x76, 0xf9, 0xf6, 0x28, - 0x9e, 0x5a, 0x79, 0x76, 0xa7, 0xbd, 0x67, 0x7f, 0xcc, 0xbc, 0xeb, 0x8d, 0x70, 0xbf, 0x4b, 0xaf, - 0xe9, 0x60, 0xb2, 0x90, 0x7d, 0xed, 0x98, 0x6e, 0x35, 0x64, 0x64, 0xdc, 0xf9, 0x79, 0xcc, 0x2c, - 0xfb, 0x94, 0x25, 0xbe, 0xb3, 0xc0, 0x12, 0xc2, 0x5e, 0xb0, 0x8e, 0x5c, 0x4a, 0x92, 0x2a, 0x71, - 0x87, 0xc1, 0x21, 0x6a, 0xb3, 0xed, 0x87, 0x7c, 0xfa, 0xff, 0xc0, 0xcd, 0x6c, 0xd4, 0xf7, 0x54, - 0xe9, 0x54, 0xdc, 0xa7, 0xb3, 0x8a, 0xa5, 0x0a, 0xd4, 0x02, 0xe1, 0xdf, 0x4c, 0xdf, 0x6c, 0xeb, - 0x97, 0xd3, 0x97, 0x29, 0x68, 0xde, 0x50, 0x2f, 0x7c, 0xeb, 0xc4, 0x1a, 0x40, 0x7f, 0x69, 0x4f, - 0xb5, 0x4f, 0x81, 0x64, 0x30, 0x49, 0xd7, 0x01, 0x7a, 0xd7, 0x55, 0x19, 0xb6, 0x33, 0xde, 0x0d, - 0x13, 0x75, 0xf7, 0x57, 0xd3, 0x81, 0xb8, 0xdd, 0x8c, 0x67, 0x73, 0xe0, 0x76, 0xb6, 0x44, 0x9f, - 0x6a, 0x33, 0x7b, 0x60, 0x60, 0x0b, 0xef, 0x23, 0x8b, 0x9d, 0x8c, 0x17, 0x1b, 0x02, 0xef, 0xf5, - 0x10, 0xcf, 0x5a, 0x8e, 0x3b, 0x00, 0x12, 0xb0, 0x45, 0x8e, 0x12, 0x57, 0x81, 0x5f, 0xfb, 0xfd, - 0x04, 0xff, 0xbc, 0xf4, 0x4c, 0xbf, 0xb5, 0x06, 0x10, 0xc1, 0xd8, 0x5e, 0x80, 0x17, 0x06, 0xda, - 0x37, 0x11, 0xba, 0x77, 0x61, 0xe5, 0xd6, 0x4a, 0x0d, 0xd8, 0x6f, 0xd1, 0xd4, 0x57, 0xba, 0xe6, - 0x8f, 0xd8, 0x7a, 0xfa, 0x4f, 0x35, 0x12, 0xdb, 0xbb, 0x34, 0xdf, 0x3f, 0x24, 0x30, 0x95, 0x42, - 0xe9, 0xc4, 0x71, 0xed, 0x0b, 0x4a, 0x9a, 0x61, 0xfa, 0x79, 0xc6, 0x5d, 0x1b, 0x0d, 0x34, 0x61, - 0x5f, 0x45, 0xc9, 0xa1, 0x01, 0xdf, 0x19, 0x3e, 0x7f, 0x3e, 0xb7, 0x2f, 0x0f, 0xdc, 0x26, 0x45, - 0xa2, 0xa0, 0xaa, 0xf9, 0xe1, 0x2b, 0x6b, 0x23, 0x19, 0xb7, 0x03, 0xd0, 0xa1, 0xb9, 0x88, 0x11, - }; - - EXPECT_TRUE(memcmp(&flash[0], expected_flash, sizeof(expected_flash)) == 0); - - ConfigFlash end; - memset(&end, 0xCC, sizeof(end)); - EXPECT_EQ(storage_fromFlash(&session, &end, (char*)&flash[0]), SUS_Valid); - - storage_secMigrate(&session, &end.storage, /*encrypt=*/false); - - EXPECT_EQ(end.storage.version, STORAGE_VERSION); - - EXPECT_EQ(end.storage.sec.cache.root_seed_cache_status, - start.storage.sec.cache.root_seed_cache_status); + const uint8_t expected_flash[] = { + 0x73, 0x74, 0x6f, 0x72, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xff, 0x42, 0x01, 0x00, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0x20, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x68, 0x9a, 0xf4, 0xaa, 0x5f, 0x36, + 0xb1, 0x9c, 0x8c, 0x5a, 0xfb, 0xaa, 0x6e, 0xc3, 0xd9, 0xfb, 0x6c, 0xee, + 0x31, 0xed, 0xf2, 0xb3, 0x08, 0x53, 0x19, 0x8b, 0x20, 0xf1, 0x15, 0x02, + 0x73, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x8d, 0xfe, + 0xcf, 0xd0, 0x54, 0x71, 0x50, 0xcb, 0x12, 0x84, 0xfa, 0x5f, 0xbf, 0xcb, + 0x09, 0xca, 0x00, 0xf1, 0x37, 0xe4, 0x8f, 0x5e, 0xf9, 0x81, 0x57, 0x26, + 0xb6, 0x7b, 0x8e, 0x03, 0x44, 0x9a, 0x2a, 0x7c, 0xf4, 0x3c, 0x79, 0x87, + 0x5d, 0x26, 0xae, 0x9b, 0x4b, 0xb4, 0xd2, 0xc4, 0x67, 0x97, 0xe7, 0x6b, + 0x6c, 0x4c, 0xbe, 0x68, 0x19, 0x4c, 0x28, 0xf0, 0x5d, 0xef, 0xe8, 0x36, + 0x20, 0x0e, 0x4e, 0x0d, 0x5a, 0x9a, 0xc6, 0x09, 0x37, 0x38, 0xcb, 0x70, + 0xb1, 0x90, 0x9d, 0xe7, 0x2c, 0x4b, 0x32, 0x91, 0x41, 0x1d, 0xda, 0x38, + 0x8c, 0xc7, 0x7b, 0x24, 0xc2, 0x5f, 0x40, 0xae, 0xfb, 0xf8, 0xe7, 0xcd, + 0x9e, 0xb5, 0x85, 0x29, 0xdb, 0xa3, 0x70, 0xc3, 0x1b, 0x56, 0xf2, 0x03, + 0xfb, 0xf8, 0xbe, 0xf6, 0x0d, 0x08, 0x00, 0xb4, 0xf8, 0x3b, 0x28, 0xdc, + 0x9e, 0x56, 0xf4, 0x86, 0x0f, 0x86, 0xbb, 0x54, 0xb6, 0x0e, 0x03, 0x78, + 0x98, 0x53, 0xeb, 0xbc, 0xe7, 0xb4, 0x5f, 0xd6, 0x3a, 0x7a, 0xc3, 0xfd, + 0x7a, 0x1e, 0xe5, 0x8b, 0x55, 0x03, 0x3d, 0x32, 0x9a, 0x9c, 0x1b, 0x58, + 0xdd, 0xca, 0x23, 0x8d, 0x3b, 0x52, 0x71, 0x7c, 0x66, 0x2f, 0x83, 0xaa, + 0xc8, 0xc9, 0xb3, 0xcc, 0xb3, 0x82, 0x88, 0xac, 0x65, 0x1c, 0xf2, 0xe9, + 0x0e, 0x94, 0xff, 0xeb, 0xfb, 0xbe, 0x71, 0x3f, 0x53, 0x79, 0x73, 0x49, + 0x9c, 0x25, 0xe5, 0xf1, 0xe4, 0xf6, 0xcf, 0x29, 0x80, 0x17, 0x6f, 0x1e, + 0x94, 0xf3, 0x79, 0x7f, 0xb0, 0x31, 0x75, 0xeb, 0xf6, 0xd3, 0x11, 0xf3, + 0xb1, 0xea, 0xbe, 0x7d, 0x7c, 0x39, 0xd9, 0x59, 0x7a, 0x30, 0x76, 0xce, + 0xc5, 0x20, 0x63, 0xc2, 0x42, 0x95, 0xa5, 0xbc, 0xf3, 0xe6, 0x39, 0x13, + 0xd6, 0xea, 0x7a, 0xf5, 0xf3, 0x68, 0xed, 0x34, 0x63, 0x76, 0xf9, 0xf6, + 0x28, 0x9e, 0x5a, 0x79, 0x76, 0xa7, 0xbd, 0x67, 0x7f, 0xcc, 0xbc, 0xeb, + 0x8d, 0x70, 0xbf, 0x4b, 0xaf, 0xe9, 0x60, 0xb2, 0x90, 0x7d, 0xed, 0x98, + 0x6e, 0x35, 0x64, 0x64, 0xdc, 0xf9, 0x79, 0xcc, 0x2c, 0xfb, 0x94, 0x25, + 0xbe, 0xb3, 0xc0, 0x12, 0xc2, 0x5e, 0xb0, 0x8e, 0x5c, 0x4a, 0x92, 0x2a, + 0x71, 0x87, 0xc1, 0x21, 0x6a, 0xb3, 0xed, 0x87, 0x7c, 0xfa, 0xff, 0xc0, + 0xcd, 0x6c, 0xd4, 0xf7, 0x54, 0xe9, 0x54, 0xdc, 0xa7, 0xb3, 0x8a, 0xa5, + 0x0a, 0xd4, 0x02, 0xe1, 0xdf, 0x4c, 0xdf, 0x6c, 0xeb, 0x97, 0xd3, 0x97, + 0x29, 0x68, 0xde, 0x50, 0x2f, 0x7c, 0xeb, 0xc4, 0x1a, 0x40, 0x7f, 0x69, + 0x4f, 0xb5, 0x4f, 0x81, 0x64, 0x30, 0x49, 0xd7, 0x01, 0x7a, 0xd7, 0x55, + 0x19, 0xb6, 0x33, 0xde, 0x0d, 0x13, 0x75, 0xf7, 0x57, 0xd3, 0x81, 0xb8, + 0xdd, 0x8c, 0x67, 0x73, 0xe0, 0x76, 0xb6, 0x44, 0x9f, 0x6a, 0x33, 0x7b, + 0x60, 0x60, 0x0b, 0xef, 0x23, 0x8b, 0x9d, 0x8c, 0x17, 0x1b, 0x02, 0xef, + 0xf5, 0x10, 0xcf, 0x5a, 0x8e, 0x3b, 0x00, 0x12, 0xb0, 0x45, 0x8e, 0x12, + 0x57, 0x81, 0x5f, 0xfb, 0xfd, 0x04, 0xff, 0xbc, 0xf4, 0x4c, 0xbf, 0xb5, + 0x06, 0x10, 0xc1, 0xd8, 0x5e, 0x80, 0x17, 0x06, 0xda, 0x37, 0x11, 0xba, + 0x77, 0x61, 0xe5, 0xd6, 0x4a, 0x0d, 0xd8, 0x6f, 0xd1, 0xd4, 0x57, 0xba, + 0xe6, 0x8f, 0xd8, 0x7a, 0xfa, 0x4f, 0x35, 0x12, 0xdb, 0xbb, 0x34, 0xdf, + 0x3f, 0x24, 0x30, 0x95, 0x42, 0xe9, 0xc4, 0x71, 0xed, 0x0b, 0x4a, 0x9a, + 0x61, 0xfa, 0x79, 0xc6, 0x5d, 0x1b, 0x0d, 0x34, 0x61, 0x5f, 0x45, 0xc9, + 0xa1, 0x01, 0xdf, 0x19, 0x3e, 0x7f, 0x3e, 0xb7, 0x2f, 0x0f, 0xdc, 0x26, + 0x45, 0xa2, 0xa0, 0xaa, 0xf9, 0xe1, 0x2b, 0x6b, + }; + + EXPECT_TRUE(memcmp(&flash[0], expected_flash, flash.size()) == 0); + + ConfigFlash end; + memset(&end, 0xCC, sizeof(end)); + EXPECT_EQ(storage_fromFlash(&session, &end, (char *)&flash[0]), SUS_Valid); + + storage_secMigrate(&session, &end.storage, /*encrypt=*/false); + + EXPECT_EQ(end.storage.version, STORAGE_VERSION); + + EXPECT_EQ(end.storage.sec.cache.root_seed_cache_status, + start.storage.sec.cache.root_seed_cache_status); } TEST(Storage, NoopSecMigrate) { - SessionState session; - Storage storage; - memset(storage.encrypted_sec, 0xAB, sizeof(storage.encrypted_sec)); - storage.has_sec = false; - - // Check that we don't blow away the encrypted_sec, if there weren't any - // plaintext secrets. - storage_secMigrate(&session, &storage, /*encrypt=*/true); - for (int i = 0; i < sizeof(storage.encrypted_sec); i++) { - ASSERT_EQ(storage.encrypted_sec[i], 0xAB); - } + SessionState session; + Storage storage; + memset(storage.encrypted_sec, 0xAB, sizeof(storage.encrypted_sec)); + storage.has_sec = false; + + // Check that we don't blow away the encrypted_sec, if there weren't any + // plaintext secrets. + storage_secMigrate(&session, &storage, /*encrypt=*/true); + for (int i = 0; i < sizeof(storage.encrypted_sec); i++) { + ASSERT_EQ(storage.encrypted_sec[i], 0xAB); + } } TEST(Storage, UpgradePolicies) { - Storage src; - src.pub.policies_count = 1; - src.pub.policies[0].has_policy_name = true; - memcpy(&src.pub.policies[0].policy_name[0], "ShapeShift", 11); - src.pub.policies[0].has_enabled = true; - src.pub.policies[0].enabled = true; - - storage_upgradePolicies(&src); - - EXPECT_EQ(src.pub.policies[0].has_policy_name, true); - EXPECT_EQ(std::string(src.pub.policies[0].policy_name), "ShapeShift"); - EXPECT_EQ(src.pub.policies[0].has_enabled, true); - EXPECT_EQ(src.pub.policies[0].enabled, true); - - EXPECT_EQ(src.pub.policies[1].has_policy_name, true); - EXPECT_EQ(std::string(src.pub.policies[1].policy_name), "Pin Caching"); - EXPECT_EQ(src.pub.policies[1].has_enabled, true); - EXPECT_EQ(src.pub.policies[1].enabled, true); + Storage src; + src.pub.policies_count = 1; + src.pub.policies[0].has_policy_name = true; + memcpy(&src.pub.policies[0].policy_name[0], "ShapeShift", 11); + src.pub.policies[0].has_enabled = true; + src.pub.policies[0].enabled = true; + + storage_upgradePolicies(&src); + + EXPECT_EQ(src.pub.policies[0].has_policy_name, true); + EXPECT_EQ(std::string(src.pub.policies[0].policy_name), "ShapeShift"); + EXPECT_EQ(src.pub.policies[0].has_enabled, true); + EXPECT_EQ(src.pub.policies[0].enabled, true); + + EXPECT_EQ(src.pub.policies[1].has_policy_name, true); + EXPECT_EQ(std::string(src.pub.policies[1].policy_name), "Pin Caching"); + EXPECT_EQ(src.pub.policies[1].has_enabled, true); + EXPECT_EQ(src.pub.policies[1].enabled, true); } TEST(Storage, IsPinCorrect) { - bool sca_hardened = true; + bool sca_hardened = true; + bool v15_16_trans = true; - uint8_t wrapping_key[64]; - uint8_t random_salt[32]; - memset(random_salt, 0, sizeof(random_salt)); - storage_deriveWrappingKey("1234", wrapping_key, sca_hardened, random_salt, ""); + uint8_t wrapping_key[64]; + uint8_t random_salt[32]; + memset(random_salt, 0, sizeof(random_salt)); + storage_deriveWrappingKey("1234", wrapping_key, sca_hardened, + v15_16_trans, random_salt, ""); - const uint8_t storage_key[64] = "Quick blue fox"; - uint8_t wrapped_key[64]; - storage_wrapStorageKey(wrapping_key, storage_key, wrapped_key); + const uint8_t storage_key[64] = "Quick blue fox"; + uint8_t wrapped_key[64]; + storage_wrapStorageKey(wrapping_key, storage_key, wrapped_key); - uint8_t fingerprint[32]; - storage_keyFingerprint(storage_key, fingerprint); + uint8_t fingerprint[32]; + storage_keyFingerprint(storage_key, fingerprint); - uint8_t key_out[64]; - EXPECT_TRUE(storage_isPinCorrect_impl("1234", wrapped_key, fingerprint, &sca_hardened, key_out, random_salt)); + uint8_t key_out[64]; + EXPECT_TRUE(storage_isPinCorrect_impl("1234", wrapped_key, fingerprint, + &sca_hardened, &v15_16_trans, + key_out, random_salt)); - EXPECT_TRUE(memcmp(key_out, storage_key, 64) == 0); + EXPECT_TRUE(memcmp(key_out, storage_key, 64) == 0); } -TEST(Storage, Vuln1996) { - ConfigFlash config; - SessionState session; - uint8_t wrapping_key[64], wrapped_key1[64], wrapping_key_upin[64], storage_key[64], random_salt[32]; - - struct { - const char *pin; - } vec[] = { - { "" }, - { "1234" }, - { "000000000" }, - }; - - for (const auto &v : vec) { - memset(&session, 0, sizeof(session)); - memset(&config, 0, sizeof(config)); - memset(random_salt, 0, sizeof(random_salt)); - storage_reset_impl(&session, &config); - - storage_setPin_impl(&session, &config.storage, v.pin); - - ASSERT_TRUE(PIN_GOOD == storage_isPinCorrect_impl(v.pin, - config.storage.pub.wrapped_storage_key, - config.storage.pub.storage_key_fingerprint, - &config.storage.pub.sca_hardened, - storage_key, - random_salt)); - ASSERT_TRUE(config.storage.pub.sca_hardened == true); - memcpy(wrapped_key1, config.storage.pub.wrapped_storage_key, sizeof(wrapped_key1)); - - // wrapped_key1 should be wrapped with aes128-pinstretch - - // Check storage wrapping update by generating parameters consistent with aes256-pinnostretch - - // first obtain the storage key generated above - storage_deriveWrappingKey(v.pin, wrapping_key, config.storage.pub.sca_hardened, random_salt, ""); - storage_unwrapStorageKey(wrapping_key, config.storage.pub.wrapped_storage_key, storage_key); - - // now derive a wrapping key from unstretched pin and wrap the storage key with it - storage_deriveWrappingKey(v.pin, wrapping_key_upin, false, random_salt, ""); - uint8_t iv[64]; - memcpy(iv, wrapping_key_upin, sizeof(iv)); - aes_encrypt_ctx ctx; - aes_encrypt_key256(wrapping_key_upin, &ctx); - aes_cbc_encrypt(storage_key, config.storage.pub.wrapped_storage_key, 64, iv + 32, &ctx); - config.storage.pub.sca_hardened = false; // indicate this is an unhardened wrap key - - // wrapped_key1 is aes128-pinstretch. Config version is wrapped aes256-pinnostretch - // for test. - - // This check ensures that test conditions are correct. - ASSERT_TRUE(memcmp(wrapped_key1, config.storage.pub.wrapped_storage_key, sizeof(wrapped_key1)) != 0); - - // now check that aes256-nopinstretch turns into aes128-pinstretched wrapping key - ASSERT_TRUE(storage_isPinCorrect_impl(v.pin, - config.storage.pub.wrapped_storage_key, - config.storage.pub.storage_key_fingerprint, - &config.storage.pub.sca_hardened, - storage_key, - random_salt)); - ASSERT_TRUE(memcmp(wrapped_key1, config.storage.pub.wrapped_storage_key, sizeof(wrapped_key1)) == 0); - ASSERT_TRUE(config.storage.pub.sca_hardened == true); - } -} +TEST(Storage, IsWipeCodeCorrect) { + uint8_t wrapping_key[64]; + uint8_t random_salt[32]; + memset(random_salt, 0, sizeof(random_salt)); + storage_deriveWrappingKey("2222", wrapping_key, true, true, random_salt, ""); -TEST(Storage, Reset) { - ConfigFlash config; - SessionState session; - memset(&session, 0, sizeof(session)); + const uint8_t storage_key[64] = "Quick blue fox"; + uint8_t wrapped_key[64]; + storage_wrapStorageKey(wrapping_key, storage_key, wrapped_key); - storage_reset_impl(&session, &config); + uint8_t fingerprint[32]; + storage_keyFingerprint(storage_key, fingerprint); - ASSERT_TRUE(storage_isPinCorrect_impl("", - config.storage.pub.wrapped_storage_key, - config.storage.pub.storage_key_fingerprint, - &config.storage.pub.sca_hardened, - session.storageKey, - config.storage.pub.random_salt)); + uint8_t key_out[64]; + EXPECT_TRUE(storage_isWipeCodeCorrect_impl("2222", wrapped_key, fingerprint, + key_out, random_salt)); - uint8_t old_storage_key[64]; - memcpy(old_storage_key, session.storageKey, sizeof(old_storage_key)); - storage_setPin_impl(&session, &config.storage, "1234"); + EXPECT_TRUE(memcmp(key_out, storage_key, 64) == 0); +} - ASSERT_TRUE(memcmp(session.storageKey, old_storage_key, 64) != 0) - << "RNG broken?"; +TEST(Storage, Vuln1996) { + ConfigFlash config; + SessionState session; + uint8_t wrapping_key[64], wrapped_key1[64], wrapping_key_upin[64], + storage_key[64], random_salt[32]; + + struct { + const char *pin; + } vec[] = { + {""}, + {"1234"}, + {"000000000"}, + }; + + for (const auto &v : vec) { + memset(&session, 0, sizeof(session)); + memset(&config, 0, sizeof(config)); + memset(random_salt, 0, sizeof(random_salt)); + storage_reset_impl(&session, &config); - uint8_t new_storage_key[64]; - ASSERT_TRUE(storage_isPinCorrect_impl("1234", - config.storage.pub.wrapped_storage_key, + storage_setPin_impl(&session, &config.storage, v.pin); + + ASSERT_TRUE(PIN_GOOD == storage_isPinCorrect_impl( + v.pin, config.storage.pub.wrapped_storage_key, + config.storage.pub.storage_key_fingerprint, + &config.storage.pub.sca_hardened, + &config.storage.pub.v15_16_trans, + storage_key, + random_salt)); + ASSERT_TRUE(config.storage.pub.sca_hardened == true); + memcpy(wrapped_key1, config.storage.pub.wrapped_storage_key, + sizeof(wrapped_key1)); + + // wrapped_key1 should be wrapped with aes128-pinstretch + + // Check storage wrapping update by generating parameters consistent with + // aes256-pinnostretch + + // first obtain the storage key generated above + storage_deriveWrappingKey(v.pin, wrapping_key, + config.storage.pub.sca_hardened, + config.storage.pub.v15_16_trans, + random_salt, ""); + storage_unwrapStorageKey( + wrapping_key, config.storage.pub.wrapped_storage_key, storage_key); + + // now derive a wrapping key from unstretched pin and wrap the storage key + // with it + storage_deriveWrappingKey(v.pin, wrapping_key_upin, false, false, random_salt, ""); + uint8_t iv[64]; + memcpy(iv, wrapping_key_upin, sizeof(iv)); + aes_encrypt_ctx ctx; + aes_encrypt_key256(wrapping_key_upin, &ctx); + aes_cbc_encrypt(storage_key, config.storage.pub.wrapped_storage_key, 64, + iv + 32, &ctx); + config.storage.pub.sca_hardened = + false; // indicate this is an unhardened wrap key + + // wrapped_key1 is aes128-pinstretch. Config version is wrapped + // aes256-pinnostretch for test. + + // This check ensures that test conditions are correct. + ASSERT_TRUE(memcmp(wrapped_key1, config.storage.pub.wrapped_storage_key, + sizeof(wrapped_key1)) != 0); + + // now check that aes256-nopinstretch turns into aes128-pinstretched + // wrapping key + ASSERT_TRUE(storage_isPinCorrect_impl( + v.pin, config.storage.pub.wrapped_storage_key, config.storage.pub.storage_key_fingerprint, - &config.storage.pub.sca_hardened, - new_storage_key, - config.storage.pub.random_salt)); + &config.storage.pub.sca_hardened, + &config.storage.pub.v15_16_trans, + storage_key, random_salt)); + ASSERT_TRUE(memcmp(wrapped_key1, config.storage.pub.wrapped_storage_key, + sizeof(wrapped_key1)) == 0); + ASSERT_TRUE(config.storage.pub.sca_hardened == true); + } +} - ASSERT_TRUE(memcmp(session.storageKey, new_storage_key, 64) == 0); +TEST(Storage, Reset) { + ConfigFlash config; + SessionState session; + uint8_t scratch_buf[64]; + memset(&session, 0, sizeof(session)); + + storage_reset_impl(&session, &config); + + ASSERT_TRUE(storage_isPinCorrect_impl( + "", config.storage.pub.wrapped_storage_key, + config.storage.pub.storage_key_fingerprint, + &config.storage.pub.sca_hardened, + &config.storage.pub.v15_16_trans, + session.storageKey, + config.storage.pub.random_salt)); + + uint8_t old_storage_key[64]; + memcpy(old_storage_key, session.storageKey, sizeof(old_storage_key)); + storage_setPin_impl(&session, &config.storage, "1234"); + storage_setWipeCode_impl(&session, &config.storage, "2222"); + + ASSERT_TRUE(memcmp(session.storageKey, old_storage_key, 64) != 0) + << "RNG broken?"; + + uint8_t new_storage_key[64]; + ASSERT_TRUE(storage_isPinCorrect_impl( + "1234", config.storage.pub.wrapped_storage_key, + config.storage.pub.storage_key_fingerprint, + &config.storage.pub.sca_hardened, + &config.storage.pub.sca_hardened, + new_storage_key, + config.storage.pub.random_salt)); + + ASSERT_TRUE(storage_isWipeCodeCorrect_impl( + "2222", config.storage.pub.wrapped_wipe_code_key, + config.storage.pub.wipe_code_key_fingerprint, scratch_buf, + config.storage.pub.random_salt)); + + ASSERT_TRUE(memcmp(session.storageKey, new_storage_key, 64) == 0); } diff --git a/unittests/firmware/u2f.cpp b/unittests/firmware/u2f.cpp index 870340fc1..3e499382c 100644 --- a/unittests/firmware/u2f.cpp +++ b/unittests/firmware/u2f.cpp @@ -8,21 +8,26 @@ extern "C" { #include TEST(U2F, WordsFromData) { - const uint8_t buff1[32] = "123456789012345678901"; - ASSERT_EQ(std::string(words_from_data(buff1, 6)), "couple muscle snack heavy"); + const uint8_t buff1[32] = "123456789012345678901"; + ASSERT_EQ(std::string(words_from_data(buff1, 6)), + "couple muscle snack heavy"); - const uint8_t buff2[32] = "keepkeykeepkeykeepkey"; - ASSERT_EQ(std::string(words_from_data(buff2, 6)), "hidden clinic foster strategy"); + const uint8_t buff2[32] = "keepkeykeepkeykeepkey"; + ASSERT_EQ(std::string(words_from_data(buff2, 6)), + "hidden clinic foster strategy"); - ASSERT_EQ(std::string(u2f_well_known[6].appname), "Bitbucket"); - ASSERT_EQ(std::string(words_from_data(u2f_well_known[6].appid, 6)), "bar peace tonight cement"); + ASSERT_EQ(std::string(u2f_well_known[6].appname), "Bitbucket"); + ASSERT_EQ(std::string(words_from_data(u2f_well_known[6].appid, 6)), + "bar peace tonight cement"); } TEST(U2F, ShapeShift) { - ASSERT_EQ(U2F_SHAPESHIFT_COM->appname, std::string("ShapeShift")); - ASSERT_EQ(U2F_SHAPESHIFT_IO->appname, std::string("ShapeShift")); - ASSERT_EQ(U2F_SHAPESHIFT_COM_STG->appname, std::string("ShapeShift (staging)")); - ASSERT_EQ(U2F_SHAPESHIFT_IO_STG->appname, std::string("ShapeShift (staging)")); - ASSERT_EQ(U2F_SHAPESHIFT_COM_DEV->appname, std::string("ShapeShift (dev)")); - ASSERT_EQ(U2F_SHAPESHIFT_IO_DEV->appname, std::string("ShapeShift (dev)")); + ASSERT_EQ(U2F_SHAPESHIFT_COM->appname, std::string("ShapeShift")); + ASSERT_EQ(U2F_SHAPESHIFT_IO->appname, std::string("ShapeShift")); + ASSERT_EQ(U2F_SHAPESHIFT_COM_STG->appname, + std::string("ShapeShift (staging)")); + ASSERT_EQ(U2F_SHAPESHIFT_IO_STG->appname, + std::string("ShapeShift (staging)")); + ASSERT_EQ(U2F_SHAPESHIFT_COM_DEV->appname, std::string("ShapeShift (dev)")); + ASSERT_EQ(U2F_SHAPESHIFT_IO_DEV->appname, std::string("ShapeShift (dev)")); } diff --git a/unittests/firmware/usb_rx.cpp b/unittests/firmware/usb_rx.cpp index e8619a4a2..4191094f1 100644 --- a/unittests/firmware/usb_rx.cpp +++ b/unittests/firmware/usb_rx.cpp @@ -15,82 +15,82 @@ static int failure_count; static std::string message; static void setup() { - failure_count = 0; + failure_count = 0; - set_msg_failure_handler(+[](FailureType code, const char *text) { - failure_count++; - message = text; - }); + set_msg_failure_handler(+[](FailureType code, const char *text) { + failure_count++; + message = text; + }); } TEST(USBRX, Overflow) { - fsm_init(); - setup(); - - char msg[64]; - TrezorFrame *frame = (TrezorFrame *)msg; - TrezorFrameFragment *frame_fragment = (TrezorFrameFragment *)msg; - - frame->usb_header.hid_type = '?'; - frame->header.pre1 = '#'; - frame->header.pre2 = '#'; - frame->header.id = __builtin_bswap16(MessageType_MessageType_Initialize); - frame->header.len = __builtin_bswap32(0xffffffff); + fsm_init(); + setup(); + + char msg[64]; + TrezorFrame *frame = (TrezorFrame *)msg; + TrezorFrameFragment *frame_fragment = (TrezorFrameFragment *)msg; + + frame->usb_header.hid_type = '?'; + frame->header.pre1 = '#'; + frame->header.pre2 = '#'; + frame->header.id = __builtin_bswap16(MessageType_MessageType_Initialize); + frame->header.len = __builtin_bswap32(0xffffffff); + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + + frame->header.pre1 = '0'; + frame->header.pre2 = '0'; + + // Send packets up until the point just before where the buffer internal to + // usb_rx_helper would overflow. All of these should succeeed. + for (unsigned i = 0; i < 1039; i++) { usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - - frame->header.pre1 = '0'; - frame->header.pre2 = '0'; - - // Send packets up until the point just before where the buffer internal to - // usb_rx_helper would overflow. All of these should succeeed. - for (unsigned i = 0; i < 1039; i++) { - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 0); - } - - // Then on the last one, check that we detect the overflow before it happens: - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 1); - ASSERT_EQ(message, "Malformed message"); - - // And check that the state got cleared out afterward: - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 2); - ASSERT_EQ(message, "Malformed packet"); + ASSERT_EQ(failure_count, 0); + } + + // Then on the last one, check that we detect the overflow before it happens: + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 1); + ASSERT_EQ(message, "Malformed message"); + + // And check that the state got cleared out afterward: + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 2); + ASSERT_EQ(message, "Malformed packet"); } TEST(USBRX, ErrorHandling) { - fsm_init(); - setup(); + fsm_init(); + setup(); - char msg[64]; - memset(msg, 0, sizeof(msg)); + char msg[64]; + memset(msg, 0, sizeof(msg)); - // Missing '?' - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 1); - ASSERT_EQ(message, "Malformed packet"); + // Missing '?' + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 1); + ASSERT_EQ(message, "Malformed packet"); - msg[0] = '?'; + msg[0] = '?'; - // Missing '#' - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 2); - ASSERT_EQ(message, "Malformed packet"); + // Missing '#' + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 2); + ASSERT_EQ(message, "Malformed packet"); - msg[1] = '#'; + msg[1] = '#'; - // Missing '#' - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 3); - ASSERT_EQ(message, "Malformed packet"); + // Missing '#' + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 3); + ASSERT_EQ(message, "Malformed packet"); - msg[2] = '#'; - msg[3] = 0xff; - msg[6] = 0xff; + msg[2] = '#'; + msg[3] = 0xff; + msg[6] = 0xff; - // Unknown msgId - usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); - ASSERT_EQ(failure_count, 4); - ASSERT_EQ(message, "Unknown message"); + // Unknown msgId + usb_rx_helper(&msg, sizeof(msg), NORMAL_MSG); + ASSERT_EQ(failure_count, 4); + ASSERT_EQ(message, "Unknown message"); }