format: start using clang-format with style=Google

pull/25/head
Pavol Rusnak 5 years ago
parent e53826e951
commit 0b7dbc12cb
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -1,3 +1,2 @@
--- ---
BasedOnStyle: Google BasedOnStyle: Google
IndentWidth: 4

@ -86,10 +86,11 @@ style: ## apply code style on application sources and tests
black $(shell find src -name *.py ! -path 'src/trezor/messages/*') black $(shell find src -name *.py ! -path 'src/trezor/messages/*')
cstyle_check: ## run code style check on low-level C code cstyle_check: ## run code style check on low-level C code
./tools/clang-format-check $(shell find embed -type f -name *.[ch]) ./tools/clang-format-check embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
cstyle: ## apply code style on low-level C code cstyle: ## apply code style on low-level C code
clang-format -i $(shell find embed -type f -name *.[ch]) clang-format -i embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
## code generation: ## code generation:

@ -21,8 +21,8 @@
#include "common.h" #include "common.h"
#include "display.h" #include "display.h"
#include "image.h"
#include "flash.h" #include "flash.h"
#include "image.h"
#include "rng.h" #include "rng.h"
#include "sdcard.h" #include "sdcard.h"
@ -45,158 +45,164 @@ static const uint8_t * const BOARDLOADER_KEYS[] = {
#endif #endif
}; };
static uint32_t check_sdcard(void) static uint32_t check_sdcard(void) {
{ if (sectrue != sdcard_power_on()) {
if (sectrue != sdcard_power_on()) { return 0;
return 0; }
}
uint64_t cap = sdcard_get_capacity_in_bytes();
if (cap < 1024 * 1024) {
sdcard_power_off();
return 0;
}
uint32_t buf[IMAGE_HEADER_SIZE / sizeof(uint32_t)]; uint64_t cap = sdcard_get_capacity_in_bytes();
if (cap < 1024 * 1024) {
sdcard_power_off();
return 0;
}
memzero(buf, sizeof(buf)); uint32_t buf[IMAGE_HEADER_SIZE / sizeof(uint32_t)];
const secbool read_status = sdcard_read_blocks(buf, 0, IMAGE_HEADER_SIZE / SDCARD_BLOCK_SIZE); memzero(buf, sizeof(buf));
sdcard_power_off(); const secbool read_status =
sdcard_read_blocks(buf, 0, IMAGE_HEADER_SIZE / SDCARD_BLOCK_SIZE);
image_header hdr; sdcard_power_off();
if ((sectrue == read_status) && (sectrue == load_image_header((const uint8_t *)buf, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE, BOARDLOADER_KEY_M, BOARDLOADER_KEY_N, BOARDLOADER_KEYS, &hdr))) { image_header hdr;
return hdr.codelen;
} else {
return 0;
}
}
static void progress_callback(int pos, int len) { if ((sectrue == read_status) &&
display_printf("."); (sectrue ==
load_image_header((const uint8_t *)buf, BOOTLOADER_IMAGE_MAGIC,
BOOTLOADER_IMAGE_MAXSIZE, BOARDLOADER_KEY_M,
BOARDLOADER_KEY_N, BOARDLOADER_KEYS, &hdr))) {
return hdr.codelen;
} else {
return 0;
}
} }
static secbool copy_sdcard(void) static void progress_callback(int pos, int len) { display_printf("."); }
{
display_backlight(255);
display_printf("TREZOR Boardloader\n"); static secbool copy_sdcard(void) {
display_printf("==================\n\n"); display_backlight(255);
display_printf("bootloader found on the SD card\n\n"); display_printf("TREZOR Boardloader\n");
display_printf("applying bootloader in 10 seconds\n\n"); display_printf("==================\n\n");
display_printf("unplug now if you want to abort\n\n");
uint32_t codelen; display_printf("bootloader found on the SD card\n\n");
display_printf("applying bootloader in 10 seconds\n\n");
display_printf("unplug now if you want to abort\n\n");
for (int i = 10; i >= 0; i--) { uint32_t codelen;
display_printf("%d ", i);
hal_delay(1000);
codelen = check_sdcard();
if (0 == codelen) {
display_printf("\n\nno SD card, aborting\n");
return secfalse;
}
}
display_printf("\n\nerasing flash:\n\n"); for (int i = 10; i >= 0; i--) {
display_printf("%d ", i);
// erase all flash (except boardloader) hal_delay(1000);
static const uint8_t sectors[] = { codelen = check_sdcard();
FLASH_SECTOR_STORAGE_1, if (0 == codelen) {
FLASH_SECTOR_STORAGE_2, display_printf("\n\nno SD card, aborting\n");
3, return secfalse;
FLASH_SECTOR_BOOTLOADER,
FLASH_SECTOR_FIRMWARE_START,
7,
8,
9,
10,
FLASH_SECTOR_FIRMWARE_END,
FLASH_SECTOR_UNUSED_START,
13,
14,
FLASH_SECTOR_UNUSED_END,
FLASH_SECTOR_FIRMWARE_EXTRA_START,
18,
19,
20,
21,
22,
FLASH_SECTOR_FIRMWARE_EXTRA_END,
};
if (sectrue != flash_erase_sectors(sectors, sizeof(sectors), progress_callback)) {
display_printf(" failed\n");
return secfalse;
} }
display_printf(" done\n\n"); }
ensure(flash_unlock_write(), NULL); display_printf("\n\nerasing flash:\n\n");
// copy bootloader from SD card to Flash // erase all flash (except boardloader)
display_printf("copying new bootloader from SD card\n\n"); static const uint8_t sectors[] = {
FLASH_SECTOR_STORAGE_1,
ensure(sdcard_power_on(), NULL); FLASH_SECTOR_STORAGE_2,
3,
uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; FLASH_SECTOR_BOOTLOADER,
for (int i = 0; i < (IMAGE_HEADER_SIZE + codelen) / SDCARD_BLOCK_SIZE; i++) { FLASH_SECTOR_FIRMWARE_START,
ensure(sdcard_read_blocks(buf, i, 1), NULL); 7,
for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { 8,
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]), NULL); 9,
} 10,
FLASH_SECTOR_FIRMWARE_END,
FLASH_SECTOR_UNUSED_START,
13,
14,
FLASH_SECTOR_UNUSED_END,
FLASH_SECTOR_FIRMWARE_EXTRA_START,
18,
19,
20,
21,
22,
FLASH_SECTOR_FIRMWARE_EXTRA_END,
};
if (sectrue !=
flash_erase_sectors(sectors, sizeof(sectors), progress_callback)) {
display_printf(" failed\n");
return secfalse;
}
display_printf(" done\n\n");
ensure(flash_unlock_write(), NULL);
// copy bootloader from SD card to Flash
display_printf("copying new bootloader from SD card\n\n");
ensure(sdcard_power_on(), NULL);
uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
for (int i = 0; i < (IMAGE_HEADER_SIZE + codelen) / SDCARD_BLOCK_SIZE; i++) {
ensure(sdcard_read_blocks(buf, i, 1), NULL);
for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) {
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER,
i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t),
buf[j]),
NULL);
} }
}
sdcard_power_off(); sdcard_power_off();
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
display_printf("\ndone\n\n"); display_printf("\ndone\n\n");
display_printf("Unplug the device and remove the SD card\n"); display_printf("Unplug the device and remove the SD card\n");
return sectrue; return sectrue;
} }
int main(void) int main(void) {
{ if (sectrue != reset_flags_check()) {
if (sectrue != reset_flags_check()) { return 1;
return 1; }
}
// need the systick timer running before many HAL operations. // need the systick timer running before many HAL operations.
// want the PVD enabled before flash operations too. // want the PVD enabled before flash operations too.
periph_init(); periph_init();
if (sectrue != flash_configure_option_bytes()) { if (sectrue != flash_configure_option_bytes()) {
// display is not initialized so don't call ensure // display is not initialized so don't call ensure
secbool r = flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL); secbool r =
(void)r; flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL);
return 2; (void)r;
} return 2;
}
clear_otg_hs_memory(); clear_otg_hs_memory();
display_init(); display_init();
sdcard_init(); sdcard_init();
if (check_sdcard()) { if (check_sdcard()) {
return copy_sdcard() == sectrue ? 0 : 3; return copy_sdcard() == sectrue ? 0 : 3;
} }
image_header hdr; image_header hdr;
ensure( ensure(load_image_header((const uint8_t *)BOOTLOADER_START,
load_image_header((const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE, BOARDLOADER_KEY_M, BOARDLOADER_KEY_N, BOARDLOADER_KEYS, &hdr), BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE,
"invalid bootloader header"); BOARDLOADER_KEY_M, BOARDLOADER_KEY_N,
BOARDLOADER_KEYS, &hdr),
"invalid bootloader header");
const uint8_t sectors[] = { const uint8_t sectors[] = {
FLASH_SECTOR_BOOTLOADER, FLASH_SECTOR_BOOTLOADER,
}; };
ensure( ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE, sectors, 1),
check_image_contents(&hdr, IMAGE_HEADER_SIZE, sectors, 1), "invalid bootloader hash");
"invalid bootloader hash");
jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE); jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE);
return 0; return 0;
} }

@ -1,4 +1,4 @@
#define VERSION_MAJOR 2 #define VERSION_MAJOR 2
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_PATCH 2 #define VERSION_PATCH 2
#define VERSION_BUILD 0 #define VERSION_BUILD 0

@ -28,9 +28,9 @@
#include "icon_cancel.h" #include "icon_cancel.h"
#include "icon_confirm.h" #include "icon_confirm.h"
#include "icon_info.h"
#include "icon_done.h" #include "icon_done.h"
#include "icon_fail.h" #include "icon_fail.h"
#include "icon_info.h"
#include "icon_install.h" #include "icon_install.h"
#include "icon_wipe.h" #include "icon_wipe.h"
@ -40,283 +40,319 @@
#define BACKLIGHT_NORMAL 150 #define BACKLIGHT_NORMAL 150
#define COLOR_BL_FAIL RGB16(0xFF, 0x00, 0x00) // red #define COLOR_BL_FAIL RGB16(0xFF, 0x00, 0x00) // red
#define COLOR_BL_DONE RGB16(0x00, 0xAE, 0x0B) // green #define COLOR_BL_DONE RGB16(0x00, 0xAE, 0x0B) // green
#define COLOR_BL_PROCESS RGB16(0x4A, 0x90, 0xE2) // blue #define COLOR_BL_PROCESS RGB16(0x4A, 0x90, 0xE2) // blue
#define COLOR_BL_GRAY RGB16(0x99, 0x99, 0x99) // gray #define COLOR_BL_GRAY RGB16(0x99, 0x99, 0x99) // gray
// common shared functions // common shared functions
static void ui_confirm_cancel_buttons(void) static void ui_confirm_cancel_buttons(void) {
{ display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4);
display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4); display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16,
display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL); toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE,
display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4); COLOR_BL_FAIL);
display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4);
display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16,
toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12,
COLOR_WHITE, COLOR_BL_DONE);
} }
static const char *format_ver(const char *format, uint32_t version) static const char *format_ver(const char *format, uint32_t version) {
{ static char ver_str[64];
static char ver_str[64]; mini_snprintf(ver_str, sizeof(ver_str), format, (int)(version & 0xFF),
mini_snprintf(ver_str, sizeof(ver_str), format, (int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF)
(int)(version & 0xFF), // ignore build field (int)((version >> 24) & 0xFF)
(int)((version >> 8) & 0xFF), );
(int)((version >> 16) & 0xFF) return ver_str;
// ignore build field (int)((version >> 24) & 0xFF)
);
return ver_str;
} }
// boot UI // boot UI
static uint16_t boot_background; static uint16_t boot_background;
void ui_screen_boot(const vendor_header * const vhdr, const image_header * const hdr) void ui_screen_boot(const vendor_header *const vhdr,
{ const image_header *const hdr) {
const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0); const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
if ((vhdr->vtrust & VTRUST_RED) == 0) { if ((vhdr->vtrust & VTRUST_RED) == 0) {
boot_background = COLOR_BL_FAIL; boot_background = COLOR_BL_FAIL;
} else { } else {
boot_background = COLOR_BLACK; boot_background = COLOR_BLACK;
} }
const uint8_t *vimg = vhdr->vimg; const uint8_t *vimg = vhdr->vimg;
const uint32_t fw_version = hdr->version; const uint32_t fw_version = hdr->version;
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, boot_background); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, boot_background);
int image_top = show_string ? 30 : (DISPLAY_RESY - 120) / 2; int image_top = show_string ? 30 : (DISPLAY_RESY - 120) / 2;
// check whether vendor image is 120x120 // check whether vendor image is 120x120
if (memcmp(vimg, "TOIf\x78\x00\x78\x00", 4) == 0) { if (memcmp(vimg, "TOIf\x78\x00\x78\x00", 4) == 0) {
uint32_t datalen = *(uint32_t *)(vimg + 8); uint32_t datalen = *(uint32_t *)(vimg + 8);
display_image((DISPLAY_RESX - 120) / 2, image_top, 120, 120, vimg + 12, datalen); display_image((DISPLAY_RESX - 120) / 2, image_top, 120, 120, vimg + 12,
} datalen);
}
if (show_string) {
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 50, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_WHITE, boot_background); if (show_string) {
const char *ver_str = format_ver("%d.%d.%d", fw_version); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 50, vhdr->vstr,
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 25, ver_str, -1, FONT_NORMAL, COLOR_WHITE, boot_background); vhdr->vstr_len, FONT_NORMAL, COLOR_WHITE,
} boot_background);
const char *ver_str = format_ver("%d.%d.%d", fw_version);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 25, ver_str, -1,
FONT_NORMAL, COLOR_WHITE, boot_background);
}
} }
void ui_screen_boot_wait(int wait_seconds) void ui_screen_boot_wait(int wait_seconds) {
{ char wait_str[16];
char wait_str[16]; mini_snprintf(wait_str, sizeof(wait_str), "starting in %d s", wait_seconds);
mini_snprintf(wait_str, sizeof(wait_str), "starting in %d s", wait_seconds); display_bar(0, DISPLAY_RESY - 5 - 20, DISPLAY_RESX, 5 + 20, boot_background);
display_bar(0, DISPLAY_RESY - 5 - 20, DISPLAY_RESX, 5 + 20, boot_background); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5, wait_str, -1,
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5, wait_str, -1, FONT_NORMAL, COLOR_WHITE, boot_background); FONT_NORMAL, COLOR_WHITE, boot_background);
} }
void ui_screen_boot_click(void) { void ui_screen_boot_click(void) {
display_bar(0, DISPLAY_RESY - 5 - 20, DISPLAY_RESX, 5 + 20, boot_background); display_bar(0, DISPLAY_RESY - 5 - 20, DISPLAY_RESX, 5 + 20, boot_background);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5, "click to continue ...", -1, FONT_NORMAL, COLOR_WHITE, boot_background); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5,
"click to continue ...", -1, FONT_NORMAL, COLOR_WHITE,
boot_background);
} }
// welcome UI // welcome UI
void ui_screen_first(void) void ui_screen_first(void) {
{ display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12,
display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12, COLOR_BLACK, COLOR_WHITE); COLOR_BLACK, COLOR_WHITE);
} }
void ui_screen_second(void) void ui_screen_second(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_icon((DISPLAY_RESX - 200) / 2, (DISPLAY_RESY - 60) / 2, 200, 60,
display_icon((DISPLAY_RESX - 200) / 2, (DISPLAY_RESY - 60) / 2, 200, 60, toi_icon_safeplace + 12, sizeof(toi_icon_safeplace) - 12, COLOR_BLACK, COLOR_WHITE); toi_icon_safeplace + 12, sizeof(toi_icon_safeplace) - 12,
COLOR_BLACK, COLOR_WHITE);
} }
void ui_screen_third(void) void ui_screen_third(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_icon((DISPLAY_RESX - 180) / 2, (DISPLAY_RESY - 30) / 2 - 5, 180, 30,
display_icon((DISPLAY_RESX - 180) / 2, (DISPLAY_RESY - 30) / 2 - 5, 180, 30, toi_icon_welcome + 12, sizeof(toi_icon_welcome) - 12, COLOR_BLACK, COLOR_WHITE); toi_icon_welcome + 12, sizeof(toi_icon_welcome) - 12,
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_BLACK, COLOR_WHITE);
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL,
COLOR_BLACK, COLOR_WHITE);
} }
// info UI // info UI
void ui_screen_info(secbool buttons, const vendor_header * const vhdr, const image_header * const hdr) void ui_screen_info(secbool buttons, const vendor_header *const vhdr,
{ const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
const char *ver_str = format_ver("Bootloader %d.%d.%d", VERSION_UINT32); const char *ver_str = format_ver("Bootloader %d.%d.%d", VERSION_UINT32);
display_text(16, 32, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text(16, 32, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BL_GRAY, COLOR_WHITE); display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
if (vhdr && hdr) { COLOR_BL_GRAY, COLOR_WHITE);
ver_str = format_ver("Firmware %d.%d.%d", (hdr->version)); if (vhdr && hdr) {
display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE); ver_str = format_ver("Firmware %d.%d.%d", (hdr->version));
display_text(55, 95, "by", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE); display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
display_text(55, 120, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE); display_text(55, 95, "by", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
} else { display_text(55, 120, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL,
display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE); COLOR_BL_GRAY, COLOR_WHITE);
} } else {
display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY,
if (sectrue == buttons) { COLOR_WHITE);
display_text_center(120, 170, "Connect to host?", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); }
ui_confirm_cancel_buttons();
} else { if (sectrue == buttons) {
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text_center(120, 170, "Connect to host?", -1, FONT_NORMAL,
} COLOR_BLACK, COLOR_WHITE);
ui_confirm_cancel_buttons();
} else {
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL,
COLOR_BLACK, COLOR_WHITE);
}
} }
void ui_screen_info_fingerprint(const image_header * const hdr) void ui_screen_info_fingerprint(const image_header *const hdr) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BLACK,
display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_WHITE);
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
static const char *hexdigits = "0123456789abcdef"; static const char *hexdigits = "0123456789abcdef";
char fingerprint_str[64]; char fingerprint_str[64];
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
fingerprint_str[i * 2 ] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF]; fingerprint_str[i * 2] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF];
fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF]; fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF];
} }
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
display_text_center(120, 70 + i * 25, fingerprint_str + i * 16, 16, FONT_MONO, COLOR_BLACK, COLOR_WHITE); display_text_center(120, 70 + i * 25, fingerprint_str + i * 16, 16,
} FONT_MONO, COLOR_BLACK, COLOR_WHITE);
}
display_bar_radius(9, 184, 222, 50, COLOR_BL_DONE, COLOR_WHITE, 4);
display_icon(9 + (222 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); display_bar_radius(9, 184, 222, 50, COLOR_BL_DONE, COLOR_WHITE, 4);
display_icon(9 + (222 - 19) / 2, 184 + (50 - 16) / 2, 20, 16,
toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12,
COLOR_WHITE, COLOR_BL_DONE);
} }
// install UI // install UI
void ui_screen_install_confirm_upgrade(const vendor_header * const vhdr, const image_header * const hdr) void ui_screen_install_confirm_upgrade(const vendor_header *const vhdr,
{ const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BLACK,
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); COLOR_WHITE);
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BLACK, COLOR_WHITE); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
display_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_BLACK, COLOR_WHITE);
const char *ver_str = format_ver("to version %d.%d.%d?", hdr->version); display_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BLACK,
display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_WHITE);
ui_confirm_cancel_buttons(); display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
const char *ver_str = format_ver("to version %d.%d.%d?", hdr->version);
display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
ui_confirm_cancel_buttons();
} }
void ui_screen_install_confirm_newvendor(const vendor_header * const vhdr, const image_header * const hdr) void ui_screen_install_confirm_newvendor(const vendor_header *const vhdr,
{ const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Vendor change", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text(16, 32, "Vendor change", -1, FONT_NORMAL, COLOR_BLACK,
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); COLOR_WHITE);
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BLACK, COLOR_WHITE); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
display_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_BLACK, COLOR_WHITE);
const char *ver_str = format_ver("(version %d.%d.%d)?", hdr->version); display_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BLACK,
display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_WHITE);
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, COLOR_BL_FAIL, COLOR_WHITE); display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK,
ui_confirm_cancel_buttons(); COLOR_WHITE);
const char *ver_str = format_ver("(version %d.%d.%d)?", hdr->version);
display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL,
COLOR_BL_FAIL, COLOR_WHITE);
ui_confirm_cancel_buttons();
} }
void ui_screen_install(void) void ui_screen_install(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install,
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK); sizeof(toi_icon_install), COLOR_BLACK);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Installing firmware", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24,
"Installing firmware", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
} }
void ui_screen_install_progress_erase(int pos, int len) void ui_screen_install_progress_erase(int pos, int len) {
{ display_loader(250 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE,
display_loader(250 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK); toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK);
} }
void ui_screen_install_progress_upload(int pos) void ui_screen_install_progress_upload(int pos) {
{ display_loader(pos, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install,
display_loader(pos, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK); sizeof(toi_icon_install), COLOR_BLACK);
} }
// wipe UI // wipe UI
void ui_screen_wipe_confirm(void) void ui_screen_wipe_confirm(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BLACK,
display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_WHITE);
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BLACK, COLOR_WHITE); display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
display_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); COLOR_BLACK, COLOR_WHITE);
display_text(55, 95, "wipe the device?", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, COLOR_BL_FAIL, COLOR_WHITE); display_text(55, 95, "wipe the device?", -1, FONT_NORMAL, COLOR_BLACK,
ui_confirm_cancel_buttons(); COLOR_WHITE);
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL,
COLOR_BL_FAIL, COLOR_WHITE);
ui_confirm_cancel_buttons();
} }
void ui_screen_wipe(void) void ui_screen_wipe(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe,
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK); sizeof(toi_icon_wipe), COLOR_BLACK);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Wiping device", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Wiping device", -1,
FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
} }
void ui_screen_wipe_progress(int pos, int len) void ui_screen_wipe_progress(int pos, int len) {
{ display_loader(1000 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE,
display_loader(1000 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK); toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK);
} }
// done UI // done UI
void ui_screen_done(int restart_seconds, secbool full_redraw) void ui_screen_done(int restart_seconds, secbool full_redraw) {
{ const char *str;
const char *str; char count_str[24];
char count_str[24]; if (restart_seconds >= 1) {
if (restart_seconds >= 1) { mini_snprintf(count_str, sizeof(count_str), "Done! Restarting in %d s",
mini_snprintf(count_str, sizeof(count_str), "Done! Restarting in %d s", restart_seconds); restart_seconds);
str = count_str; str = count_str;
} else { } else {
str = "Done! Unplug the device."; str = "Done! Unplug the device.";
} }
if (sectrue == full_redraw) { if (sectrue == full_redraw) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
} }
display_loader(1000, -20, COLOR_BL_DONE, COLOR_WHITE, toi_icon_done, sizeof(toi_icon_done), COLOR_BLACK); display_loader(1000, -20, COLOR_BL_DONE, COLOR_WHITE, toi_icon_done,
if (secfalse == full_redraw) { sizeof(toi_icon_done), COLOR_BLACK);
display_bar(0, DISPLAY_RESY - 24 - 18, 240, 23, COLOR_WHITE); if (secfalse == full_redraw) {
} display_bar(0, DISPLAY_RESY - 24 - 18, 240, 23, COLOR_WHITE);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); }
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, str, -1, FONT_NORMAL,
COLOR_BLACK, COLOR_WHITE);
} }
// error UI // error UI
void ui_screen_fail(void) void ui_screen_fail(void) {
{ display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_loader(1000, -20, COLOR_BL_FAIL, COLOR_WHITE, toi_icon_fail,
display_loader(1000, -20, COLOR_BL_FAIL, COLOR_WHITE, toi_icon_fail, sizeof(toi_icon_fail), COLOR_BLACK); sizeof(toi_icon_fail), COLOR_BLACK);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Failed! Please, reconnect.", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24,
"Failed! Please, reconnect.", -1, FONT_NORMAL,
COLOR_BLACK, COLOR_WHITE);
} }
// general functions // general functions
void ui_fadein(void) void ui_fadein(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); }
{
display_fade(0, BACKLIGHT_NORMAL, 1000);
}
void ui_fadeout(void) void ui_fadeout(void) {
{ display_fade(BACKLIGHT_NORMAL, 0, 500);
display_fade(BACKLIGHT_NORMAL, 0, 500); display_clear();
display_clear();
} }
int ui_user_input(int zones) int ui_user_input(int zones) {
{ for (;;) {
for (;;) { uint32_t evt = touch_click();
uint32_t evt = touch_click(); uint16_t x = touch_unpack_x(evt);
uint16_t x = touch_unpack_x(evt); uint16_t y = touch_unpack_y(evt);
uint16_t y = touch_unpack_y(evt); // clicked on Cancel button
// clicked on Cancel button if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 &&
if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 && y < 184 + 50) { y < 184 + 50) {
return INPUT_CANCEL; return INPUT_CANCEL;
} }
// clicked on Confirm button // clicked on Confirm button
if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 && y < 184 + 50) { if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 &&
return INPUT_CONFIRM; y < 184 + 50) {
} return INPUT_CONFIRM;
// clicked on Long Confirm button }
if ((zones & INPUT_LONG_CONFIRM) && x >= 9 && x < 9 + 222 && y > 184 && y < 184 + 50) { // clicked on Long Confirm button
return INPUT_LONG_CONFIRM; if ((zones & INPUT_LONG_CONFIRM) && x >= 9 && x < 9 + 222 && y > 184 &&
} y < 184 + 50) {
// clicked on Info icon return INPUT_LONG_CONFIRM;
if ((zones & INPUT_INFO) && x >= 16 && x < 16 + 32 && y > 54 && y < 54 + 32) { }
return INPUT_INFO; // clicked on Info icon
} if ((zones & INPUT_INFO) && x >= 16 && x < 16 + 32 && y > 54 &&
y < 54 + 32) {
return INPUT_INFO;
} }
}
} }

@ -20,10 +20,11 @@
#ifndef __BOOTUI_H__ #ifndef __BOOTUI_H__
#define __BOOTUI_H__ #define __BOOTUI_H__
#include "secbool.h"
#include "image.h" #include "image.h"
#include "secbool.h"
void ui_screen_boot(const vendor_header * const vhdr, const image_header * const hdr); void ui_screen_boot(const vendor_header* const vhdr,
const image_header* const hdr);
void ui_screen_boot_wait(int wait_seconds); void ui_screen_boot_wait(int wait_seconds);
void ui_screen_boot_click(void); void ui_screen_boot_click(void);
@ -31,11 +32,14 @@ void ui_screen_first(void);
void ui_screen_second(void); void ui_screen_second(void);
void ui_screen_third(void); void ui_screen_third(void);
void ui_screen_info(secbool buttons, const vendor_header * const vhdr, const image_header * const hdr); void ui_screen_info(secbool buttons, const vendor_header* const vhdr,
void ui_screen_info_fingerprint(const image_header * const hdr); const image_header* const hdr);
void ui_screen_info_fingerprint(const image_header* const hdr);
void ui_screen_install_confirm_upgrade(const vendor_header * const vhdr, const image_header * const hdr); void ui_screen_install_confirm_upgrade(const vendor_header* const vhdr,
void ui_screen_install_confirm_newvendor(const vendor_header * const vhdr, const image_header * const hdr); const image_header* const hdr);
void ui_screen_install_confirm_newvendor(const vendor_header* const vhdr,
const image_header* const hdr);
void ui_screen_install(void); void ui_screen_install(void);
void ui_screen_install_progress_erase(int pos, int len); void ui_screen_install_progress_erase(int pos, int len);
void ui_screen_install_progress_upload(int pos); void ui_screen_install_progress_upload(int pos);
@ -51,10 +55,10 @@ void ui_screen_fail(void);
void ui_fadein(void); void ui_fadein(void);
void ui_fadeout(void); void ui_fadeout(void);
#define INPUT_CANCEL 0x01 // Cancel button #define INPUT_CANCEL 0x01 // Cancel button
#define INPUT_CONFIRM 0x02 // Confirm button #define INPUT_CONFIRM 0x02 // Confirm button
#define INPUT_LONG_CONFIRM 0x04 // Long Confirm button #define INPUT_LONG_CONFIRM 0x04 // Long Confirm button
#define INPUT_INFO 0x08 // Info icon #define INPUT_INFO 0x08 // Info icon
int ui_user_input(int zones); int ui_user_input(int zones);
#endif #endif

@ -21,11 +21,11 @@
#include <sys/types.h> #include <sys/types.h>
#include "common.h" #include "common.h"
#include "mpu.h"
#include "image.h"
#include "flash.h"
#include "display.h" #include "display.h"
#include "flash.h"
#include "image.h"
#include "mini_printf.h" #include "mini_printf.h"
#include "mpu.h"
#include "rng.h" #include "rng.h"
#include "secbool.h" #include "secbool.h"
#include "touch.h" #include "touch.h"
@ -48,342 +48,355 @@ static const uint8_t * const BOOTLOADER_KEYS[] = {
// (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48", // (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48",
}; };
#define USB_IFACE_NUM 0 #define USB_IFACE_NUM 0
static void usb_init_all(void) { static void usb_init_all(void) {
static const usb_dev_info_t dev_info = {
static const usb_dev_info_t dev_info = { .device_class = 0x00,
.device_class = 0x00, .device_subclass = 0x00,
.device_subclass = 0x00, .device_protocol = 0x00,
.device_protocol = 0x00, .vendor_id = 0x1209,
.vendor_id = 0x1209, .product_id = 0x53C0,
.product_id = 0x53C0, .release_num = 0x0200,
.release_num = 0x0200, .manufacturer = "SatoshiLabs",
.manufacturer = "SatoshiLabs", .product = "TREZOR",
.product = "TREZOR", .serial_number = "000000000000000000000000",
.serial_number = "000000000000000000000000", .interface = "TREZOR Interface",
.interface = "TREZOR Interface", .usb21_enabled = sectrue,
.usb21_enabled = sectrue, .usb21_landing = sectrue,
.usb21_landing = sectrue, };
};
static uint8_t rx_buffer[USB_PACKET_SIZE];
static uint8_t rx_buffer[USB_PACKET_SIZE];
static const usb_webusb_info_t webusb_info = {
static const usb_webusb_info_t webusb_info = { .iface_num = USB_IFACE_NUM,
.iface_num = USB_IFACE_NUM, .ep_in = USB_EP_DIR_IN | 0x01,
.ep_in = USB_EP_DIR_IN | 0x01, .ep_out = USB_EP_DIR_OUT | 0x01,
.ep_out = USB_EP_DIR_OUT | 0x01, .subclass = 0,
.subclass = 0, .protocol = 0,
.protocol = 0, .max_packet_len = sizeof(rx_buffer),
.max_packet_len = sizeof(rx_buffer), .rx_buffer = rx_buffer,
.rx_buffer = rx_buffer, .polling_interval = 1,
.polling_interval = 1, };
};
usb_init(&dev_info);
usb_init(&dev_info);
ensure(usb_webusb_add(&webusb_info), NULL);
ensure(usb_webusb_add(&webusb_info), NULL);
usb_start();
usb_start();
} }
static secbool bootloader_usb_loop(const vendor_header * const vhdr, const image_header * const hdr) static secbool bootloader_usb_loop(const vendor_header *const vhdr,
{ const image_header *const hdr) {
usb_init_all(); usb_init_all();
uint8_t buf[USB_PACKET_SIZE]; uint8_t buf[USB_PACKET_SIZE];
for (;;) { for (;;) {
int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE, USB_TIMEOUT); int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE,
if (r != USB_PACKET_SIZE) { USB_TIMEOUT);
continue; if (r != USB_PACKET_SIZE) {
continue;
}
uint16_t msg_id;
uint32_t msg_size;
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
// invalid header -> discard
continue;
}
switch (msg_id) {
case 0: // Initialize
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
break;
case 1: // Ping
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
break;
case 5: // WipeDevice
ui_fadeout();
ui_screen_wipe_confirm();
ui_fadein();
int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL);
if (INPUT_CANCEL == response) {
ui_fadeout();
ui_screen_info(secfalse, vhdr, hdr);
ui_fadein();
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
break;
} }
uint16_t msg_id; ui_fadeout();
uint32_t msg_size; ui_screen_wipe();
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) { ui_fadein();
// invalid header -> discard r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
continue; if (r < 0) { // error
ui_fadeout();
ui_screen_fail();
ui_fadein();
usb_stop();
usb_deinit();
return secfalse; // shutdown
} else { // success
ui_fadeout();
ui_screen_done(0, sectrue);
ui_fadein();
usb_stop();
usb_deinit();
return secfalse; // shutdown
} }
switch (msg_id) { break;
case 0: // Initialize case 6: // FirmwareErase
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr); process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf);
break; break;
case 1: // Ping case 7: // FirmwareUpload
process_msg_Ping(USB_IFACE_NUM, msg_size, buf); r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
break; if (r < 0 && r != -4) { // error, but not user abort (-4)
case 5: // WipeDevice ui_fadeout();
ui_fadeout(); ui_screen_fail();
ui_screen_wipe_confirm(); ui_fadein();
ui_fadein(); usb_stop();
int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); usb_deinit();
if (INPUT_CANCEL == response) { return secfalse; // shutdown
ui_fadeout(); } else if (r == 0) { // last chunk received
ui_screen_info(secfalse, vhdr, hdr); ui_screen_install_progress_upload(1000);
ui_fadein(); ui_fadeout();
send_user_abort(USB_IFACE_NUM, "Wipe cancelled"); ui_screen_done(4, sectrue);
break; ui_fadein();
} ui_screen_done(3, secfalse);
ui_fadeout(); hal_delay(1000);
ui_screen_wipe(); ui_screen_done(2, secfalse);
ui_fadein(); hal_delay(1000);
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf); ui_screen_done(1, secfalse);
if (r < 0) { // error hal_delay(1000);
ui_fadeout(); usb_stop();
ui_screen_fail(); usb_deinit();
ui_fadein(); ui_fadeout();
usb_stop(); return sectrue; // jump to firmware
usb_deinit();
return secfalse; // shutdown
} else { // success
ui_fadeout();
ui_screen_done(0, sectrue);
ui_fadein();
usb_stop();
usb_deinit();
return secfalse; // shutdown
}
break;
case 6: // FirmwareErase
process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf);
break;
case 7: // FirmwareUpload
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
if (r < 0 && r != -4) { // error, but not user abort (-4)
ui_fadeout();
ui_screen_fail();
ui_fadein();
usb_stop();
usb_deinit();
return secfalse; // shutdown
} else
if (r == 0) { // last chunk received
ui_screen_install_progress_upload(1000);
ui_fadeout();
ui_screen_done(4, sectrue);
ui_fadein();
ui_screen_done(3, secfalse);
hal_delay(1000);
ui_screen_done(2, secfalse);
hal_delay(1000);
ui_screen_done(1, secfalse);
hal_delay(1000);
usb_stop();
usb_deinit();
ui_fadeout();
return sectrue; // jump to firmware
}
break;
case 55: // GetFeatures
process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(USB_IFACE_NUM, msg_size, buf);
break;
} }
break;
case 55: // GetFeatures
process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
break;
default:
process_msg_unknown(USB_IFACE_NUM, msg_size, buf);
break;
} }
}
} }
secbool load_vendor_header_keys(const uint8_t * const data, vendor_header * const vhdr) secbool load_vendor_header_keys(const uint8_t *const data,
{ vendor_header *const vhdr) {
return load_vendor_header(data, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N, BOOTLOADER_KEYS, vhdr); return load_vendor_header(data, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
BOOTLOADER_KEYS, vhdr);
} }
static secbool check_vendor_keys_lock(const vendor_header * const vhdr) { static secbool check_vendor_keys_lock(const vendor_header *const vhdr) {
uint8_t lock[FLASH_OTP_BLOCK_SIZE]; uint8_t lock[FLASH_OTP_BLOCK_SIZE];
ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK, 0, lock, FLASH_OTP_BLOCK_SIZE), NULL); ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK, 0, lock,
if (0 == memcmp(lock, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", FLASH_OTP_BLOCK_SIZE)) { FLASH_OTP_BLOCK_SIZE),
return sectrue; NULL);
} if (0 ==
uint8_t hash[32]; memcmp(lock,
vendor_keys_hash(vhdr, hash); "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
return sectrue * (0 == memcmp(lock, hash, 32)); "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
FLASH_OTP_BLOCK_SIZE)) {
return sectrue;
}
uint8_t hash[32];
vendor_keys_hash(vhdr, hash);
return sectrue * (0 == memcmp(lock, hash, 32));
} }
// protection against bootloader downgrade // protection against bootloader downgrade
#if PRODUCTION #if PRODUCTION
static void check_bootloader_version(void) static void check_bootloader_version(void) {
{ uint8_t bits[FLASH_OTP_BLOCK_SIZE];
uint8_t bits[FLASH_OTP_BLOCK_SIZE]; for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) { if (i < VERSION_MONOTONIC) {
if (i < VERSION_MONOTONIC) { bits[i / 8] &= ~(1 << (7 - (i % 8)));
bits[i / 8] &= ~(1 << (7 - (i % 8))); } else {
} else { bits[i / 8] |= (1 << (7 - (i % 8)));
bits[i / 8] |= (1 << (7 - (i % 8)));
}
} }
ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL); }
ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits,
uint8_t bits2[FLASH_OTP_BLOCK_SIZE]; FLASH_OTP_BLOCK_SIZE),
ensure(flash_otp_read(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits2, FLASH_OTP_BLOCK_SIZE), NULL); NULL);
ensure(sectrue * (0 == memcmp(bits, bits2, FLASH_OTP_BLOCK_SIZE)), "Bootloader downgraded"); uint8_t bits2[FLASH_OTP_BLOCK_SIZE];
ensure(flash_otp_read(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits2,
FLASH_OTP_BLOCK_SIZE),
NULL);
ensure(sectrue * (0 == memcmp(bits, bits2, FLASH_OTP_BLOCK_SIZE)),
"Bootloader downgraded");
} }
#endif #endif
int main(void) int main(void) {
{ touch_init();
touch_init(); touch_power_on();
touch_power_on();
mpu_config_bootloader(); mpu_config_bootloader();
#if PRODUCTION #if PRODUCTION
check_bootloader_version(); check_bootloader_version();
#endif #endif
main_start: main_start:
display_clear(); display_clear();
// delay to detect touch // delay to detect touch
uint32_t touched = 0; uint32_t touched = 0;
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
touched = touch_is_detected() | touch_read(); touched = touch_is_detected() | touch_read();
if (touched) { if (touched) {
break; break;
}
hal_delay(1);
}
vendor_header vhdr;
image_header hdr;
secbool firmware_present;
// detect whether the devices contains a valid firmware
firmware_present = load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr);
if (sectrue == firmware_present) {
firmware_present = check_vendor_keys_lock(&vhdr);
}
if (sectrue == firmware_present) {
firmware_present = load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr);
} }
if (sectrue == firmware_present) { hal_delay(1);
firmware_present = check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT); }
vendor_header vhdr;
image_header hdr;
secbool firmware_present;
// detect whether the devices contains a valid firmware
firmware_present =
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr);
if (sectrue == firmware_present) {
firmware_present = check_vendor_keys_lock(&vhdr);
}
if (sectrue == firmware_present) {
firmware_present = load_image_header(
(const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC,
FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr);
}
if (sectrue == firmware_present) {
firmware_present =
check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT);
}
// start the bootloader if no or broken firmware found ...
if (firmware_present != sectrue) {
// show intro animation
// no ui_fadeout(); - we already start from black screen
ui_screen_first();
ui_fadein();
hal_delay(1000);
ui_fadeout();
ui_screen_second();
ui_fadein();
hal_delay(1000);
ui_fadeout();
ui_screen_third();
ui_fadein();
// erase storage
ensure(flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL),
NULL);
// and start the usb loop
if (bootloader_usb_loop(NULL, NULL) != sectrue) {
return 1;
} }
} else
// ... or if user touched the screen on start
if (touched) {
// show firmware info with connect buttons
// start the bootloader if no or broken firmware found ... // no ui_fadeout(); - we already start from black screen
if (firmware_present != sectrue) { ui_screen_info(sectrue, &vhdr, &hdr);
// show intro animation ui_fadein();
// no ui_fadeout(); - we already start from black screen
ui_screen_first();
ui_fadein();
hal_delay(1000);
ui_fadeout(); for (;;) {
ui_screen_second(); int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL | INPUT_INFO);
ui_fadeout();
// if cancel was pressed -> restart
if (INPUT_CANCEL == response) {
goto main_start;
}
// if confirm was pressed -> jump out
if (INPUT_CONFIRM == response) {
// show firmware info without connect buttons
ui_screen_info(secfalse, &vhdr, &hdr);
ui_fadein(); ui_fadein();
break;
}
hal_delay(1000); // if info icon was pressed -> show fingerprint
if (INPUT_INFO == response) {
ui_fadeout(); // show fingerprint
ui_screen_third(); ui_screen_info_fingerprint(&hdr);
ui_fadein(); ui_fadein();
while (INPUT_LONG_CONFIRM != ui_user_input(INPUT_LONG_CONFIRM)) {
// erase storage
ensure(flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL), NULL);
// and start the usb loop
if (bootloader_usb_loop(NULL, NULL) != sectrue) {
return 1;
} }
} else ui_fadeout();
// ... or if user touched the screen on start
if (touched) {
// show firmware info with connect buttons
// no ui_fadeout(); - we already start from black screen
ui_screen_info(sectrue, &vhdr, &hdr); ui_screen_info(sectrue, &vhdr, &hdr);
ui_fadein(); ui_fadein();
}
for (;;) {
int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL | INPUT_INFO);
ui_fadeout();
// if cancel was pressed -> restart
if (INPUT_CANCEL == response) {
goto main_start;
}
// if confirm was pressed -> jump out
if (INPUT_CONFIRM == response) {
// show firmware info without connect buttons
ui_screen_info(secfalse, &vhdr, &hdr);
ui_fadein();
break;
}
// if info icon was pressed -> show fingerprint
if (INPUT_INFO == response) {
// show fingerprint
ui_screen_info_fingerprint(&hdr);
ui_fadein();
while (INPUT_LONG_CONFIRM != ui_user_input(INPUT_LONG_CONFIRM)) { }
ui_fadeout();
ui_screen_info(sectrue, &vhdr, &hdr);
ui_fadein();
}
}
// and start the usb loop
if (bootloader_usb_loop(&vhdr, &hdr) != sectrue) {
return 1;
}
} }
ensure( // and start the usb loop
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr), if (bootloader_usb_loop(&vhdr, &hdr) != sectrue) {
"invalid vendor header"); return 1;
}
}
ensure( ensure(load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
check_vendor_keys_lock(&vhdr), "invalid vendor header");
"unauthorized vendor keys");
ensure( ensure(check_vendor_keys_lock(&vhdr), "unauthorized vendor keys");
load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr),
"invalid firmware header");
ensure( ensure(load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT), FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
"invalid firmware hash"); vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr),
"invalid firmware header");
// if all VTRUST flags are unset = ultimate trust => skip the procedure ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT),
"invalid firmware hash");
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) { // if all VTRUST flags are unset = ultimate trust => skip the procedure
// ui_fadeout(); // no fadeout - we start from black screen if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
ui_screen_boot(&vhdr, &hdr); // ui_fadeout(); // no fadeout - we start from black screen
ui_fadein(); ui_screen_boot(&vhdr, &hdr);
ui_fadein();
int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT; int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT;
if (delay > 1) { if (delay > 1) {
while (delay > 0) { while (delay > 0) {
ui_screen_boot_wait(delay); ui_screen_boot_wait(delay);
hal_delay(1000); hal_delay(1000);
delay--; delay--;
} }
} else if (delay == 1) { } else if (delay == 1) {
hal_delay(1000); hal_delay(1000);
} }
if ((vhdr.vtrust & VTRUST_CLICK) == 0) {
ui_screen_boot_click();
touch_click();
}
ui_fadeout(); if ((vhdr.vtrust & VTRUST_CLICK) == 0) {
ui_screen_boot_click();
touch_click();
} }
// mpu_config_firmware(); ui_fadeout();
// jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); }
// mpu_config_firmware();
// jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE);
mpu_config_off(); mpu_config_off();
jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

@ -24,20 +24,27 @@
#include "image.h" #include "image.h"
#include "secbool.h" #include "secbool.h"
#define USB_TIMEOUT 500 #define USB_TIMEOUT 500
#define USB_PACKET_SIZE 64 #define USB_PACKET_SIZE 64
#define FIRMWARE_UPLOAD_CHUNK_RETRY_COUNT 2 #define FIRMWARE_UPLOAD_CHUNK_RETRY_COUNT 2
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id, uint32_t *msg_size); secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
uint32_t *msg_size);
void send_user_abort(uint8_t iface_num, const char *msg); void send_user_abort(uint8_t iface_num, const char *msg);
void process_msg_Initialize(uint8_t iface_num, uint32_t msg_size, uint8_t *buf, const vendor_header * const vhdr, const image_header * const hdr); void process_msg_Initialize(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
void process_msg_GetFeatures(uint8_t iface_num, uint32_t msg_size, uint8_t *buf, const vendor_header * const vhdr, const image_header * const hdr); const vendor_header *const vhdr,
const image_header *const hdr);
void process_msg_GetFeatures(uint8_t iface_num, uint32_t msg_size, uint8_t *buf,
const vendor_header *const vhdr,
const image_header *const hdr);
void process_msg_Ping(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); void process_msg_Ping(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
void process_msg_FirmwareErase(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); void process_msg_FirmwareErase(uint8_t iface_num, uint32_t msg_size,
int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); uint8_t *buf);
int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
uint8_t *buf);
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf); void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);

@ -1,12 +1,14 @@
#define VERSION_MAJOR 2 #define VERSION_MAJOR 2
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_PATCH 3 #define VERSION_PATCH 3
#define VERSION_BUILD 0 #define VERSION_BUILD 0
#define VERSION_UINT32 (VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | (VERSION_BUILD << 24)) #define VERSION_UINT32 \
(VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | \
(VERSION_BUILD << 24))
#define FIX_VERSION_MAJOR 2 #define FIX_VERSION_MAJOR 2
#define FIX_VERSION_MINOR 0 #define FIX_VERSION_MINOR 0
#define FIX_VERSION_PATCH 0 #define FIX_VERSION_PATCH 0
#define FIX_VERSION_BUILD 0 #define FIX_VERSION_BUILD 0
#define VERSION_MONOTONIC 1 #define VERSION_MONOTONIC 1

@ -19,31 +19,32 @@
#include <string.h> #include <string.h>
#include "py/runtime.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "py/objstr.h" #include "py/objstr.h"
#include "py/runtime.h"
#if MICROPY_PY_TREZORCONFIG #if MICROPY_PY_TREZORCONFIG
#include "embed/extmod/trezorobj.h" #include "embed/extmod/trezorobj.h"
#include "storage.h"
#include "common.h" #include "common.h"
#include "memzero.h" #include "memzero.h"
#include "storage.h"
STATIC mp_obj_t ui_wait_callback = mp_const_none; STATIC mp_obj_t ui_wait_callback = mp_const_none;
STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress, const char* message) { STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress,
if (mp_obj_is_callable(ui_wait_callback)) { const char *message) {
mp_obj_t args[3]; if (mp_obj_is_callable(ui_wait_callback)) {
args[0] = mp_obj_new_int(wait); mp_obj_t args[3];
args[1] = mp_obj_new_int(progress); args[0] = mp_obj_new_int(wait);
args[2] = mp_obj_new_str(message, strlen(message)); args[1] = mp_obj_new_int(progress);
if (mp_call_function_n_kw(ui_wait_callback, 3, 0, args) == mp_const_true) { args[2] = mp_obj_new_str(message, strlen(message));
return sectrue; if (mp_call_function_n_kw(ui_wait_callback, 3, 0, args) == mp_const_true) {
} return sectrue;
} }
return secfalse; }
return secfalse;
} }
/// def init(ui_wait_callback: (int, int -> None)=None) -> None: /// def init(ui_wait_callback: (int, int -> None)=None) -> None:
@ -52,29 +53,31 @@ STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress, const
/// called from this module! /// called from this module!
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) {
if (n_args > 0) { if (n_args > 0) {
ui_wait_callback = args[0]; ui_wait_callback = args[0];
storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
} else { } else {
storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
} }
memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1, mod_trezorconfig_init); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1,
mod_trezorconfig_init);
/// def check_pin(pin: int) -> bool: /// def check_pin(pin: int) -> bool:
/// ''' /// '''
/// Check the given PIN. Returns True on success, False on failure. /// Check the given PIN. Returns True on success, False on failure.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_check_pin(mp_obj_t pin) { STATIC mp_obj_t mod_trezorconfig_check_pin(mp_obj_t pin) {
uint32_t pin_i = trezor_obj_get_uint(pin); uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) { if (sectrue != storage_unlock(pin_i)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_check_pin_obj, mod_trezorconfig_check_pin); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_check_pin_obj,
mod_trezorconfig_check_pin);
/// def unlock(pin: int) -> bool: /// def unlock(pin: int) -> bool:
/// ''' /// '''
@ -82,205 +85,227 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_check_pin_obj, mod_trezorconfi
/// success, False on failure. /// success, False on failure.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin) { STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin) {
uint32_t pin_i = trezor_obj_get_uint(pin); uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) { if (sectrue != storage_unlock(pin_i)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_unlock_obj, mod_trezorconfig_unlock); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_unlock_obj,
mod_trezorconfig_unlock);
/// def lock() -> None: /// def lock() -> None:
/// ''' /// '''
/// Locks the storage. /// Locks the storage.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_lock(void) { STATIC mp_obj_t mod_trezorconfig_lock(void) {
storage_lock(); storage_lock();
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_lock_obj, mod_trezorconfig_lock); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_lock_obj,
mod_trezorconfig_lock);
/// def has_pin() -> bool: /// def has_pin() -> bool:
/// ''' /// '''
/// Returns True if storage has a configured PIN, False otherwise. /// Returns True if storage has a configured PIN, False otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_has_pin(void) { STATIC mp_obj_t mod_trezorconfig_has_pin(void) {
if (sectrue != storage_has_pin()) { if (sectrue != storage_has_pin()) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_has_pin_obj, mod_trezorconfig_has_pin); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_has_pin_obj,
mod_trezorconfig_has_pin);
/// def get_pin_rem() -> int: /// def get_pin_rem() -> int:
/// ''' /// '''
/// Returns the number of remaining PIN entry attempts. /// Returns the number of remaining PIN entry attempts.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_get_pin_rem(void) { STATIC mp_obj_t mod_trezorconfig_get_pin_rem(void) {
return mp_obj_new_int_from_uint(storage_get_pin_rem()); return mp_obj_new_int_from_uint(storage_get_pin_rem());
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_get_pin_rem_obj, mod_trezorconfig_get_pin_rem); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_get_pin_rem_obj,
mod_trezorconfig_get_pin_rem);
/// def change_pin(pin: int, newpin: int) -> bool: /// def change_pin(pin: int, newpin: int) -> bool:
/// ''' /// '''
/// Change PIN. Returns True on success, False on failure. /// Change PIN. Returns True on success, False on failure.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_change_pin(mp_obj_t pin, mp_obj_t newpin) { STATIC mp_obj_t mod_trezorconfig_change_pin(mp_obj_t pin, mp_obj_t newpin) {
uint32_t pin_i = trezor_obj_get_uint(pin); uint32_t pin_i = trezor_obj_get_uint(pin);
uint32_t newpin_i = trezor_obj_get_uint(newpin); uint32_t newpin_i = trezor_obj_get_uint(newpin);
if (sectrue != storage_change_pin(pin_i, newpin_i)) { if (sectrue != storage_change_pin(pin_i, newpin_i)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_change_pin_obj, mod_trezorconfig_change_pin); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_change_pin_obj,
mod_trezorconfig_change_pin);
/// def get(app: int, key: int, public: bool=False) -> bytes: /// def get(app: int, key: int, public: bool=False) -> bytes:
/// ''' /// '''
/// Gets the value of the given key for the given app (or None if not set). /// Gets the value of the given key for the given app (or None if not set).
/// Raises a RuntimeError if decryption or authentication of the stored value fails. /// Raises a RuntimeError if decryption or authentication of the stored
/// value fails.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_get(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_get(size_t n_args, const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]); uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) { if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80; app |= 0x80;
} }
uint16_t appkey = (app << 8) | key; uint16_t appkey = (app << 8) | key;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != storage_get(appkey, NULL, 0, &len)) { if (sectrue != storage_get(appkey, NULL, 0, &len)) {
return mp_const_none; return mp_const_none;
} }
if (len == 0) { if (len == 0) {
return mp_const_empty_bytes; return mp_const_empty_bytes;
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, len); vstr_init_len(&vstr, len);
if (sectrue != storage_get(appkey, vstr.buf, vstr.len, &len)) { if (sectrue != storage_get(appkey, vstr.buf, vstr.len, &len)) {
vstr_clear(&vstr); vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to get value from storage."); mp_raise_msg(&mp_type_RuntimeError, "Failed to get value from storage.");
} }
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_get_obj, 2, 3, mod_trezorconfig_get); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_get_obj, 2, 3,
mod_trezorconfig_get);
/// def set(app: int, key: int, value: bytes, public: bool=False) -> None: /// def set(app: int, key: int, value: bytes, public: bool=False) -> None:
/// ''' /// '''
/// Sets a value of given key for given app. /// Sets a value of given key for given app.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_set(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_set(size_t n_args, const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]); uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 3 && args[3] == mp_const_true) { if (n_args > 3 && args[3] == mp_const_true) {
app |= 0x80; app |= 0x80;
} }
uint16_t appkey = (app << 8) | key; uint16_t appkey = (app << 8) | key;
mp_buffer_info_t value; mp_buffer_info_t value;
mp_get_buffer_raise(args[2], &value, MP_BUFFER_READ); mp_get_buffer_raise(args[2], &value, MP_BUFFER_READ);
if (sectrue != storage_set(appkey, value.buf, value.len)) { if (sectrue != storage_set(appkey, value.buf, value.len)) {
mp_raise_msg(&mp_type_RuntimeError, "Could not save value"); mp_raise_msg(&mp_type_RuntimeError, "Could not save value");
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_obj, 3, 4, mod_trezorconfig_set); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_obj, 3, 4,
mod_trezorconfig_set);
/// def delete(app: int, key: int, public: bool=False) -> bool: /// def delete(app: int, key: int, public: bool=False) -> bool:
/// ''' /// '''
/// Deletes the given key of the given app. /// Deletes the given key of the given app.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]); uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) { if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80; app |= 0x80;
} }
uint16_t appkey = (app << 8) | key; uint16_t appkey = (app << 8) | key;
if (sectrue != storage_delete(appkey)) { if (sectrue != storage_delete(appkey)) {
return mp_const_false; return mp_const_false;
} }
return mp_const_true; return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 2, 3, mod_trezorconfig_delete); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 2, 3,
mod_trezorconfig_delete);
/// def set_counter(app: int, key: int, count: int, writable_locked: bool=False) -> bool: /// def set_counter(app: int, key: int, count: int, writable_locked: bool=False)
/// -> bool:
/// ''' /// '''
/// Sets the given key of the given app as a counter with the given value. /// Sets the given key of the given app as a counter with the given value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_set_counter(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_set_counter(size_t n_args,
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; const mp_obj_t *args) {
uint8_t key = trezor_obj_get_uint8(args[1]); uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
if (n_args > 3 && args[3] == mp_const_true) { uint8_t key = trezor_obj_get_uint8(args[1]);
app |= 0xC0; if (n_args > 3 && args[3] == mp_const_true) {
} else { app |= 0xC0;
app |= 0x80; } else {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
if (args[2] == mp_const_none) {
if (sectrue != storage_delete(appkey)) {
return mp_const_false;
} }
uint16_t appkey = (app << 8) | key; } else {
if (args[2] == mp_const_none) { uint32_t count = trezor_obj_get_uint(args[2]);
if (sectrue != storage_delete(appkey)) { if (sectrue != storage_set_counter(appkey, count)) {
return mp_const_false; return mp_const_false;
}
} else {
uint32_t count = trezor_obj_get_uint(args[2]);
if (sectrue != storage_set_counter(appkey, count)) {
return mp_const_false;
}
} }
return mp_const_true; }
return mp_const_true;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_counter_obj, 3, 4, mod_trezorconfig_set_counter); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_counter_obj, 3,
4, mod_trezorconfig_set_counter);
/// def next_counter(app: int, key: int, writable_locked: bool=False) -> bool: /// def next_counter(app: int, key: int, writable_locked: bool=False) -> bool:
/// ''' /// '''
/// Increments the counter stored under the given key of the given app and returns the new value. /// Increments the counter stored under the given key of the given app and
/// returns the new value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_next_counter(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorconfig_next_counter(size_t n_args,
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; const mp_obj_t *args) {
uint8_t key = trezor_obj_get_uint8(args[1]); uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
if (n_args > 2 && args[2] == mp_const_true) { uint8_t key = trezor_obj_get_uint8(args[1]);
app |= 0xC0; if (n_args > 2 && args[2] == mp_const_true) {
} else { app |= 0xC0;
app |= 0x80; } else {
} app |= 0x80;
uint16_t appkey = (app << 8) | key; }
uint32_t count = 0; uint16_t appkey = (app << 8) | key;
if (sectrue != storage_next_counter(appkey, &count)) { uint32_t count = 0;
return mp_const_none; if (sectrue != storage_next_counter(appkey, &count)) {
} return mp_const_none;
return mp_obj_new_int_from_uint(count); }
return mp_obj_new_int_from_uint(count);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_next_counter_obj, 2, 3, mod_trezorconfig_next_counter); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_next_counter_obj, 2,
3, mod_trezorconfig_next_counter);
/// def wipe() -> None: /// def wipe() -> None:
/// ''' /// '''
/// Erases the whole config. Use with caution! /// Erases the whole config. Use with caution!
/// ''' /// '''
STATIC mp_obj_t mod_trezorconfig_wipe(void) { STATIC mp_obj_t mod_trezorconfig_wipe(void) {
storage_wipe(); storage_wipe();
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_wipe_obj, mod_trezorconfig_wipe); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_wipe_obj,
mod_trezorconfig_wipe);
STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorconfig) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorconfig)},
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mod_trezorconfig_init_obj) }, {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mod_trezorconfig_init_obj)},
{ MP_ROM_QSTR(MP_QSTR_check_pin), MP_ROM_PTR(&mod_trezorconfig_check_pin_obj) }, {MP_ROM_QSTR(MP_QSTR_check_pin),
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj) }, MP_ROM_PTR(&mod_trezorconfig_check_pin_obj)},
{ MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorconfig_lock_obj) }, {MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj)},
{ MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj) }, {MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorconfig_lock_obj)},
{ MP_ROM_QSTR(MP_QSTR_get_pin_rem), MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj) }, {MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj)},
{ MP_ROM_QSTR(MP_QSTR_change_pin), MP_ROM_PTR(&mod_trezorconfig_change_pin_obj) }, {MP_ROM_QSTR(MP_QSTR_get_pin_rem),
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj) }, MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj)},
{ MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_obj) }, {MP_ROM_QSTR(MP_QSTR_change_pin),
{ MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mod_trezorconfig_delete_obj) }, MP_ROM_PTR(&mod_trezorconfig_change_pin_obj)},
{ MP_ROM_QSTR(MP_QSTR_set_counter), MP_ROM_PTR(&mod_trezorconfig_set_counter_obj) }, {MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj)},
{ MP_ROM_QSTR(MP_QSTR_next_counter), MP_ROM_PTR(&mod_trezorconfig_next_counter_obj) }, {MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_obj)},
{ MP_ROM_QSTR(MP_QSTR_wipe), MP_ROM_PTR(&mod_trezorconfig_wipe_obj) }, {MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mod_trezorconfig_delete_obj)},
{MP_ROM_QSTR(MP_QSTR_set_counter),
MP_ROM_PTR(&mod_trezorconfig_set_counter_obj)},
{MP_ROM_QSTR(MP_QSTR_next_counter),
MP_ROM_PTR(&mod_trezorconfig_next_counter_obj)},
{MP_ROM_QSTR(MP_QSTR_wipe), MP_ROM_PTR(&mod_trezorconfig_wipe_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorconfig_globals, mp_module_trezorconfig_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_trezorconfig_globals,
mp_module_trezorconfig_globals_table);
const mp_obj_module_t mp_module_trezorconfig = { const mp_obj_module_t mp_module_trezorconfig = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mp_module_trezorconfig_globals, .globals = (mp_obj_dict_t *)&mp_module_trezorconfig_globals,
}; };
#endif // MICROPY_PY_TREZORCONFIG #endif // MICROPY_PY_TREZORCONFIG

@ -22,18 +22,20 @@
#include "flash.h" #include "flash.h"
#define NORCOW_HEADER_LEN 0 #define NORCOW_HEADER_LEN 0
#define NORCOW_SECTOR_COUNT 2 #define NORCOW_SECTOR_COUNT 2
#if TREZOR_MODEL == T #if TREZOR_MODEL == T
#define NORCOW_SECTOR_SIZE (64*1024) #define NORCOW_SECTOR_SIZE (64 * 1024)
#define NORCOW_SECTORS {FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2} #define NORCOW_SECTORS \
{ FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2 }
#elif TREZOR_MODEL == 1 #elif TREZOR_MODEL == 1
#define NORCOW_SECTOR_SIZE (16*1024) #define NORCOW_SECTOR_SIZE (16 * 1024)
#define NORCOW_SECTORS {2, 3} #define NORCOW_SECTORS \
{ 2, 3 }
#else #else

@ -58,21 +58,18 @@
#include "crc.h" #include "crc.h"
static const uint32_t crc32tab[16] = { static const uint32_t crc32tab[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
0xbdbdf21c
};
/* crc is previous value for incremental computation, 0xffffffff initially */ /* crc is previous value for incremental computation, 0xffffffff initially */
uint32_t checksum_crc32(const uint8_t *data, uint32_t length, uint32_t crc) uint32_t checksum_crc32(const uint8_t *data, uint32_t length, uint32_t crc) {
{ for (uint32_t i = 0; i < length; ++i) {
for (uint32_t i = 0; i < length; ++i) { crc ^= data[i];
crc ^= data[i]; crc = crc32tab[crc & 0x0f] ^ (crc >> 4);
crc = crc32tab[crc & 0x0f] ^ (crc >> 4); crc = crc32tab[crc & 0x0f] ^ (crc >> 4);
crc = crc32tab[crc & 0x0f] ^ (crc >> 4); }
}
// return value suitable for passing in next time, for final value invert it // return value suitable for passing in next time, for final value invert it
return crc/* ^ 0xffffffff*/; return crc /* ^ 0xffffffff*/;
} }

@ -23,11 +23,11 @@
#include "memzero.h" #include "memzero.h"
enum AESMode { enum AESMode {
ECB = 0x00, ECB = 0x00,
CBC = 0x01, CBC = 0x01,
CFB = 0x02, CFB = 0x02,
OFB = 0x03, OFB = 0x03,
CTR = 0x04, CTR = 0x04,
}; };
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -37,102 +37,114 @@ enum AESMode {
/// AES context. /// AES context.
/// ''' /// '''
typedef struct _mp_obj_AES_t { typedef struct _mp_obj_AES_t {
mp_obj_base_t base; mp_obj_base_t base;
aes_encrypt_ctx encrypt_ctx; aes_encrypt_ctx encrypt_ctx;
aes_decrypt_ctx decrypt_ctx; aes_decrypt_ctx decrypt_ctx;
mp_int_t mode; mp_int_t mode;
uint8_t iv[AES_BLOCK_SIZE]; uint8_t iv[AES_BLOCK_SIZE];
} mp_obj_AES_t; } mp_obj_AES_t;
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None: /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None:
/// ''' /// '''
/// Initialize AES context. /// Initialize AES context.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_AES_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_AES_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 2, 3, false); size_t n_args, size_t n_kw,
mp_obj_AES_t *o = m_new_obj(mp_obj_AES_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 2, 3, false);
o->mode = mp_obj_get_int(args[0]); mp_obj_AES_t *o = m_new_obj(mp_obj_AES_t);
if (o->mode < ECB || o->mode > CTR) { o->base.type = type;
mp_raise_ValueError("Invalid AES mode"); o->mode = mp_obj_get_int(args[0]);
if (o->mode < ECB || o->mode > CTR) {
mp_raise_ValueError("Invalid AES mode");
}
mp_buffer_info_t key;
mp_get_buffer_raise(args[1], &key, MP_BUFFER_READ);
if (key.len != 16 && key.len != 24 && key.len != 32) {
mp_raise_ValueError(
"Invalid length of key (has to be 128, 192 or 256 bits)");
}
if (n_args > 2) {
mp_buffer_info_t iv;
mp_get_buffer_raise(args[2], &iv, MP_BUFFER_READ);
if (iv.len != AES_BLOCK_SIZE) {
mp_raise_ValueError(
"Invalid length of initialization vector (has to be 128 bits)");
} }
mp_buffer_info_t key; memcpy(o->iv, iv.buf, AES_BLOCK_SIZE);
mp_get_buffer_raise(args[1], &key, MP_BUFFER_READ); } else {
if (key.len != 16 && key.len != 24 && key.len != 32) { memzero(o->iv, AES_BLOCK_SIZE);
mp_raise_ValueError("Invalid length of key (has to be 128, 192 or 256 bits)"); }
} switch (key.len) {
if (n_args > 2) { case 16:
mp_buffer_info_t iv; aes_decrypt_key128(key.buf, &(o->decrypt_ctx));
mp_get_buffer_raise(args[2], &iv, MP_BUFFER_READ); aes_encrypt_key128(key.buf, &(o->encrypt_ctx));
if (iv.len != AES_BLOCK_SIZE) { break;
mp_raise_ValueError("Invalid length of initialization vector (has to be 128 bits)"); case 24:
} aes_decrypt_key192(key.buf, &(o->decrypt_ctx));
memcpy(o->iv, iv.buf, AES_BLOCK_SIZE); aes_encrypt_key192(key.buf, &(o->encrypt_ctx));
} else { break;
memzero(o->iv, AES_BLOCK_SIZE); case 32:
} aes_decrypt_key256(key.buf, &(o->decrypt_ctx));
switch (key.len) { aes_encrypt_key256(key.buf, &(o->encrypt_ctx));
case 16: break;
aes_decrypt_key128(key.buf, &(o->decrypt_ctx)); }
aes_encrypt_key128(key.buf, &(o->encrypt_ctx)); return MP_OBJ_FROM_PTR(o);
break;
case 24:
aes_decrypt_key192(key.buf, &(o->decrypt_ctx));
aes_encrypt_key192(key.buf, &(o->encrypt_ctx));
break;
case 32:
aes_decrypt_key256(key.buf, &(o->decrypt_ctx));
aes_encrypt_key256(key.buf, &(o->encrypt_ctx));
break;
}
return MP_OBJ_FROM_PTR(o);
} }
static mp_obj_t aes_update(mp_obj_t self, mp_obj_t data, bool encrypt) { static mp_obj_t aes_update(mp_obj_t self, mp_obj_t data, bool encrypt) {
mp_buffer_info_t buf; mp_buffer_info_t buf;
mp_get_buffer_raise(data, &buf, MP_BUFFER_READ); mp_get_buffer_raise(data, &buf, MP_BUFFER_READ);
if (buf.len == 0) { if (buf.len == 0) {
return mp_const_empty_bytes; return mp_const_empty_bytes;
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, buf.len); vstr_init_len(&vstr, buf.len);
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self); mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
switch (o->mode) { switch (o->mode) {
case ECB: case ECB:
if (buf.len & (AES_BLOCK_SIZE - 1)) { if (buf.len & (AES_BLOCK_SIZE - 1)) {
mp_raise_ValueError("Invalid data length"); mp_raise_ValueError("Invalid data length");
} }
if (encrypt) { if (encrypt) {
aes_ecb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, &(o->encrypt_ctx)); aes_ecb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len,
} else { &(o->encrypt_ctx));
aes_ecb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, &(o->decrypt_ctx)); } else {
} aes_ecb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len,
break; &(o->decrypt_ctx));
case CBC: }
if (buf.len & (AES_BLOCK_SIZE - 1)) { break;
mp_raise_ValueError("Invalid data length"); case CBC:
} if (buf.len & (AES_BLOCK_SIZE - 1)) {
if (encrypt) { mp_raise_ValueError("Invalid data length");
aes_cbc_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx)); }
} else { if (encrypt) {
aes_cbc_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->decrypt_ctx)); aes_cbc_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
} &(o->encrypt_ctx));
break; } else {
case CFB: aes_cbc_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
if (encrypt) { &(o->decrypt_ctx));
aes_cfb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx)); }
} else { break;
aes_cfb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx)); // decrypt uses encrypt_ctx case CFB:
} if (encrypt) {
break; aes_cfb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
case OFB: // (encrypt == decrypt) &(o->encrypt_ctx));
aes_ofb_crypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx)); } else {
break; aes_cfb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
case CTR: // (encrypt == decrypt) &(o->encrypt_ctx)); // decrypt uses encrypt_ctx
aes_ctr_crypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, aes_ctr_cbuf_inc, &(o->encrypt_ctx)); }
break; break;
} case OFB: // (encrypt == decrypt)
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); aes_ofb_crypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
&(o->encrypt_ctx));
break;
case CTR: // (encrypt == decrypt)
aes_ctr_crypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
aes_ctr_cbuf_inc, &(o->encrypt_ctx));
break;
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
/// def encrypt(self, data: bytes) -> bytes: /// def encrypt(self, data: bytes) -> bytes:
@ -140,43 +152,50 @@ static mp_obj_t aes_update(mp_obj_t self, mp_obj_t data, bool encrypt) {
/// Encrypt data and update AES context. /// Encrypt data and update AES context.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_AES_encrypt(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_AES_encrypt(mp_obj_t self, mp_obj_t data) {
return aes_update(self, data, true); return aes_update(self, data, true);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AES_encrypt_obj, mod_trezorcrypto_AES_encrypt); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AES_encrypt_obj,
mod_trezorcrypto_AES_encrypt);
/// def decrypt(self, data: bytes) -> bytes: /// def decrypt(self, data: bytes) -> bytes:
/// ''' /// '''
/// Decrypt data and update AES context. /// Decrypt data and update AES context.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_AES_decrypt(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_AES_decrypt(mp_obj_t self, mp_obj_t data) {
return aes_update(self, data, false); return aes_update(self, data, false);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AES_decrypt_obj, mod_trezorcrypto_AES_decrypt); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AES_decrypt_obj,
mod_trezorcrypto_AES_decrypt);
STATIC mp_obj_t mod_trezorcrypto_AES___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_AES___del__(mp_obj_t self) {
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self); mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->encrypt_ctx), sizeof(aes_encrypt_ctx)); memzero(&(o->encrypt_ctx), sizeof(aes_encrypt_ctx));
memzero(&(o->decrypt_ctx), sizeof(aes_decrypt_ctx)); memzero(&(o->decrypt_ctx), sizeof(aes_decrypt_ctx));
memzero(o->iv, AES_BLOCK_SIZE); memzero(o->iv, AES_BLOCK_SIZE);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_AES___del___obj, mod_trezorcrypto_AES___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_AES___del___obj,
mod_trezorcrypto_AES___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_AES_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_AES_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&mod_trezorcrypto_AES_encrypt_obj) }, {MP_ROM_QSTR(MP_QSTR_encrypt),
{ MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&mod_trezorcrypto_AES_decrypt_obj) }, MP_ROM_PTR(&mod_trezorcrypto_AES_encrypt_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_AES___del___obj) }, {MP_ROM_QSTR(MP_QSTR_decrypt),
{ MP_ROM_QSTR(MP_QSTR_ECB), MP_OBJ_NEW_SMALL_INT(ECB) }, MP_ROM_PTR(&mod_trezorcrypto_AES_decrypt_obj)},
{ MP_ROM_QSTR(MP_QSTR_CBC), MP_OBJ_NEW_SMALL_INT(CBC) }, {MP_ROM_QSTR(MP_QSTR___del__),
{ MP_ROM_QSTR(MP_QSTR_CFB), MP_OBJ_NEW_SMALL_INT(CFB) }, MP_ROM_PTR(&mod_trezorcrypto_AES___del___obj)},
{ MP_ROM_QSTR(MP_QSTR_OFB), MP_OBJ_NEW_SMALL_INT(OFB) }, {MP_ROM_QSTR(MP_QSTR_ECB), MP_OBJ_NEW_SMALL_INT(ECB)},
{ MP_ROM_QSTR(MP_QSTR_CTR), MP_OBJ_NEW_SMALL_INT(CTR) }, {MP_ROM_QSTR(MP_QSTR_CBC), MP_OBJ_NEW_SMALL_INT(CBC)},
{MP_ROM_QSTR(MP_QSTR_CFB), MP_OBJ_NEW_SMALL_INT(CFB)},
{MP_ROM_QSTR(MP_QSTR_OFB), MP_OBJ_NEW_SMALL_INT(OFB)},
{MP_ROM_QSTR(MP_QSTR_CTR), MP_OBJ_NEW_SMALL_INT(CTR)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_AES_locals_dict, mod_trezorcrypto_AES_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_AES_locals_dict,
mod_trezorcrypto_AES_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_AES_type = { STATIC const mp_obj_type_t mod_trezorcrypto_AES_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_AES, .name = MP_QSTR_AES,
.make_new = mod_trezorcrypto_AES_make_new, .make_new = mod_trezorcrypto_AES_make_new,
.locals_dict = (void*)&mod_trezorcrypto_AES_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_AES_locals_dict,
}; };

@ -34,9 +34,9 @@
/// BIP0032 HD node structure. /// BIP0032 HD node structure.
/// ''' /// '''
typedef struct _mp_obj_HDNode_t { typedef struct _mp_obj_HDNode_t {
mp_obj_base_t base; mp_obj_base_t base;
uint32_t fingerprint; uint32_t fingerprint;
HDNode hdnode; HDNode hdnode;
} mp_obj_HDNode_t; } mp_obj_HDNode_t;
STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type; STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type;
@ -54,512 +54,612 @@ STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type;
/// curve_name: str = None) -> None: /// curve_name: str = None) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
STATIC const mp_arg_t allowed_args[] = { const mp_obj_t *args) {
{ MP_QSTR_depth, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_fingerprint, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_depth,
{ MP_QSTR_child_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{ MP_QSTR_chain_code, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {.u_obj = mp_const_none}},
{ MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {MP_QSTR_fingerprint,
{ MP_QSTR_public_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{ MP_QSTR_curve_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {.u_obj = mp_const_none}},
}; {MP_QSTR_child_num,
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); {.u_obj = mp_const_none}},
{MP_QSTR_chain_code,
mp_buffer_info_t chain_code; MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
mp_buffer_info_t private_key; {.u_obj = mp_const_empty_bytes}},
mp_buffer_info_t public_key; {MP_QSTR_private_key,
mp_buffer_info_t curve_name; MP_ARG_KW_ONLY | MP_ARG_OBJ,
const uint32_t depth = trezor_obj_get_uint(vals[0].u_obj); {.u_obj = mp_const_empty_bytes}},
const uint32_t fingerprint = trezor_obj_get_uint(vals[1].u_obj); {MP_QSTR_public_key,
const uint32_t child_num = trezor_obj_get_uint(vals[2].u_obj); MP_ARG_KW_ONLY | MP_ARG_OBJ,
mp_get_buffer_raise(vals[3].u_obj, &chain_code, MP_BUFFER_READ); {.u_obj = mp_const_empty_bytes}},
mp_get_buffer_raise(vals[4].u_obj, &private_key, MP_BUFFER_READ); {MP_QSTR_curve_name,
mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ); MP_ARG_KW_ONLY | MP_ARG_OBJ,
mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ); {.u_obj = mp_const_empty_bytes}},
};
if (32 != chain_code.len) { mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_raise_ValueError("chain_code is invalid"); mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
} allowed_args, vals);
if (0 == public_key.len && 0 == private_key.len) {
mp_raise_ValueError("either public_key or private_key is required"); mp_buffer_info_t chain_code;
} mp_buffer_info_t private_key;
if (0 != private_key.len && 32 != private_key.len) { mp_buffer_info_t public_key;
mp_raise_ValueError("private_key is invalid"); mp_buffer_info_t curve_name;
} const uint32_t depth = trezor_obj_get_uint(vals[0].u_obj);
if (0 != public_key.len && 33 != public_key.len) { const uint32_t fingerprint = trezor_obj_get_uint(vals[1].u_obj);
mp_raise_ValueError("public_key is invalid"); const uint32_t child_num = trezor_obj_get_uint(vals[2].u_obj);
} mp_get_buffer_raise(vals[3].u_obj, &chain_code, MP_BUFFER_READ);
mp_get_buffer_raise(vals[4].u_obj, &private_key, MP_BUFFER_READ);
const curve_info *curve = NULL; mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ);
if (0 == curve_name.len) { mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ);
curve = get_curve_by_name(SECP256K1_NAME);
} else { if (32 != chain_code.len) {
curve = get_curve_by_name(curve_name.buf); mp_raise_ValueError("chain_code is invalid");
} }
if (NULL == curve) { if (0 == public_key.len && 0 == private_key.len) {
mp_raise_ValueError("curve_name is invalid"); mp_raise_ValueError("either public_key or private_key is required");
} }
if (0 != private_key.len && 32 != private_key.len) {
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t); mp_raise_ValueError("private_key is invalid");
o->base.type = type; }
o->fingerprint = fingerprint; if (0 != public_key.len && 33 != public_key.len) {
o->hdnode.depth = depth; mp_raise_ValueError("public_key is invalid");
o->hdnode.child_num = child_num; }
if (32 == chain_code.len) {
memcpy(o->hdnode.chain_code, chain_code.buf, 32); const curve_info *curve = NULL;
} else { if (0 == curve_name.len) {
memzero(o->hdnode.chain_code, 32); curve = get_curve_by_name(SECP256K1_NAME);
} } else {
if (32 == private_key.len) { curve = get_curve_by_name(curve_name.buf);
memcpy(o->hdnode.private_key, private_key.buf, 32); }
} else { if (NULL == curve) {
memzero(o->hdnode.private_key, 32); mp_raise_ValueError("curve_name is invalid");
} }
if (33 == public_key.len) {
memcpy(o->hdnode.public_key, public_key.buf, 33); mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
} else { o->base.type = type;
memzero(o->hdnode.public_key, 33); o->fingerprint = fingerprint;
} o->hdnode.depth = depth;
o->hdnode.curve = curve; o->hdnode.child_num = child_num;
if (32 == chain_code.len) {
return MP_OBJ_FROM_PTR(o); memcpy(o->hdnode.chain_code, chain_code.buf, 32);
} else {
memzero(o->hdnode.chain_code, 32);
}
if (32 == private_key.len) {
memcpy(o->hdnode.private_key, private_key.buf, 32);
} else {
memzero(o->hdnode.private_key, 32);
}
if (33 == public_key.len) {
memcpy(o->hdnode.public_key, public_key.buf, 33);
} else {
memzero(o->hdnode.public_key, 33);
}
o->hdnode.curve = curve;
return MP_OBJ_FROM_PTR(o);
} }
/// def derive(self, index: int, public: bool=False) -> None: /// def derive(self, index: int, public: bool=False) -> None:
/// ''' /// '''
/// Derive a BIP0032 child node in place. /// Derive a BIP0032 child node in place.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args,
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]); const mp_obj_t *args) {
uint32_t i = trezor_obj_get_uint(args[1]); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
uint32_t fp = hdnode_fingerprint(&o->hdnode); uint32_t i = trezor_obj_get_uint(args[1]);
bool public = n_args > 2 && args[2] == mp_const_true; uint32_t fp = hdnode_fingerprint(&o->hdnode);
bool public = n_args > 2 && args[2] == mp_const_true;
int res;
if (public) { int res;
res = hdnode_public_ckd(&o->hdnode, i); if (public) {
} else { res = hdnode_public_ckd(&o->hdnode, i);
if (0 == memcmp(o->hdnode.private_key, "\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)) { } else {
memzero(&o->hdnode, sizeof(o->hdnode)); if (0 ==
mp_raise_ValueError("Failed to derive, private key not set"); memcmp(
} o->hdnode.private_key,
res = hdnode_private_ckd(&o->hdnode, i); "\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)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
} }
if (!res) { res = hdnode_private_ckd(&o->hdnode, i);
memzero(&o->hdnode, sizeof(o->hdnode)); }
mp_raise_ValueError("Failed to derive"); if (!res) {
} memzero(&o->hdnode, sizeof(o->hdnode));
o->fingerprint = fp; mp_raise_ValueError("Failed to derive");
}
o->fingerprint = fp;
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_HDNode_derive_obj, 2, 3, mod_trezorcrypto_HDNode_derive); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_HDNode_derive_obj,
2, 3,
mod_trezorcrypto_HDNode_derive);
/// def derive_cardano(self, index: int) -> None: /// def derive_cardano(self, index: int) -> None:
/// ''' /// '''
/// Derive a BIP0032 child node in place using Cardano algorithm. /// Derive a BIP0032 child node in place using Cardano algorithm.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_cardano(mp_obj_t self, mp_obj_t index) { STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_cardano(mp_obj_t self,
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_t index) {
uint32_t i = mp_obj_get_int_truncated(index); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t fp = hdnode_fingerprint(&o->hdnode); uint32_t i = mp_obj_get_int_truncated(index);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
int res;
// same as in derive int res;
if (0 == memcmp(o->hdnode.private_key, "\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)) { // same as in derive
memzero(&o->hdnode, sizeof(o->hdnode)); if (0 ==
mp_raise_ValueError("Failed to derive, private key not set"); memcmp(o->hdnode.private_key,
} "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
// special for cardano "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
res = hdnode_private_ckd_cardano(&o->hdnode, i); 32)) {
if (!res) { memzero(&o->hdnode, sizeof(o->hdnode));
memzero(&o->hdnode, sizeof(o->hdnode)); mp_raise_ValueError("Failed to derive, private key not set");
mp_raise_ValueError("Failed to derive"); }
} // special for cardano
o->fingerprint = fp; res = hdnode_private_ckd_cardano(&o->hdnode, i);
if (!res) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive");
}
o->fingerprint = fp;
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_cardano_obj, mod_trezorcrypto_HDNode_derive_cardano); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_cardano_obj,
mod_trezorcrypto_HDNode_derive_cardano);
/// def derive_path(self, path: List[int]) -> None: /// def derive_path(self, path: List[int]) -> None:
/// ''' /// '''
/// Go through a list of indexes and iteratively derive a child node in place. /// Go through a list of indexes and iteratively derive a child node in
/// ''' /// place.
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_path(mp_obj_t self, mp_obj_t path) { /// '''
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_path(mp_obj_t self,
mp_obj_t path) {
// get path objects and length mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
size_t plen;
mp_obj_t *pitems; // get path objects and length
mp_obj_get_array(path, &plen, &pitems); size_t plen;
if (plen > 32) { mp_obj_t *pitems;
mp_raise_ValueError("Path cannot be longer than 32 indexes"); mp_obj_get_array(path, &plen, &pitems);
} if (plen > 32) {
mp_raise_ValueError("Path cannot be longer than 32 indexes");
// convert path to int array }
uint32_t pi;
uint32_t pints[plen]; // convert path to int array
for (pi = 0; pi < plen; pi++) { uint32_t pi;
pints[pi] = trezor_obj_get_uint(pitems[pi]); uint32_t pints[plen];
} for (pi = 0; pi < plen; pi++) {
pints[pi] = trezor_obj_get_uint(pitems[pi]);
if (!hdnode_private_ckd_cached(&o->hdnode, pints, plen, &o->fingerprint)) { }
// derivation failed, reset the state and raise
o->fingerprint = 0; if (!hdnode_private_ckd_cached(&o->hdnode, pints, plen, &o->fingerprint)) {
memzero(&o->hdnode, sizeof(o->hdnode)); // derivation failed, reset the state and raise
mp_raise_ValueError("Failed to derive path"); o->fingerprint = 0;
} memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive path");
}
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_path_obj, mod_trezorcrypto_HDNode_derive_path); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_path_obj,
mod_trezorcrypto_HDNode_derive_path);
STATIC mp_obj_t serialize_public_private(mp_obj_t self, bool use_public, uint32_t version) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); STATIC mp_obj_t serialize_public_private(mp_obj_t self, bool use_public,
char xpub[XPUB_MAXLEN] = {0}; uint32_t version) {
int written; mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
if (use_public) { char xpub[XPUB_MAXLEN] = {0};
hdnode_fill_public_key(&o->hdnode); int written;
written = hdnode_serialize_public(&o->hdnode, o->fingerprint, version, xpub, XPUB_MAXLEN); if (use_public) {
} else { hdnode_fill_public_key(&o->hdnode);
written = hdnode_serialize_private(&o->hdnode, o->fingerprint, version, xpub, XPUB_MAXLEN); written = hdnode_serialize_public(&o->hdnode, o->fingerprint, version, xpub,
} XPUB_MAXLEN);
if (written <= 0) { } else {
mp_raise_ValueError("Failed to serialize"); written = hdnode_serialize_private(&o->hdnode, o->fingerprint, version,
} xpub, XPUB_MAXLEN);
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)xpub, written - 1); // written includes 0 at the end }
if (written <= 0) {
mp_raise_ValueError("Failed to serialize");
}
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)xpub,
written - 1); // written includes 0 at the end
} }
/// def serialize_public(self, version: int) -> str: /// def serialize_public(self, version: int) -> str:
/// ''' /// '''
/// Serialize the public info from HD node to base58 string. /// Serialize the public info from HD node to base58 string.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_public(mp_obj_t self, mp_obj_t version) { STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_public(mp_obj_t self,
uint32_t ver = trezor_obj_get_uint(version); mp_obj_t version) {
return serialize_public_private(self, true, ver); uint32_t ver = trezor_obj_get_uint(version);
return serialize_public_private(self, true, ver);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_serialize_public_obj, mod_trezorcrypto_HDNode_serialize_public); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_serialize_public_obj,
mod_trezorcrypto_HDNode_serialize_public);
/// def serialize_private(self, version: int) -> str: /// def serialize_private(self, version: int) -> str:
/// ''' /// '''
/// Serialize the private info HD node to base58 string. /// Serialize the private info HD node to base58 string.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_private(mp_obj_t self, mp_obj_t version) { STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_private(mp_obj_t self,
uint32_t ver = trezor_obj_get_uint(version); mp_obj_t version) {
return serialize_public_private(self, false, ver); uint32_t ver = trezor_obj_get_uint(version);
return serialize_public_private(self, false, ver);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_serialize_private_obj, mod_trezorcrypto_HDNode_serialize_private); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_serialize_private_obj,
mod_trezorcrypto_HDNode_serialize_private);
/// def clone(self) -> HDNode: /// def clone(self) -> HDNode:
/// ''' /// '''
/// Returns a copy of the HD node. /// Returns a copy of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_clone(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_clone(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
mp_obj_HDNode_t *copy = m_new_obj(mp_obj_HDNode_t); mp_obj_HDNode_t *copy = m_new_obj(mp_obj_HDNode_t);
copy->base.type = &mod_trezorcrypto_HDNode_type; copy->base.type = &mod_trezorcrypto_HDNode_type;
copy->hdnode = o->hdnode; copy->hdnode = o->hdnode;
copy->fingerprint = o->fingerprint; copy->fingerprint = o->fingerprint;
return MP_OBJ_FROM_PTR(copy); return MP_OBJ_FROM_PTR(copy);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_clone_obj, mod_trezorcrypto_HDNode_clone); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_clone_obj,
mod_trezorcrypto_HDNode_clone);
/// def depth(self) -> int: /// def depth(self) -> int:
/// ''' /// '''
/// Returns a depth of the HD node. /// Returns a depth of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_depth(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_depth(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.depth); return mp_obj_new_int_from_uint(o->hdnode.depth);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_depth_obj, mod_trezorcrypto_HDNode_depth); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_depth_obj,
mod_trezorcrypto_HDNode_depth);
/// def fingerprint(self) -> int: /// def fingerprint(self) -> int:
/// ''' /// '''
/// Returns a fingerprint of the HD node (hash of the parent public key). /// Returns a fingerprint of the HD node (hash of the parent public key).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_fingerprint(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_fingerprint(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->fingerprint); return mp_obj_new_int_from_uint(o->fingerprint);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_fingerprint_obj, mod_trezorcrypto_HDNode_fingerprint); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_fingerprint_obj,
mod_trezorcrypto_HDNode_fingerprint);
/// def child_num(self) -> int: /// def child_num(self) -> int:
/// ''' /// '''
/// Returns a child index of the HD node. /// Returns a child index of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_child_num(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_child_num(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.child_num); return mp_obj_new_int_from_uint(o->hdnode.child_num);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_child_num_obj, mod_trezorcrypto_HDNode_child_num); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_child_num_obj,
mod_trezorcrypto_HDNode_child_num);
/// def chain_code(self) -> bytes: /// def chain_code(self) -> bytes:
/// ''' /// '''
/// Returns a chain code of the HD node. /// Returns a chain code of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_chain_code(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_chain_code(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.chain_code, sizeof(o->hdnode.chain_code)); return mp_obj_new_bytes(o->hdnode.chain_code, sizeof(o->hdnode.chain_code));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_chain_code_obj, mod_trezorcrypto_HDNode_chain_code); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_chain_code_obj,
mod_trezorcrypto_HDNode_chain_code);
/// def private_key(self) -> bytes: /// def private_key(self) -> bytes:
/// ''' /// '''
/// Returns a private key of the HD node. /// Returns a private key of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.private_key, sizeof(o->hdnode.private_key)); return mp_obj_new_bytes(o->hdnode.private_key, sizeof(o->hdnode.private_key));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_obj, mod_trezorcrypto_HDNode_private_key); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_obj,
mod_trezorcrypto_HDNode_private_key);
/// def private_key_ext(self) -> bytes: /// def private_key_ext(self) -> bytes:
/// ''' /// '''
/// Returns a private key extension of the HD node. /// Returns a private key extension of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key_ext(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key_ext(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.private_key_extension, sizeof(o->hdnode.private_key_extension)); return mp_obj_new_bytes(o->hdnode.private_key_extension,
sizeof(o->hdnode.private_key_extension));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_ext_obj, mod_trezorcrypto_HDNode_private_key_ext); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_ext_obj,
mod_trezorcrypto_HDNode_private_key_ext);
/// def public_key(self) -> bytes: /// def public_key(self) -> bytes:
/// ''' /// '''
/// Returns a public key of the HD node. /// Returns a public key of the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_public_key(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_public_key(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
hdnode_fill_public_key(&o->hdnode); hdnode_fill_public_key(&o->hdnode);
return mp_obj_new_bytes(o->hdnode.public_key, sizeof(o->hdnode.public_key)); return mp_obj_new_bytes(o->hdnode.public_key, sizeof(o->hdnode.public_key));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_public_key_obj, mod_trezorcrypto_HDNode_public_key); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_public_key_obj,
mod_trezorcrypto_HDNode_public_key);
/// def address(self, version: int) -> str: /// def address(self, version: int) -> str:
/// ''' /// '''
/// Compute a base58-encoded address string from the HD node. /// Compute a base58-encoded address string from the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t self, mp_obj_t version) { STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t self,
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_t version) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t v = trezor_obj_get_uint(version); uint32_t v = trezor_obj_get_uint(version);
char address[ADDRESS_MAXLEN] = {0}; char address[ADDRESS_MAXLEN] = {0};
hdnode_get_address(&o->hdnode, v, address, ADDRESS_MAXLEN); hdnode_get_address(&o->hdnode, v, address, ADDRESS_MAXLEN);
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)address, strlen(address)); return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)address,
strlen(address));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj, mod_trezorcrypto_HDNode_address); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj,
mod_trezorcrypto_HDNode_address);
/// def nem_address(self, network: int) -> str: /// def nem_address(self, network: int) -> str:
/// ''' /// '''
/// Compute a NEM address string from the HD node. /// Compute a NEM address string from the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_address(mp_obj_t self, mp_obj_t network) { STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_address(mp_obj_t self,
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_t network) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint8_t n = trezor_obj_get_uint8(network); uint8_t n = trezor_obj_get_uint8(network);
char address[NEM_ADDRESS_SIZE + 1] = {0}; // + 1 for the 0 byte char address[NEM_ADDRESS_SIZE + 1] = {0}; // + 1 for the 0 byte
if (!hdnode_get_nem_address(&o->hdnode, n, address)) { if (!hdnode_get_nem_address(&o->hdnode, n, address)) {
mp_raise_ValueError("Failed to compute a NEM address"); mp_raise_ValueError("Failed to compute a NEM address");
} }
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)address, strlen(address)); return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)address,
strlen(address));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_nem_address_obj, mod_trezorcrypto_HDNode_nem_address); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_nem_address_obj,
mod_trezorcrypto_HDNode_nem_address);
/// def nem_encrypt(self, transfer_public_key: bytes, iv: bytes, salt: bytes, payload: bytes) -> bytes: /// def nem_encrypt(self, transfer_public_key: bytes, iv: bytes, salt: bytes,
/// payload: bytes) -> bytes:
/// ''' /// '''
/// Encrypts payload using the transfer's public key /// Encrypts payload using the transfer's public key
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_encrypt(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_encrypt(size_t n_args,
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]); const mp_obj_t *args) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
mp_buffer_info_t transfer_pk;
mp_get_buffer_raise(args[1], &transfer_pk, MP_BUFFER_READ); mp_buffer_info_t transfer_pk;
if (transfer_pk.len != 32) { mp_get_buffer_raise(args[1], &transfer_pk, MP_BUFFER_READ);
mp_raise_ValueError("transfer_public_key has invalid length"); if (transfer_pk.len != 32) {
} mp_raise_ValueError("transfer_public_key has invalid length");
}
mp_buffer_info_t iv;
mp_get_buffer_raise(args[2], &iv, MP_BUFFER_READ); mp_buffer_info_t iv;
if (iv.len != 16) { mp_get_buffer_raise(args[2], &iv, MP_BUFFER_READ);
mp_raise_ValueError("iv has invalid length"); if (iv.len != 16) {
} mp_raise_ValueError("iv has invalid length");
mp_buffer_info_t salt; }
mp_get_buffer_raise(args[3], &salt, MP_BUFFER_READ); mp_buffer_info_t salt;
if (salt.len != NEM_SALT_SIZE) { mp_get_buffer_raise(args[3], &salt, MP_BUFFER_READ);
mp_raise_ValueError("salt has invalid length"); if (salt.len != NEM_SALT_SIZE) {
} mp_raise_ValueError("salt has invalid length");
mp_buffer_info_t payload; }
mp_get_buffer_raise(args[4], &payload, MP_BUFFER_READ); mp_buffer_info_t payload;
if (payload.len == 0) { mp_get_buffer_raise(args[4], &payload, MP_BUFFER_READ);
mp_raise_ValueError("payload is empty"); if (payload.len == 0) {
} mp_raise_ValueError("payload is empty");
}
vstr_t vstr;
vstr_init_len(&vstr, NEM_ENCRYPTED_SIZE(payload.len)); vstr_t vstr;
if (!hdnode_nem_encrypt(&o->hdnode, *(const ed25519_public_key *)transfer_pk.buf, iv.buf, salt.buf, payload.buf, payload.len, (uint8_t *)vstr.buf)) { vstr_init_len(&vstr, NEM_ENCRYPTED_SIZE(payload.len));
mp_raise_ValueError("HDNode nem encrypt failed"); if (!hdnode_nem_encrypt(
} &o->hdnode, *(const ed25519_public_key *)transfer_pk.buf, iv.buf,
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); salt.buf, payload.buf, payload.len, (uint8_t *)vstr.buf)) {
mp_raise_ValueError("HDNode nem encrypt failed");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_HDNode_nem_encrypt_obj, 5, 5, mod_trezorcrypto_HDNode_nem_encrypt); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorcrypto_HDNode_nem_encrypt_obj, 5, 5,
mod_trezorcrypto_HDNode_nem_encrypt);
/// def ethereum_pubkeyhash(self) -> bytes: /// def ethereum_pubkeyhash(self) -> bytes:
/// ''' /// '''
/// Compute an Ethereum pubkeyhash (aka address) from the HD node. /// Compute an Ethereum pubkeyhash (aka address) from the HD node.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_ethereum_pubkeyhash(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode_ethereum_pubkeyhash(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint8_t pkh[20]; uint8_t pkh[20];
hdnode_get_ethereum_pubkeyhash(&o->hdnode, pkh); hdnode_get_ethereum_pubkeyhash(&o->hdnode, pkh);
return mp_obj_new_bytes(pkh, sizeof(pkh)); return mp_obj_new_bytes(pkh, sizeof(pkh));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj, mod_trezorcrypto_HDNode_ethereum_pubkeyhash); STATIC MP_DEFINE_CONST_FUN_OBJ_1(
mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj,
mod_trezorcrypto_HDNode_ethereum_pubkeyhash);
STATIC mp_obj_t mod_trezorcrypto_HDNode___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_HDNode___del__(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self); mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
o->fingerprint = 0; o->fingerprint = 0;
memzero(&o->hdnode, sizeof(o->hdnode)); memzero(&o->hdnode, sizeof(o->hdnode));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode___del___obj, mod_trezorcrypto_HDNode___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode___del___obj,
mod_trezorcrypto_HDNode___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_HDNode___del___obj) }, {MP_ROM_QSTR(MP_QSTR___del__),
{ MP_ROM_QSTR(MP_QSTR_derive), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode___del___obj)},
{ MP_ROM_QSTR(MP_QSTR_derive_cardano), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_cardano_obj) }, {MP_ROM_QSTR(MP_QSTR_derive),
{ MP_ROM_QSTR(MP_QSTR_derive_path), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj)},
{ MP_ROM_QSTR(MP_QSTR_serialize_private), MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_private_obj) }, {MP_ROM_QSTR(MP_QSTR_derive_cardano),
{ MP_ROM_QSTR(MP_QSTR_serialize_public), MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_public_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_cardano_obj)},
{MP_ROM_QSTR(MP_QSTR_derive_path),
{ MP_ROM_QSTR(MP_QSTR_clone), MP_ROM_PTR(&mod_trezorcrypto_HDNode_clone_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj)},
{ MP_ROM_QSTR(MP_QSTR_depth), MP_ROM_PTR(&mod_trezorcrypto_HDNode_depth_obj) }, {MP_ROM_QSTR(MP_QSTR_serialize_private),
{ MP_ROM_QSTR(MP_QSTR_fingerprint), MP_ROM_PTR(&mod_trezorcrypto_HDNode_fingerprint_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_private_obj)},
{ MP_ROM_QSTR(MP_QSTR_child_num), MP_ROM_PTR(&mod_trezorcrypto_HDNode_child_num_obj) }, {MP_ROM_QSTR(MP_QSTR_serialize_public),
{ MP_ROM_QSTR(MP_QSTR_chain_code), MP_ROM_PTR(&mod_trezorcrypto_HDNode_chain_code_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_public_obj)},
{ MP_ROM_QSTR(MP_QSTR_private_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_obj) },
{ MP_ROM_QSTR(MP_QSTR_private_key_ext), MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_ext_obj) }, {MP_ROM_QSTR(MP_QSTR_clone),
{ MP_ROM_QSTR(MP_QSTR_public_key), MP_ROM_PTR(&mod_trezorcrypto_HDNode_public_key_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_clone_obj)},
{ MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj) }, {MP_ROM_QSTR(MP_QSTR_depth),
{ MP_ROM_QSTR(MP_QSTR_nem_address), MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_address_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_depth_obj)},
{ MP_ROM_QSTR(MP_QSTR_nem_encrypt), MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_encrypt_obj) }, {MP_ROM_QSTR(MP_QSTR_fingerprint),
{ MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash), MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj) }, MP_ROM_PTR(&mod_trezorcrypto_HDNode_fingerprint_obj)},
{MP_ROM_QSTR(MP_QSTR_child_num),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_child_num_obj)},
{MP_ROM_QSTR(MP_QSTR_chain_code),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_chain_code_obj)},
{MP_ROM_QSTR(MP_QSTR_private_key),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_obj)},
{MP_ROM_QSTR(MP_QSTR_private_key_ext),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_ext_obj)},
{MP_ROM_QSTR(MP_QSTR_public_key),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_public_key_obj)},
{MP_ROM_QSTR(MP_QSTR_address),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj)},
{MP_ROM_QSTR(MP_QSTR_nem_address),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_address_obj)},
{MP_ROM_QSTR(MP_QSTR_nem_encrypt),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_encrypt_obj)},
{MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_HDNode_locals_dict, mod_trezorcrypto_HDNode_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_HDNode_locals_dict,
mod_trezorcrypto_HDNode_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type = { STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_HDNode, .name = MP_QSTR_HDNode,
.make_new = mod_trezorcrypto_HDNode_make_new, .make_new = mod_trezorcrypto_HDNode_make_new,
.locals_dict = (void*)&mod_trezorcrypto_HDNode_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_HDNode_locals_dict,
}; };
/// def deserialize(self, value: str, version_public: int, version_private: int) -> HDNode: /// def deserialize(self, value: str, version_public: int, version_private: int)
/// -> HDNode:
/// ''' /// '''
/// Construct a BIP0032 HD node from a base58-serialized value. /// Construct a BIP0032 HD node from a base58-serialized value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip32_deserialize(mp_obj_t value, mp_obj_t version_public, mp_obj_t version_private) { STATIC mp_obj_t mod_trezorcrypto_bip32_deserialize(mp_obj_t value,
mp_buffer_info_t valueb; mp_obj_t version_public,
mp_get_buffer_raise(value, &valueb, MP_BUFFER_READ); mp_obj_t version_private) {
if (valueb.len == 0) { mp_buffer_info_t valueb;
mp_raise_ValueError("Invalid value"); mp_get_buffer_raise(value, &valueb, MP_BUFFER_READ);
} if (valueb.len == 0) {
uint32_t vpub = trezor_obj_get_uint(version_public); mp_raise_ValueError("Invalid value");
uint32_t vpriv = trezor_obj_get_uint(version_private); }
HDNode hdnode; uint32_t vpub = trezor_obj_get_uint(version_public);
uint32_t fingerprint; uint32_t vpriv = trezor_obj_get_uint(version_private);
if (hdnode_deserialize(valueb.buf, vpub, vpriv, SECP256K1_NAME, &hdnode, &fingerprint) < 0) { HDNode hdnode;
mp_raise_ValueError("Failed to deserialize"); uint32_t fingerprint;
} if (hdnode_deserialize(valueb.buf, vpub, vpriv, SECP256K1_NAME, &hdnode,
&fingerprint) < 0) {
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t); mp_raise_ValueError("Failed to deserialize");
o->base.type = &mod_trezorcrypto_HDNode_type; }
o->hdnode = hdnode;
o->fingerprint = fingerprint; mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
return MP_OBJ_FROM_PTR(o); o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = fingerprint;
return MP_OBJ_FROM_PTR(o);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_bip32_deserialize_obj, mod_trezorcrypto_bip32_deserialize); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_bip32_deserialize_obj,
mod_trezorcrypto_bip32_deserialize);
/// def from_seed(seed: bytes, curve_name: str) -> HDNode: /// def from_seed(seed: bytes, curve_name: str) -> HDNode:
/// ''' /// '''
/// Construct a BIP0032 HD node from a BIP0039 seed value. /// Construct a BIP0032 HD node from a BIP0039 seed value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip32_from_seed(mp_obj_t seed, mp_obj_t curve_name) { STATIC mp_obj_t mod_trezorcrypto_bip32_from_seed(mp_obj_t seed,
mp_buffer_info_t seedb; mp_obj_t curve_name) {
mp_get_buffer_raise(seed, &seedb, MP_BUFFER_READ); mp_buffer_info_t seedb;
if (seedb.len == 0) { mp_get_buffer_raise(seed, &seedb, MP_BUFFER_READ);
mp_raise_ValueError("Invalid seed"); if (seedb.len == 0) {
} mp_raise_ValueError("Invalid seed");
mp_buffer_info_t curveb; }
mp_get_buffer_raise(curve_name, &curveb, MP_BUFFER_READ); mp_buffer_info_t curveb;
if (curveb.len == 0) { mp_get_buffer_raise(curve_name, &curveb, MP_BUFFER_READ);
mp_raise_ValueError("Invalid curve name"); if (curveb.len == 0) {
} mp_raise_ValueError("Invalid curve name");
HDNode hdnode; }
if (!hdnode_from_seed(seedb.buf, seedb.len, curveb.buf, &hdnode)) { HDNode hdnode;
mp_raise_ValueError("Failed to derive the root node"); if (!hdnode_from_seed(seedb.buf, seedb.len, curveb.buf, &hdnode)) {
} mp_raise_ValueError("Failed to derive the root node");
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t); }
o->base.type = &mod_trezorcrypto_HDNode_type; mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
o->hdnode = hdnode; o->base.type = &mod_trezorcrypto_HDNode_type;
o->fingerprint = 0; o->hdnode = hdnode;
return MP_OBJ_FROM_PTR(o); o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_seed_obj, mod_trezorcrypto_bip32_from_seed); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_seed_obj,
mod_trezorcrypto_bip32_from_seed);
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes: /// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes:
/// ''' /// '''
/// Convert mnemonic to hdnode /// Convert mnemonic to hdnode
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip32_from_mnemonic_cardano(mp_obj_t mnemonic, mp_obj_t passphrase) { STATIC mp_obj_t mod_trezorcrypto_bip32_from_mnemonic_cardano(
mp_buffer_info_t mnemo, phrase; mp_obj_t mnemonic, mp_obj_t passphrase) {
mp_get_buffer_raise(mnemonic, &mnemo, MP_BUFFER_READ); mp_buffer_info_t mnemo, phrase;
mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ); mp_get_buffer_raise(mnemonic, &mnemo, MP_BUFFER_READ);
HDNode hdnode; mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ);
const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : ""; HDNode hdnode;
const char *ppassphrase = phrase.len > 0 ? phrase.buf : ""; const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : "";
const char *ppassphrase = phrase.len > 0 ? phrase.buf : "";
uint8_t entropy[64];
int entropy_len = mnemonic_to_entropy(pmnemonic, entropy); uint8_t entropy[64];
int entropy_len = mnemonic_to_entropy(pmnemonic, entropy);
if (entropy_len == 0) {
mp_raise_ValueError("Invalid mnemonic"); if (entropy_len == 0) {
} mp_raise_ValueError("Invalid mnemonic");
}
const int res = hdnode_from_seed_cardano((const uint8_t *)ppassphrase, phrase.len, entropy, entropy_len / 8, &hdnode);
const int res =
if (!res) { hdnode_from_seed_cardano((const uint8_t *)ppassphrase, phrase.len,
mp_raise_ValueError("Secret key generation from mnemonic is looping forever"); entropy, entropy_len / 8, &hdnode);
} else
if (res == -1) { if (!res) {
mp_raise_ValueError("Invalid mnemonic"); mp_raise_ValueError(
} "Secret key generation from mnemonic is looping forever");
} else if (res == -1) {
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t); mp_raise_ValueError("Invalid mnemonic");
o->base.type = &mod_trezorcrypto_HDNode_type; }
o->hdnode = hdnode;
o->fingerprint = 0; mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
return MP_OBJ_FROM_PTR(o); o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_mnemonic_cardano_obj, mod_trezorcrypto_bip32_from_mnemonic_cardano); STATIC MP_DEFINE_CONST_FUN_OBJ_2(
mod_trezorcrypto_bip32_from_mnemonic_cardano_obj,
mod_trezorcrypto_bip32_from_mnemonic_cardano);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip32_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip32_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bip32) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bip32)},
{ MP_ROM_QSTR(MP_QSTR_HDNode), MP_ROM_PTR(&mod_trezorcrypto_HDNode_type) }, {MP_ROM_QSTR(MP_QSTR_HDNode), MP_ROM_PTR(&mod_trezorcrypto_HDNode_type)},
{ MP_ROM_QSTR(MP_QSTR_deserialize), MP_ROM_PTR(&mod_trezorcrypto_bip32_deserialize_obj) }, {MP_ROM_QSTR(MP_QSTR_deserialize),
{ MP_ROM_QSTR(MP_QSTR_from_seed), MP_ROM_PTR(&mod_trezorcrypto_bip32_from_seed_obj) }, MP_ROM_PTR(&mod_trezorcrypto_bip32_deserialize_obj)},
{ MP_ROM_QSTR(MP_QSTR_from_mnemonic_cardano), MP_ROM_PTR(&mod_trezorcrypto_bip32_from_mnemonic_cardano_obj) }, {MP_ROM_QSTR(MP_QSTR_from_seed),
MP_ROM_PTR(&mod_trezorcrypto_bip32_from_seed_obj)},
{MP_ROM_QSTR(MP_QSTR_from_mnemonic_cardano),
MP_ROM_PTR(&mod_trezorcrypto_bip32_from_mnemonic_cardano_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_bip32_globals, mod_trezorcrypto_bip32_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_bip32_globals,
mod_trezorcrypto_bip32_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_bip32_module = { STATIC const mp_obj_module_t mod_trezorcrypto_bip32_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_bip32_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_bip32_globals,
}; };

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "py/runtime.h"
#include "py/objstr.h" #include "py/objstr.h"
#include "py/runtime.h"
#include "bip39.h" #include "bip39.h"
@ -28,138 +28,157 @@
/// ''' /// '''
/// Return the first word from the wordlist starting with prefix. /// Return the first word from the wordlist starting with prefix.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_find_word(mp_obj_t prefix) STATIC mp_obj_t mod_trezorcrypto_bip39_find_word(mp_obj_t prefix) {
{ mp_buffer_info_t pfx;
mp_buffer_info_t pfx; mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ); if (pfx.len == 0) {
if (pfx.len == 0) {
return mp_const_none;
}
for (const char * const *w = mnemonic_wordlist(); *w != 0; w++) {
if (strncmp(*w, pfx.buf, pfx.len) == 0) {
return mp_obj_new_str(*w, strlen(*w));
}
}
return mp_const_none; return mp_const_none;
}
for (const char *const *w = mnemonic_wordlist(); *w != 0; w++) {
if (strncmp(*w, pfx.buf, pfx.len) == 0) {
return mp_obj_new_str(*w, strlen(*w));
}
}
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_find_word_obj, mod_trezorcrypto_bip39_find_word); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_find_word_obj,
mod_trezorcrypto_bip39_find_word);
/// def complete_word(prefix: str) -> int: /// def complete_word(prefix: str) -> int:
/// ''' /// '''
/// Return possible 1-letter suffixes for given word prefix. /// Return possible 1-letter suffixes for given word prefix.
/// Result is a bitmask, with 'a' on the lowest bit, 'b' on the second lowest, etc. /// Result is a bitmask, with 'a' on the lowest bit, 'b' on the second
/// lowest, etc.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_complete_word(mp_obj_t prefix) STATIC mp_obj_t mod_trezorcrypto_bip39_complete_word(mp_obj_t prefix) {
{ mp_buffer_info_t pfx;
mp_buffer_info_t pfx; mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ); if (pfx.len == 0) {
if (pfx.len == 0) { return mp_obj_new_int(0xFFFFFFFF); // all letters
return mp_obj_new_int(0xFFFFFFFF); // all letters }
uint32_t res = 0;
uint8_t bit;
const char *word;
const char *const *wlist;
for (wlist = mnemonic_wordlist(); *wlist != 0; wlist++) {
word = *wlist;
if (strncmp(word, pfx.buf, pfx.len) == 0 && strlen(word) > pfx.len) {
bit = word[pfx.len] - 'a';
res |= 1 << bit;
} }
uint32_t res = 0; }
uint8_t bit; return mp_obj_new_int(res);
const char *word;
const char *const *wlist;
for (wlist = mnemonic_wordlist(); *wlist != 0; wlist++) {
word = *wlist;
if (strncmp(word, pfx.buf, pfx.len) == 0 && strlen(word) > pfx.len) {
bit = word[pfx.len] - 'a';
res |= 1 << bit;
}
}
return mp_obj_new_int(res);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_complete_word_obj, mod_trezorcrypto_bip39_complete_word); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_complete_word_obj,
mod_trezorcrypto_bip39_complete_word);
/// def generate(strength: int) -> str: /// def generate(strength: int) -> str:
/// ''' /// '''
/// Generate a mnemonic of given strength (128, 160, 192, 224 and 256 bits). /// Generate a mnemonic of given strength (128, 160, 192, 224 and 256 bits).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_generate(mp_obj_t strength) { STATIC mp_obj_t mod_trezorcrypto_bip39_generate(mp_obj_t strength) {
int bits = mp_obj_get_int(strength); int bits = mp_obj_get_int(strength);
if (bits % 32 || bits < 128 || bits > 256) { if (bits % 32 || bits < 128 || bits > 256) {
mp_raise_ValueError("Invalid bit strength (only 128, 160, 192, 224 and 256 values are allowed)"); mp_raise_ValueError(
} "Invalid bit strength (only 128, 160, 192, 224 and 256 values are "
const char *mnemo = mnemonic_generate(bits); "allowed)");
mp_obj_t res = mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)mnemo, strlen(mnemo)); }
mnemonic_clear(); const char *mnemo = mnemonic_generate(bits);
return res; mp_obj_t res =
mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)mnemo, strlen(mnemo));
mnemonic_clear();
return res;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_generate_obj, mod_trezorcrypto_bip39_generate); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_generate_obj,
mod_trezorcrypto_bip39_generate);
/// def from_data(data: bytes) -> str: /// def from_data(data: bytes) -> str:
/// ''' /// '''
/// Generate a mnemonic from given data (of 16, 20, 24, 28 and 32 bytes). /// Generate a mnemonic from given data (of 16, 20, 24, 28 and 32 bytes).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_from_data(mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_bip39_from_data(mp_obj_t data) {
mp_buffer_info_t bin; mp_buffer_info_t bin;
mp_get_buffer_raise(data, &bin, MP_BUFFER_READ); mp_get_buffer_raise(data, &bin, MP_BUFFER_READ);
if (bin.len % 4 || bin.len < 16 || bin.len > 32) { if (bin.len % 4 || bin.len < 16 || bin.len > 32) {
mp_raise_ValueError("Invalid data length (only 16, 20, 24, 28 and 32 bytes are allowed)"); mp_raise_ValueError(
} "Invalid data length (only 16, 20, 24, 28 and 32 bytes are allowed)");
const char *mnemo = mnemonic_from_data(bin.buf, bin.len); }
mp_obj_t res = mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)mnemo, strlen(mnemo)); const char *mnemo = mnemonic_from_data(bin.buf, bin.len);
mnemonic_clear(); mp_obj_t res =
return res; mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)mnemo, strlen(mnemo));
mnemonic_clear();
return res;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_from_data_obj, mod_trezorcrypto_bip39_from_data); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_from_data_obj,
mod_trezorcrypto_bip39_from_data);
/// def check(mnemonic: str) -> bool: /// def check(mnemonic: str) -> bool:
/// ''' /// '''
/// Check whether given mnemonic is valid. /// Check whether given mnemonic is valid.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_check(mp_obj_t mnemonic) { STATIC mp_obj_t mod_trezorcrypto_bip39_check(mp_obj_t mnemonic) {
mp_buffer_info_t text; mp_buffer_info_t text;
mp_get_buffer_raise(mnemonic, &text, MP_BUFFER_READ); mp_get_buffer_raise(mnemonic, &text, MP_BUFFER_READ);
return (text.len > 0 && mnemonic_check(text.buf)) ? mp_const_true : mp_const_false; return (text.len > 0 && mnemonic_check(text.buf)) ? mp_const_true
: mp_const_false;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_check_obj, mod_trezorcrypto_bip39_check); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_bip39_check_obj,
mod_trezorcrypto_bip39_check);
STATIC mp_obj_t ui_wait_callback = mp_const_none; STATIC mp_obj_t ui_wait_callback = mp_const_none;
STATIC void wrapped_ui_wait_callback(uint32_t current, uint32_t total) { STATIC void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
if (mp_obj_is_callable(ui_wait_callback)) { if (mp_obj_is_callable(ui_wait_callback)) {
mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(current), mp_obj_new_int(total)); mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(current),
} mp_obj_new_int(total));
}
} }
/// def seed(mnemonic: str, passphrase: str, callback: (int, int -> None)=None) -> bytes: /// def seed(mnemonic: str, passphrase: str, callback: (int, int -> None)=None)
/// -> bytes:
/// ''' /// '''
/// Generate seed from mnemonic and passphrase. /// Generate seed from mnemonic and passphrase.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_seed(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_bip39_seed(size_t n_args,
mp_buffer_info_t mnemo; const mp_obj_t *args) {
mp_buffer_info_t phrase; mp_buffer_info_t mnemo;
mp_get_buffer_raise(args[0], &mnemo, MP_BUFFER_READ); mp_buffer_info_t phrase;
mp_get_buffer_raise(args[1], &phrase, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &mnemo, MP_BUFFER_READ);
uint8_t seed[64]; mp_get_buffer_raise(args[1], &phrase, MP_BUFFER_READ);
const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : ""; uint8_t seed[64];
const char *ppassphrase = phrase.len > 0 ? phrase.buf : ""; const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : "";
if (n_args > 2) { const char *ppassphrase = phrase.len > 0 ? phrase.buf : "";
// generate with a progress callback if (n_args > 2) {
ui_wait_callback = args[2]; // generate with a progress callback
mnemonic_to_seed(pmnemonic, ppassphrase, seed, wrapped_ui_wait_callback); ui_wait_callback = args[2];
ui_wait_callback = mp_const_none; mnemonic_to_seed(pmnemonic, ppassphrase, seed, wrapped_ui_wait_callback);
} else { ui_wait_callback = mp_const_none;
// generate without callback } else {
mnemonic_to_seed(pmnemonic, ppassphrase, seed, NULL); // generate without callback
} mnemonic_to_seed(pmnemonic, ppassphrase, seed, NULL);
return mp_obj_new_bytes(seed, sizeof(seed)); }
return mp_obj_new_bytes(seed, sizeof(seed));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_bip39_seed_obj, 2, 3, mod_trezorcrypto_bip39_seed); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_bip39_seed_obj, 2,
3, mod_trezorcrypto_bip39_seed);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip39_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip39_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bip39) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bip39)},
{ MP_ROM_QSTR(MP_QSTR_find_word), MP_ROM_PTR(&mod_trezorcrypto_bip39_find_word_obj) }, {MP_ROM_QSTR(MP_QSTR_find_word),
{ MP_ROM_QSTR(MP_QSTR_complete_word), MP_ROM_PTR(&mod_trezorcrypto_bip39_complete_word_obj) }, MP_ROM_PTR(&mod_trezorcrypto_bip39_find_word_obj)},
{ MP_ROM_QSTR(MP_QSTR_generate), MP_ROM_PTR(&mod_trezorcrypto_bip39_generate_obj) }, {MP_ROM_QSTR(MP_QSTR_complete_word),
{ MP_ROM_QSTR(MP_QSTR_from_data), MP_ROM_PTR(&mod_trezorcrypto_bip39_from_data_obj) }, MP_ROM_PTR(&mod_trezorcrypto_bip39_complete_word_obj)},
{ MP_ROM_QSTR(MP_QSTR_check), MP_ROM_PTR(&mod_trezorcrypto_bip39_check_obj) }, {MP_ROM_QSTR(MP_QSTR_generate),
{ MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_trezorcrypto_bip39_seed_obj) }, MP_ROM_PTR(&mod_trezorcrypto_bip39_generate_obj)},
{MP_ROM_QSTR(MP_QSTR_from_data),
MP_ROM_PTR(&mod_trezorcrypto_bip39_from_data_obj)},
{MP_ROM_QSTR(MP_QSTR_check), MP_ROM_PTR(&mod_trezorcrypto_bip39_check_obj)},
{MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_trezorcrypto_bip39_seed_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_bip39_globals, mod_trezorcrypto_bip39_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_bip39_globals,
mod_trezorcrypto_bip39_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_bip39_module = { STATIC const mp_obj_module_t mod_trezorcrypto_bip39_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_bip39_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_bip39_globals,
}; };

@ -29,8 +29,8 @@
/// Blake256 context. /// Blake256 context.
/// ''' /// '''
typedef struct _mp_obj_Blake256_t { typedef struct _mp_obj_Blake256_t {
mp_obj_base_t base; mp_obj_base_t base;
BLAKE256_CTX ctx; BLAKE256_CTX ctx;
} mp_obj_Blake256_t; } mp_obj_Blake256_t;
STATIC mp_obj_t mod_trezorcrypto_Blake256_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Blake256_update(mp_obj_t self, mp_obj_t data);
@ -39,16 +39,18 @@ STATIC mp_obj_t mod_trezorcrypto_Blake256_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Blake256_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Blake256_t *o = m_new_obj(mp_obj_Blake256_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
blake256_Init(&(o->ctx)); mp_obj_Blake256_t *o = m_new_obj(mp_obj_Blake256_t);
// constructor called with bytes/str as first parameter o->base.type = type;
if (n_args == 1) { blake256_Init(&(o->ctx));
mod_trezorcrypto_Blake256_update(MP_OBJ_FROM_PTR(o), args[0]); // constructor called with bytes/str as first parameter
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Blake256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -56,50 +58,59 @@ STATIC mp_obj_t mod_trezorcrypto_Blake256_make_new(const mp_obj_type_t *type, si
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake256_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Blake256_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
blake256_Update(&(o->ctx), msg.buf, msg.len); blake256_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake256_update_obj, mod_trezorcrypto_Blake256_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake256_update_obj,
mod_trezorcrypto_Blake256_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake256_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake256_digest(mp_obj_t self) {
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
uint8_t hash[BLAKE256_DIGEST_LENGTH]; uint8_t hash[BLAKE256_DIGEST_LENGTH];
BLAKE256_CTX ctx; BLAKE256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE256_CTX)); memcpy(&ctx, &(o->ctx), sizeof(BLAKE256_CTX));
blake256_Final(&ctx, hash); blake256_Final(&ctx, hash);
memzero(&ctx, sizeof(BLAKE256_CTX)); memzero(&ctx, sizeof(BLAKE256_CTX));
return mp_obj_new_bytes(hash, sizeof(hash)); return mp_obj_new_bytes(hash, sizeof(hash));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake256_digest_obj, mod_trezorcrypto_Blake256_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake256_digest_obj,
mod_trezorcrypto_Blake256_digest);
STATIC mp_obj_t mod_trezorcrypto_Blake256___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake256___del__(mp_obj_t self) {
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE256_CTX)); memzero(&(o->ctx), sizeof(BLAKE256_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake256___del___obj, mod_trezorcrypto_Blake256___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake256___del___obj,
mod_trezorcrypto_Blake256___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake256_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake256_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake256_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake256_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Blake256_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Blake256___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(BLAKE256_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Blake256_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(BLAKE256_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Blake256___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(BLAKE256_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(BLAKE256_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake256_locals_dict, mod_trezorcrypto_Blake256_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake256_locals_dict,
mod_trezorcrypto_Blake256_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Blake256_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Blake256_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Blake256, .name = MP_QSTR_Blake256,
.make_new = mod_trezorcrypto_Blake256_make_new, .make_new = mod_trezorcrypto_Blake256_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Blake256_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Blake256_locals_dict,
}; };

@ -31,61 +31,75 @@
/// Blake2b context. /// Blake2b context.
/// ''' /// '''
typedef struct _mp_obj_Blake2b_t { typedef struct _mp_obj_Blake2b_t {
mp_obj_base_t base; mp_obj_base_t base;
BLAKE2B_CTX ctx; BLAKE2B_CTX ctx;
} mp_obj_Blake2b_t; } mp_obj_Blake2b_t;
STATIC mp_obj_t mod_trezorcrypto_Blake2b_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Blake2b_update(mp_obj_t self, mp_obj_t data);
/// def __init__(self, data: bytes = None, outlen: int = Blake2b.digest_size, personal: bytes = None) -> None: /// def __init__(self, data: bytes = None, outlen: int = Blake2b.digest_size,
/// personal: bytes = None) -> None:
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2b_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Blake2b_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
STATIC const mp_arg_t allowed_args[] = { const mp_obj_t *args) {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_outlen, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLAKE2B_DIGEST_LENGTH} }, {MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes}},
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {MP_QSTR_outlen,
{ MP_QSTR_personal, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, MP_ARG_KW_ONLY | MP_ARG_INT,
}; {.u_int = BLAKE2B_DIGEST_LENGTH}},
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; {MP_QSTR_key,
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
size_t data_len; {MP_QSTR_personal,
const uint8_t *data = (const uint8_t *)mp_obj_str_get_data(vals[0].u_obj, &data_len); MP_ARG_KW_ONLY | MP_ARG_OBJ,
const mp_int_t outlen = vals[1].u_int; {.u_obj = mp_const_empty_bytes}},
size_t key_len; };
const uint8_t *key = (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len); mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
size_t personal_len; mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
const uint8_t *personal = (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len); allowed_args, vals);
if (key_len > 0 && personal_len > 0) { size_t data_len;
mp_raise_ValueError("Invalid Blake2b parameters: cannot use key and personal at the same time"); const uint8_t *data =
} (const uint8_t *)mp_obj_str_get_data(vals[0].u_obj, &data_len);
const mp_int_t outlen = vals[1].u_int;
mp_obj_Blake2b_t *o = m_new_obj(mp_obj_Blake2b_t); size_t key_len;
o->base.type = type; const uint8_t *key =
int res = 0; (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
if (key_len > 0) { const uint8_t *personal =
res = blake2b_InitKey(&(o->ctx), outlen, key, key_len); (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
} else if (personal_len > 0) {
res = blake2b_InitPersonal(&(o->ctx), outlen, personal, personal_len); if (key_len > 0 && personal_len > 0) {
} else { mp_raise_ValueError(
res = blake2b_Init(&(o->ctx), outlen); "Invalid Blake2b parameters: cannot use key and personal at the same "
} "time");
}
if (res < 0) {
mp_raise_ValueError("Invalid Blake2b parameters"); mp_obj_Blake2b_t *o = m_new_obj(mp_obj_Blake2b_t);
} o->base.type = type;
int res = 0;
// constructor called with data argument set
if (data_len > 0) { if (key_len > 0) {
blake2b_Update(&(o->ctx), data, data_len); res = blake2b_InitKey(&(o->ctx), outlen, key, key_len);
} } else if (personal_len > 0) {
res = blake2b_InitPersonal(&(o->ctx), outlen, personal, personal_len);
return MP_OBJ_FROM_PTR(o); } else {
res = blake2b_Init(&(o->ctx), outlen);
}
if (res < 0) {
mp_raise_ValueError("Invalid Blake2b parameters");
}
// constructor called with data argument set
if (data_len > 0) {
blake2b_Update(&(o->ctx), data, data_len);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -93,50 +107,59 @@ STATIC mp_obj_t mod_trezorcrypto_Blake2b_make_new(const mp_obj_type_t *type, siz
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2b_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Blake2b_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
blake2b_Update(&(o->ctx), msg.buf, msg.len); blake2b_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake2b_update_obj, mod_trezorcrypto_Blake2b_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake2b_update_obj,
mod_trezorcrypto_Blake2b_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2b_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake2b_digest(mp_obj_t self) {
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2B_DIGEST_LENGTH]; uint8_t out[BLAKE2B_DIGEST_LENGTH];
BLAKE2B_CTX ctx; BLAKE2B_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2B_CTX)); memcpy(&ctx, &(o->ctx), sizeof(BLAKE2B_CTX));
blake2b_Final(&ctx, out, ctx.outlen); blake2b_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2B_CTX)); memzero(&ctx, sizeof(BLAKE2B_CTX));
return mp_obj_new_bytes(out, o->ctx.outlen); return mp_obj_new_bytes(out, o->ctx.outlen);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2b_digest_obj, mod_trezorcrypto_Blake2b_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2b_digest_obj,
mod_trezorcrypto_Blake2b_digest);
STATIC mp_obj_t mod_trezorcrypto_Blake2b___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake2b___del__(mp_obj_t self) {
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2B_CTX)); memzero(&(o->ctx), sizeof(BLAKE2B_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2b___del___obj, mod_trezorcrypto_Blake2b___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2b___del___obj,
mod_trezorcrypto_Blake2b___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake2b_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake2b_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Blake2b_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Blake2b___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(BLAKE2B_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Blake2b_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(BLAKE2B_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Blake2b___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(BLAKE2B_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(BLAKE2B_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake2b_locals_dict, mod_trezorcrypto_Blake2b_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake2b_locals_dict,
mod_trezorcrypto_Blake2b_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Blake2b_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Blake2b_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Blake2b, .name = MP_QSTR_Blake2b,
.make_new = mod_trezorcrypto_Blake2b_make_new, .make_new = mod_trezorcrypto_Blake2b_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Blake2b_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Blake2b_locals_dict,
}; };

@ -31,61 +31,75 @@
/// Blake2s context. /// Blake2s context.
/// ''' /// '''
typedef struct _mp_obj_Blake2s_t { typedef struct _mp_obj_Blake2s_t {
mp_obj_base_t base; mp_obj_base_t base;
BLAKE2S_CTX ctx; BLAKE2S_CTX ctx;
} mp_obj_Blake2s_t; } mp_obj_Blake2s_t;
STATIC mp_obj_t mod_trezorcrypto_Blake2s_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Blake2s_update(mp_obj_t self, mp_obj_t data);
/// def __init__(self, data: bytes = None, outlen: int = Blake2s.digest_size, key: bytes = None, personal: bytes = None) -> None: /// def __init__(self, data: bytes = None, outlen: int = Blake2s.digest_size,
/// key: bytes = None, personal: bytes = None) -> None:
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2s_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Blake2s_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
STATIC const mp_arg_t allowed_args[] = { const mp_obj_t *args) {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_outlen, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLAKE2S_DIGEST_LENGTH} }, {MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes}},
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {MP_QSTR_outlen,
{ MP_QSTR_personal, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, MP_ARG_KW_ONLY | MP_ARG_INT,
}; {.u_int = BLAKE2S_DIGEST_LENGTH}},
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; {MP_QSTR_key,
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
size_t data_len; {MP_QSTR_personal,
const uint8_t *data = (const uint8_t *)mp_obj_str_get_data(vals[0].u_obj, &data_len); MP_ARG_KW_ONLY | MP_ARG_OBJ,
const mp_int_t outlen = vals[1].u_int; {.u_obj = mp_const_empty_bytes}},
size_t key_len; };
const uint8_t *key = (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len); mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
size_t personal_len; mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
const uint8_t *personal = (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len); allowed_args, vals);
if (key_len > 0 && personal_len > 0) { size_t data_len;
mp_raise_ValueError("Invalid Blake2s parameters: cannot use key and personal at the same time"); const uint8_t *data =
} (const uint8_t *)mp_obj_str_get_data(vals[0].u_obj, &data_len);
const mp_int_t outlen = vals[1].u_int;
mp_obj_Blake2s_t *o = m_new_obj(mp_obj_Blake2s_t); size_t key_len;
o->base.type = type; const uint8_t *key =
int res = 0; (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
if (key_len > 0) { const uint8_t *personal =
res = blake2s_InitKey(&(o->ctx), outlen, key, key_len); (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
} else if (personal_len > 0) {
res = blake2s_InitPersonal(&(o->ctx), outlen, personal, personal_len); if (key_len > 0 && personal_len > 0) {
} else { mp_raise_ValueError(
res = blake2s_Init(&(o->ctx), outlen); "Invalid Blake2s parameters: cannot use key and personal at the same "
} "time");
}
if (res < 0) {
mp_raise_ValueError("Invalid Blake2s parameters"); mp_obj_Blake2s_t *o = m_new_obj(mp_obj_Blake2s_t);
} o->base.type = type;
int res = 0;
// constructor called with data argument set
if (data_len > 0) { if (key_len > 0) {
blake2s_Update(&(o->ctx), data, data_len); res = blake2s_InitKey(&(o->ctx), outlen, key, key_len);
} } else if (personal_len > 0) {
res = blake2s_InitPersonal(&(o->ctx), outlen, personal, personal_len);
return MP_OBJ_FROM_PTR(o); } else {
res = blake2s_Init(&(o->ctx), outlen);
}
if (res < 0) {
mp_raise_ValueError("Invalid Blake2s parameters");
}
// constructor called with data argument set
if (data_len > 0) {
blake2s_Update(&(o->ctx), data, data_len);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -93,50 +107,59 @@ STATIC mp_obj_t mod_trezorcrypto_Blake2s_make_new(const mp_obj_type_t *type, siz
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2s_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Blake2s_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
blake2s_Update(&(o->ctx), msg.buf, msg.len); blake2s_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake2s_update_obj, mod_trezorcrypto_Blake2s_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Blake2s_update_obj,
mod_trezorcrypto_Blake2s_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2s_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake2s_digest(mp_obj_t self) {
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2S_DIGEST_LENGTH]; uint8_t out[BLAKE2S_DIGEST_LENGTH];
BLAKE2S_CTX ctx; BLAKE2S_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2S_CTX)); memcpy(&ctx, &(o->ctx), sizeof(BLAKE2S_CTX));
blake2s_Final(&ctx, out, ctx.outlen); blake2s_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2S_CTX)); memzero(&ctx, sizeof(BLAKE2S_CTX));
return mp_obj_new_bytes(out, o->ctx.outlen); return mp_obj_new_bytes(out, o->ctx.outlen);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2s_digest_obj, mod_trezorcrypto_Blake2s_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2s_digest_obj,
mod_trezorcrypto_Blake2s_digest);
STATIC mp_obj_t mod_trezorcrypto_Blake2s___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Blake2s___del__(mp_obj_t self) {
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self); mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2S_CTX)); memzero(&(o->ctx), sizeof(BLAKE2S_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2s___del___obj, mod_trezorcrypto_Blake2s___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Blake2s___del___obj,
mod_trezorcrypto_Blake2s___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake2s_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Blake2s_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Blake2s_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Blake2s___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(BLAKE2S_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Blake2s_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(BLAKE2S_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Blake2s___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(BLAKE2S_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(BLAKE2S_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake2s_locals_dict, mod_trezorcrypto_Blake2s_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Blake2s_locals_dict,
mod_trezorcrypto_Blake2s_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Blake2s_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Blake2s_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Blake2s, .name = MP_QSTR_Blake2s,
.make_new = mod_trezorcrypto_Blake2s_make_new, .make_new = mod_trezorcrypto_Blake2s_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Blake2s_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Blake2s_locals_dict,
}; };

@ -29,9 +29,9 @@
/// ChaCha20Poly1305 context. /// ChaCha20Poly1305 context.
/// ''' /// '''
typedef struct _mp_obj_ChaCha20Poly1305_t { typedef struct _mp_obj_ChaCha20Poly1305_t {
mp_obj_base_t base; mp_obj_base_t base;
chacha20poly1305_ctx ctx; chacha20poly1305_ctx ctx;
int64_t alen, plen; int64_t alen, plen;
} mp_obj_ChaCha20Poly1305_t; } mp_obj_ChaCha20Poly1305_t;
/// def __init__(self, key: bytes, nonce: bytes) -> None: /// def __init__(self, key: bytes, nonce: bytes) -> None:
@ -39,56 +39,64 @@ typedef struct _mp_obj_ChaCha20Poly1305_t {
/// Initialize the ChaCha20 + Poly1305 context for encryption or decryption /// Initialize the ChaCha20 + Poly1305 context for encryption or decryption
/// using a 32 byte key and 12 byte nonce as in the RFC 7539 style. /// using a 32 byte key and 12 byte nonce as in the RFC 7539 style.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_make_new(
mp_arg_check_num(n_args, n_kw, 2, 2, false); const mp_obj_type_t *type, size_t n_args, size_t n_kw,
mp_obj_ChaCha20Poly1305_t *o = m_new_obj(mp_obj_ChaCha20Poly1305_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_buffer_info_t key, nonce; mp_obj_ChaCha20Poly1305_t *o = m_new_obj(mp_obj_ChaCha20Poly1305_t);
mp_get_buffer_raise(args[0], &key, MP_BUFFER_READ); o->base.type = type;
mp_get_buffer_raise(args[1], &nonce, MP_BUFFER_READ); mp_buffer_info_t key, nonce;
if (key.len != 32) { mp_get_buffer_raise(args[0], &key, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of key"); mp_get_buffer_raise(args[1], &nonce, MP_BUFFER_READ);
} if (key.len != 32) {
if (nonce.len != 12) { mp_raise_ValueError("Invalid length of key");
mp_raise_ValueError("Invalid length of nonce"); }
} if (nonce.len != 12) {
rfc7539_init(&(o->ctx), key.buf, nonce.buf); mp_raise_ValueError("Invalid length of nonce");
o->alen = 0; }
o->plen = 0; rfc7539_init(&(o->ctx), key.buf, nonce.buf);
return MP_OBJ_FROM_PTR(o); o->alen = 0;
o->plen = 0;
return MP_OBJ_FROM_PTR(o);
} }
/// def encrypt(self, data: bytes) -> bytes: /// def encrypt(self, data: bytes) -> bytes:
/// ''' /// '''
/// Encrypt data (length of data must be divisible by 64 except for the final value). /// Encrypt data (length of data must be divisible by 64 except for the
/// final value).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_encrypt(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_encrypt(mp_obj_t self,
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self); mp_obj_t data) {
mp_buffer_info_t in; mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_get_buffer_raise(data, &in, MP_BUFFER_READ); mp_buffer_info_t in;
vstr_t vstr; mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_init_len(&vstr, in.len); vstr_t vstr;
chacha20poly1305_encrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len); vstr_init_len(&vstr, in.len);
o->plen += in.len; chacha20poly1305_encrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); o->plen += in.len;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj, mod_trezorcrypto_ChaCha20Poly1305_encrypt); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj,
mod_trezorcrypto_ChaCha20Poly1305_encrypt);
/// def decrypt(self, data: bytes) -> bytes: /// def decrypt(self, data: bytes) -> bytes:
/// ''' /// '''
/// Decrypt data (length of data must be divisible by 64 except for the final value). /// Decrypt data (length of data must be divisible by 64 except for the
/// final value).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_decrypt(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_decrypt(mp_obj_t self,
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self); mp_obj_t data) {
mp_buffer_info_t in; mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_get_buffer_raise(data, &in, MP_BUFFER_READ); mp_buffer_info_t in;
vstr_t vstr; mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_init_len(&vstr, in.len); vstr_t vstr;
chacha20poly1305_decrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len); vstr_init_len(&vstr, in.len);
o->plen += in.len; chacha20poly1305_decrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); o->plen += in.len;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_decrypt_obj, mod_trezorcrypto_ChaCha20Poly1305_decrypt); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_decrypt_obj,
mod_trezorcrypto_ChaCha20Poly1305_decrypt);
/// def auth(self, data: bytes) -> None: /// def auth(self, data: bytes) -> None:
/// ''' /// '''
@ -96,49 +104,61 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_decrypt_obj,
/// style with 16 byte padding. This must only be called once and prior /// style with 16 byte padding. This must only be called once and prior
/// to encryption or decryption. /// to encryption or decryption.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_auth(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_auth(mp_obj_t self,
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self); mp_obj_t data) {
mp_buffer_info_t in; mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_get_buffer_raise(data, &in, MP_BUFFER_READ); mp_buffer_info_t in;
rfc7539_auth(&(o->ctx), in.buf, in.len); mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
o->alen += in.len; rfc7539_auth(&(o->ctx), in.buf, in.len);
return mp_const_none; o->alen += in.len;
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_auth_obj, mod_trezorcrypto_ChaCha20Poly1305_auth); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ChaCha20Poly1305_auth_obj,
mod_trezorcrypto_ChaCha20Poly1305_auth);
/// def finish(self) -> bytes: /// def finish(self) -> bytes:
/// ''' /// '''
/// Compute RFC 7539-style Poly1305 MAC. /// Compute RFC 7539-style Poly1305 MAC.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_finish(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_finish(mp_obj_t self) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self); mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[16]; uint8_t out[16];
rfc7539_finish(&(o->ctx), o->alen, o->plen, out); rfc7539_finish(&(o->ctx), o->alen, o->plen, out);
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ChaCha20Poly1305_finish_obj, mod_trezorcrypto_ChaCha20Poly1305_finish); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ChaCha20Poly1305_finish_obj,
mod_trezorcrypto_ChaCha20Poly1305_finish);
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305___del__(mp_obj_t self) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self); mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(chacha20poly1305_ctx)); memzero(&(o->ctx), sizeof(chacha20poly1305_ctx));
o->alen = 0; o->alen = 0;
o->plen = 0; o->plen = 0;
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ChaCha20Poly1305___del___obj, mod_trezorcrypto_ChaCha20Poly1305___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ChaCha20Poly1305___del___obj,
mod_trezorcrypto_ChaCha20Poly1305___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_ChaCha20Poly1305_locals_dict_table[] = { STATIC const mp_rom_map_elem_t
{ MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj) }, mod_trezorcrypto_ChaCha20Poly1305_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_decrypt_obj) }, {MP_ROM_QSTR(MP_QSTR_encrypt),
{ MP_ROM_QSTR(MP_QSTR_auth), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_auth_obj) }, MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj)},
{ MP_ROM_QSTR(MP_QSTR_finish), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_finish_obj) }, {MP_ROM_QSTR(MP_QSTR_decrypt),
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305___del___obj) }, MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_decrypt_obj)},
{MP_ROM_QSTR(MP_QSTR_auth),
MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_auth_obj)},
{MP_ROM_QSTR(MP_QSTR_finish),
MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_finish_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305___del___obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_ChaCha20Poly1305_locals_dict, mod_trezorcrypto_ChaCha20Poly1305_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(
mod_trezorcrypto_ChaCha20Poly1305_locals_dict,
mod_trezorcrypto_ChaCha20Poly1305_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_ChaCha20Poly1305_type = { STATIC const mp_obj_type_t mod_trezorcrypto_ChaCha20Poly1305_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_ChaCha20Poly1305, .name = MP_QSTR_ChaCha20Poly1305,
.make_new = mod_trezorcrypto_ChaCha20Poly1305_make_new, .make_new = mod_trezorcrypto_ChaCha20Poly1305_make_new,
.locals_dict = (void*)&mod_trezorcrypto_ChaCha20Poly1305_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_ChaCha20Poly1305_locals_dict,
}; };

@ -24,21 +24,23 @@
#include "crc.h" #include "crc.h"
mp_obj_t mod_trezorcrypto_crc_crc32(size_t n_args, const mp_obj_t *args) { mp_obj_t mod_trezorcrypto_crc_crc32(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
uint32_t crc = (n_args > 1) ? trezor_obj_get_uint(args[1]) : 0; uint32_t crc = (n_args > 1) ? trezor_obj_get_uint(args[1]) : 0;
crc = checksum_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); crc = checksum_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
return mp_obj_new_int_from_uint(crc ^ 0xffffffff); return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_crc_crc32_obj, 1, 2, mod_trezorcrypto_crc_crc32); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_crc_crc32_obj, 1, 2,
mod_trezorcrypto_crc_crc32);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_crc_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_crc_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_crc) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_crc)},
{ MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_trezorcrypto_crc_crc32_obj) }, {MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_trezorcrypto_crc_crc32_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_crc_globals, mod_trezorcrypto_crc_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_crc_globals,
mod_trezorcrypto_crc_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_crc_module = { STATIC const mp_obj_module_t mod_trezorcrypto_crc_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_crc_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_crc_globals,
}; };

@ -30,62 +30,71 @@
/// Generate secret key. /// Generate secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_generate_secret() { STATIC mp_obj_t mod_trezorcrypto_curve25519_generate_secret() {
uint8_t out[32]; uint8_t out[32];
random_buffer(out, 32); random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html // taken from https://cr.yp.to/ecdh.html
out[0] &= 248; out[0] &= 248;
out[31] &= 127; out[31] &= 127;
out[31] |= 64; out[31] |= 64;
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_curve25519_generate_secret_obj, mod_trezorcrypto_curve25519_generate_secret); STATIC MP_DEFINE_CONST_FUN_OBJ_0(
mod_trezorcrypto_curve25519_generate_secret_obj,
mod_trezorcrypto_curve25519_generate_secret);
/// def publickey(secret_key: bytes) -> bytes: /// def publickey(secret_key: bytes) -> bytes:
/// ''' /// '''
/// Computes public key from secret key. /// Computes public key from secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_publickey(mp_obj_t secret_key) { STATIC mp_obj_t mod_trezorcrypto_curve25519_publickey(mp_obj_t secret_key) {
mp_buffer_info_t sk; mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key"); mp_raise_ValueError("Invalid length of secret key");
} }
uint8_t out[32]; uint8_t out[32];
curve25519_scalarmult_basepoint(out, (const uint8_t *)sk.buf); curve25519_scalarmult_basepoint(out, (const uint8_t *)sk.buf);
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_curve25519_publickey_obj, mod_trezorcrypto_curve25519_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_curve25519_publickey_obj,
mod_trezorcrypto_curve25519_publickey);
/// def multiply(secret_key: bytes, public_key: bytes) -> bytes: /// def multiply(secret_key: bytes, public_key: bytes) -> bytes:
/// ''' /// '''
/// Multiplies point defined by public_key with scalar defined by secret_key. /// Multiplies point defined by public_key with scalar defined by
/// Useful for ECDH. /// secret_key. Useful for ECDH.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_multiply(mp_obj_t secret_key, mp_obj_t public_key) { STATIC mp_obj_t mod_trezorcrypto_curve25519_multiply(mp_obj_t secret_key,
mp_buffer_info_t sk, pk; mp_obj_t public_key) {
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_buffer_info_t sk, pk;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (pk.len != 32) { }
mp_raise_ValueError("Invalid length of public key"); if (pk.len != 32) {
} mp_raise_ValueError("Invalid length of public key");
uint8_t out[32]; }
curve25519_scalarmult(out, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf); uint8_t out[32];
return mp_obj_new_bytes(out, sizeof(out)); curve25519_scalarmult(out, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf);
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_curve25519_multiply_obj, mod_trezorcrypto_curve25519_multiply); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_curve25519_multiply_obj,
mod_trezorcrypto_curve25519_multiply);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_curve25519_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_curve25519_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_curve25519) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_curve25519)},
{ MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_trezorcrypto_curve25519_generate_secret_obj) }, {MP_ROM_QSTR(MP_QSTR_generate_secret),
{ MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_trezorcrypto_curve25519_publickey_obj) }, MP_ROM_PTR(&mod_trezorcrypto_curve25519_generate_secret_obj)},
{ MP_ROM_QSTR(MP_QSTR_multiply), MP_ROM_PTR(&mod_trezorcrypto_curve25519_multiply_obj) }, {MP_ROM_QSTR(MP_QSTR_publickey),
MP_ROM_PTR(&mod_trezorcrypto_curve25519_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_multiply),
MP_ROM_PTR(&mod_trezorcrypto_curve25519_multiply_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_curve25519_globals, mod_trezorcrypto_curve25519_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_curve25519_globals,
mod_trezorcrypto_curve25519_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_curve25519_module = { STATIC const mp_obj_module_t mod_trezorcrypto_curve25519_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_curve25519_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_curve25519_globals,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "ed25519-donna/ed25519.h"
#include "ed25519-donna/ed25519-keccak.h" #include "ed25519-donna/ed25519-keccak.h"
#include "ed25519-donna/ed25519.h"
#include "rand.h" #include "rand.h"
@ -31,220 +31,266 @@
/// Generate secret key. /// Generate secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_generate_secret() { STATIC mp_obj_t mod_trezorcrypto_ed25519_generate_secret() {
uint8_t out[32]; uint8_t out[32];
random_buffer(out, 32); random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html // taken from https://cr.yp.to/ecdh.html
out[0] &= 248; out[0] &= 248;
out[31] &= 127; out[31] &= 127;
out[31] |= 64; out[31] |= 64;
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_generate_secret_obj, mod_trezorcrypto_ed25519_generate_secret); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_generate_secret_obj,
mod_trezorcrypto_ed25519_generate_secret);
/// def publickey(secret_key: bytes) -> bytes: /// def publickey(secret_key: bytes) -> bytes:
/// ''' /// '''
/// Computes public key from secret key. /// Computes public key from secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_publickey(mp_obj_t secret_key) { STATIC mp_obj_t mod_trezorcrypto_ed25519_publickey(mp_obj_t secret_key) {
mp_buffer_info_t sk; mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key"); mp_raise_ValueError("Invalid length of secret key");
} }
uint8_t out[32]; uint8_t out[32];
ed25519_publickey(*(const ed25519_secret_key *)sk.buf, *(ed25519_public_key *)out); ed25519_publickey(*(const ed25519_secret_key *)sk.buf,
return mp_obj_new_bytes(out, sizeof(out)); *(ed25519_public_key *)out);
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ed25519_publickey_obj, mod_trezorcrypto_ed25519_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ed25519_publickey_obj,
mod_trezorcrypto_ed25519_publickey);
/// def sign(secret_key: bytes, message: bytes, hasher: str='') -> bytes: /// def sign(secret_key: bytes, message: bytes, hasher: str='') -> bytes:
/// ''' /// '''
/// Uses secret key to produce the signature of message. /// Uses secret key to produce the signature of message.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_sign(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_ed25519_sign(size_t n_args,
mp_buffer_info_t sk, msg; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk, msg;
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (msg.len == 0) { }
mp_raise_ValueError("Empty data to sign"); if (msg.len == 0) {
} mp_raise_ValueError("Empty data to sign");
ed25519_public_key pk; }
uint8_t out[64]; ed25519_public_key pk;
mp_buffer_info_t hash_func; uint8_t out[64];
mp_buffer_info_t hash_func;
if (n_args == 3) {
mp_get_buffer_raise(args[2], &hash_func, MP_BUFFER_READ); if (n_args == 3) {
// if hash_func == 'keccak': mp_get_buffer_raise(args[2], &hash_func, MP_BUFFER_READ);
if (memcmp(hash_func.buf, "keccak", sizeof("keccak")) == 0) { // if hash_func == 'keccak':
ed25519_publickey_keccak(*(const ed25519_secret_key *)sk.buf, pk); if (memcmp(hash_func.buf, "keccak", sizeof("keccak")) == 0) {
ed25519_sign_keccak(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, pk, *(ed25519_signature *)out); ed25519_publickey_keccak(*(const ed25519_secret_key *)sk.buf, pk);
} else { ed25519_sign_keccak(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf,
mp_raise_ValueError("Unknown hash function"); pk, *(ed25519_signature *)out);
}
} else { } else {
ed25519_publickey(*(const ed25519_secret_key *)sk.buf, pk); mp_raise_ValueError("Unknown hash function");
ed25519_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, pk, *(ed25519_signature *)out);
} }
} else {
ed25519_publickey(*(const ed25519_secret_key *)sk.buf, pk);
ed25519_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, pk,
*(ed25519_signature *)out);
}
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_ed25519_sign_obj, 2, 3, mod_trezorcrypto_ed25519_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_ed25519_sign_obj, 2,
3, mod_trezorcrypto_ed25519_sign);
/// def sign_ext(secret_key: bytes, secret_extension: bytes, message: bytes) -> bytes: /// def sign_ext(secret_key: bytes, secret_extension: bytes, message: bytes) ->
/// bytes:
/// ''' /// '''
/// Uses secret key to produce the cardano signature of message. /// Uses secret key to produce the cardano signature of message.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_key, mp_obj_t secret_extension, mp_obj_t message) { STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_key,
mp_buffer_info_t sk, skext, msg; mp_obj_t secret_extension,
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_obj_t message) {
mp_get_buffer_raise(secret_extension, &skext, MP_BUFFER_READ); mp_buffer_info_t sk, skext, msg;
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(secret_extension, &skext, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
} if (sk.len != 32) {
if (skext.len != 32) { mp_raise_ValueError("Invalid length of secret key");
mp_raise_ValueError("Invalid length of secret key extension"); }
} if (skext.len != 32) {
if (msg.len == 0) { mp_raise_ValueError("Invalid length of secret key extension");
mp_raise_ValueError("Empty data to sign"); }
} if (msg.len == 0) {
ed25519_public_key pk; mp_raise_ValueError("Empty data to sign");
}
ed25519_public_key pk;
ed25519_publickey_ext(*(const ed25519_secret_key *)sk.buf, *(const ed25519_secret_key *)skext.buf, pk); ed25519_publickey_ext(*(const ed25519_secret_key *)sk.buf,
uint8_t out[64]; *(const ed25519_secret_key *)skext.buf, pk);
ed25519_sign_ext(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, *(const ed25519_secret_key *)skext.buf, pk, *(ed25519_signature *)out); uint8_t out[64];
return mp_obj_new_bytes(out, sizeof(out)); ed25519_sign_ext(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf,
*(const ed25519_secret_key *)skext.buf, pk,
*(ed25519_signature *)out);
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_ed25519_sign_ext_obj, mod_trezorcrypto_ed25519_sign_ext); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_ed25519_sign_ext_obj,
mod_trezorcrypto_ed25519_sign_ext);
/// def verify(public_key: bytes, signature: bytes, message: bytes) -> bool: /// def verify(public_key: bytes, signature: bytes, message: bytes) -> bool:
/// ''' /// '''
/// Uses public key to verify the signature of the message. /// Uses public key to verify the signature of the message.
/// Returns True on success. /// Returns True on success.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_verify(mp_obj_t public_key, mp_obj_t signature, mp_obj_t message) { STATIC mp_obj_t mod_trezorcrypto_ed25519_verify(mp_obj_t public_key,
mp_buffer_info_t pk, sig, msg; mp_obj_t signature,
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_obj_t message) {
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ); mp_buffer_info_t pk, sig, msg;
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (pk.len != 32) { mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of public key"); mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
} if (pk.len != 32) {
if (sig.len != 64) { mp_raise_ValueError("Invalid length of public key");
mp_raise_ValueError("Invalid length of signature"); }
} if (sig.len != 64) {
if (msg.len == 0) { mp_raise_ValueError("Invalid length of signature");
mp_raise_ValueError("Empty data to verify"); }
} if (msg.len == 0) {
return (0 == ed25519_sign_open(msg.buf, msg.len, *(const ed25519_public_key *)pk.buf, *(const ed25519_signature *)sig.buf)) ? mp_const_true : mp_const_false; mp_raise_ValueError("Empty data to verify");
}
return (0 == ed25519_sign_open(msg.buf, msg.len,
*(const ed25519_public_key *)pk.buf,
*(const ed25519_signature *)sig.buf))
? mp_const_true
: mp_const_false;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_ed25519_verify_obj, mod_trezorcrypto_ed25519_verify); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_ed25519_verify_obj,
mod_trezorcrypto_ed25519_verify);
/// def cosi_combine_publickeys(public_keys: List[bytes]) -> bytes: /// def cosi_combine_publickeys(public_keys: List[bytes]) -> bytes:
/// ''' /// '''
/// Combines a list of public keys used in COSI cosigning scheme. /// Combines a list of public keys used in COSI cosigning scheme.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_combine_publickeys(mp_obj_t public_keys) { STATIC mp_obj_t
size_t pklen; mod_trezorcrypto_ed25519_cosi_combine_publickeys(mp_obj_t public_keys) {
mp_obj_t *pkitems; size_t pklen;
mp_obj_get_array(public_keys, &pklen, &pkitems); mp_obj_t *pkitems;
if (pklen > 15) { mp_obj_get_array(public_keys, &pklen, &pkitems);
mp_raise_ValueError("Can't combine more than 15 public keys"); if (pklen > 15) {
} mp_raise_ValueError("Can't combine more than 15 public keys");
mp_buffer_info_t buf; }
ed25519_public_key pks[pklen]; mp_buffer_info_t buf;
for (int i = 0; i < pklen; i++) { ed25519_public_key pks[pklen];
mp_get_buffer_raise(pkitems[i], &buf, MP_BUFFER_READ); for (int i = 0; i < pklen; i++) {
if (buf.len != 32) { mp_get_buffer_raise(pkitems[i], &buf, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of public key"); if (buf.len != 32) {
} mp_raise_ValueError("Invalid length of public key");
memcpy(pks[i], buf.buf, buf.len);
} }
uint8_t out[32]; memcpy(pks[i], buf.buf, buf.len);
if (0 != ed25519_cosi_combine_publickeys(*(ed25519_public_key *)out, pks, pklen)) { }
mp_raise_ValueError("Error combining public keys"); uint8_t out[32];
} if (0 !=
return mp_obj_new_bytes(out, sizeof(out)); ed25519_cosi_combine_publickeys(*(ed25519_public_key *)out, pks, pklen)) {
mp_raise_ValueError("Error combining public keys");
}
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj, mod_trezorcrypto_ed25519_cosi_combine_publickeys); STATIC MP_DEFINE_CONST_FUN_OBJ_1(
mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj,
mod_trezorcrypto_ed25519_cosi_combine_publickeys);
/// def cosi_combine_signatures(R: bytes, signatures: List[bytes]) -> bytes: /// def cosi_combine_signatures(R: bytes, signatures: List[bytes]) -> bytes:
/// ''' /// '''
/// Combines a list of signatures used in COSI cosigning scheme. /// Combines a list of signatures used in COSI cosigning scheme.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_combine_signatures(mp_obj_t R, mp_obj_t signatures) { STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_combine_signatures(
mp_buffer_info_t sigR; mp_obj_t R, mp_obj_t signatures) {
mp_get_buffer_raise(R, &sigR, MP_BUFFER_READ); mp_buffer_info_t sigR;
if (sigR.len != 32) { mp_get_buffer_raise(R, &sigR, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of R"); if (sigR.len != 32) {
} mp_raise_ValueError("Invalid length of R");
size_t siglen; }
mp_obj_t *sigitems; size_t siglen;
mp_obj_get_array(signatures, &siglen, &sigitems); mp_obj_t *sigitems;
if (siglen > 15) { mp_obj_get_array(signatures, &siglen, &sigitems);
mp_raise_ValueError("Can't combine more than 15 COSI signatures"); if (siglen > 15) {
mp_raise_ValueError("Can't combine more than 15 COSI signatures");
}
mp_buffer_info_t buf;
ed25519_cosi_signature sigs[siglen];
for (int i = 0; i < siglen; i++) {
mp_get_buffer_raise(sigitems[i], &buf, MP_BUFFER_READ);
if (buf.len != 32) {
mp_raise_ValueError("Invalid length of COSI signature");
} }
mp_buffer_info_t buf; memcpy(sigs[i], buf.buf, buf.len);
ed25519_cosi_signature sigs[siglen]; }
for (int i = 0; i < siglen; i++) { uint8_t out[64];
mp_get_buffer_raise(sigitems[i], &buf, MP_BUFFER_READ); ed25519_cosi_combine_signatures(*(ed25519_signature *)out,
if (buf.len != 32) { *(const ed25519_public_key *)sigR.buf, sigs,
mp_raise_ValueError("Invalid length of COSI signature"); siglen);
} return mp_obj_new_bytes(out, sizeof(out));
memcpy(sigs[i], buf.buf, buf.len);
}
uint8_t out[64];
ed25519_cosi_combine_signatures(*(ed25519_signature *)out, *(const ed25519_public_key *)sigR.buf, sigs, siglen);
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_ed25519_cosi_combine_signatures_obj, mod_trezorcrypto_ed25519_cosi_combine_signatures); STATIC MP_DEFINE_CONST_FUN_OBJ_2(
mod_trezorcrypto_ed25519_cosi_combine_signatures_obj,
mod_trezorcrypto_ed25519_cosi_combine_signatures);
/// def cosi_sign(secret_key: bytes, message: bytes, nonce: bytes, sigR: bytes, combined_pubkey: bytes) -> bytes: /// def cosi_sign(secret_key: bytes, message: bytes, nonce: bytes, sigR: bytes,
/// combined_pubkey: bytes) -> bytes:
/// ''' /// '''
/// Produce signature of message using COSI cosigning scheme. /// Produce signature of message using COSI cosigning scheme.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args,
mp_buffer_info_t sk, msg, nonce, sigR, pk; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk, msg, nonce, sigR, pk;
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[2], &nonce, MP_BUFFER_READ); mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
mp_get_buffer_raise(args[3], &sigR, MP_BUFFER_READ); mp_get_buffer_raise(args[2], &nonce, MP_BUFFER_READ);
mp_get_buffer_raise(args[4], &pk, MP_BUFFER_READ); mp_get_buffer_raise(args[3], &sigR, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(args[4], &pk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (nonce.len != 32) { }
mp_raise_ValueError("Invalid length of nonce"); if (nonce.len != 32) {
} mp_raise_ValueError("Invalid length of nonce");
if (sigR.len != 32) { }
mp_raise_ValueError("Invalid length of R"); if (sigR.len != 32) {
} mp_raise_ValueError("Invalid length of R");
if (pk.len != 32) { }
mp_raise_ValueError("Invalid length of aggregated public key"); if (pk.len != 32) {
} mp_raise_ValueError("Invalid length of aggregated public key");
uint8_t out[32]; }
ed25519_cosi_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, *(const ed25519_secret_key *)nonce.buf, *(const ed25519_public_key *)sigR.buf, *(const ed25519_secret_key *)pk.buf, *(ed25519_cosi_signature *)out); uint8_t out[32];
return mp_obj_new_bytes(out, sizeof(out)); ed25519_cosi_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf,
*(const ed25519_secret_key *)nonce.buf,
*(const ed25519_public_key *)sigR.buf,
*(const ed25519_secret_key *)pk.buf,
*(ed25519_cosi_signature *)out);
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_ed25519_cosi_sign_obj, 5, 5, mod_trezorcrypto_ed25519_cosi_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorcrypto_ed25519_cosi_sign_obj, 5, 5,
mod_trezorcrypto_ed25519_cosi_sign);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_ed25519_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_ed25519_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ed25519) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ed25519)},
{ MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_trezorcrypto_ed25519_generate_secret_obj) }, {MP_ROM_QSTR(MP_QSTR_generate_secret),
{ MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_trezorcrypto_ed25519_publickey_obj) }, MP_ROM_PTR(&mod_trezorcrypto_ed25519_generate_secret_obj)},
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_obj) }, {MP_ROM_QSTR(MP_QSTR_publickey),
{ MP_ROM_QSTR(MP_QSTR_sign_ext), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_ext_obj) }, MP_ROM_PTR(&mod_trezorcrypto_ed25519_publickey_obj)},
{ MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_trezorcrypto_ed25519_verify_obj) }, {MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_obj)},
{ MP_ROM_QSTR(MP_QSTR_cosi_combine_publickeys), MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj) }, {MP_ROM_QSTR(MP_QSTR_sign_ext),
{ MP_ROM_QSTR(MP_QSTR_cosi_combine_signatures), MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_signatures_obj) }, MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_ext_obj)},
{ MP_ROM_QSTR(MP_QSTR_cosi_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_sign_obj) }, {MP_ROM_QSTR(MP_QSTR_verify),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_verify_obj)},
{MP_ROM_QSTR(MP_QSTR_cosi_combine_publickeys),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj)},
{MP_ROM_QSTR(MP_QSTR_cosi_combine_signatures),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_signatures_obj)},
{MP_ROM_QSTR(MP_QSTR_cosi_sign),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_sign_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_ed25519_globals, mod_trezorcrypto_ed25519_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_ed25519_globals,
mod_trezorcrypto_ed25519_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_ed25519_module = { STATIC const mp_obj_module_t mod_trezorcrypto_ed25519_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_ed25519_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_ed25519_globals,
}; };

@ -32,76 +32,90 @@
/// GROESTL512 context. /// GROESTL512 context.
/// ''' /// '''
typedef struct _mp_obj_Groestl512_t { typedef struct _mp_obj_Groestl512_t {
mp_obj_base_t base; mp_obj_base_t base;
GROESTL512_CTX ctx; GROESTL512_CTX ctx;
} mp_obj_Groestl512_t; } mp_obj_Groestl512_t;
STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self,
mp_obj_t data);
/// def __init__(self, data: bytes = None) -> None: /// def __init__(self, data: bytes = None) -> None:
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Groestl512_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Groestl512_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Groestl512_t *o = m_new_obj(mp_obj_Groestl512_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
groestl512_Init(&(o->ctx)); mp_obj_Groestl512_t *o = m_new_obj(mp_obj_Groestl512_t);
if (n_args == 1) { o->base.type = type;
mod_trezorcrypto_Groestl512_update(MP_OBJ_FROM_PTR(o), args[0]); groestl512_Init(&(o->ctx));
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Groestl512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
/// ''' /// '''
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self,
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self); mp_obj_t data) {
mp_buffer_info_t msg; mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_buffer_info_t msg;
if (msg.len > 0) { mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
groestl512_Update(&(o->ctx), msg.buf, msg.len); if (msg.len > 0) {
} groestl512_Update(&(o->ctx), msg.buf, msg.len);
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Groestl512_update_obj, mod_trezorcrypto_Groestl512_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Groestl512_update_obj,
mod_trezorcrypto_Groestl512_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Groestl512_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Groestl512_digest(mp_obj_t self) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[GROESTL512_DIGEST_LENGTH]; uint8_t out[GROESTL512_DIGEST_LENGTH];
GROESTL512_CTX ctx; GROESTL512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(GROESTL512_CTX)); memcpy(&ctx, &(o->ctx), sizeof(GROESTL512_CTX));
groestl512_Final(&ctx, out); groestl512_Final(&ctx, out);
memzero(&ctx, sizeof(GROESTL512_CTX)); memzero(&ctx, sizeof(GROESTL512_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Groestl512_digest_obj, mod_trezorcrypto_Groestl512_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Groestl512_digest_obj,
mod_trezorcrypto_Groestl512_digest);
STATIC mp_obj_t mod_trezorcrypto_Groestl512___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Groestl512___del__(mp_obj_t self) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(GROESTL512_CTX)); memzero(&(o->ctx), sizeof(GROESTL512_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Groestl512___del___obj, mod_trezorcrypto_Groestl512___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Groestl512___del___obj,
mod_trezorcrypto_Groestl512___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Groestl512_locals_dict_table[] = { STATIC const mp_rom_map_elem_t
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Groestl512_update_obj) }, mod_trezorcrypto_Groestl512_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Groestl512_digest_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Groestl512___del___obj) }, MP_ROM_PTR(&mod_trezorcrypto_Groestl512_update_obj)},
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(GROESTL512_BLOCK_LENGTH) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(GROESTL512_DIGEST_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Groestl512_digest_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Groestl512___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(GROESTL512_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(GROESTL512_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Groestl512_locals_dict, mod_trezorcrypto_Groestl512_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Groestl512_locals_dict,
mod_trezorcrypto_Groestl512_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Groestl512_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Groestl512_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Groestl512, .name = MP_QSTR_Groestl512,
.make_new = mod_trezorcrypto_Groestl512_make_new, .make_new = mod_trezorcrypto_Groestl512_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Groestl512_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Groestl512_locals_dict,
}; };

File diff suppressed because it is too large Load Diff

@ -29,43 +29,51 @@
/// ''' /// '''
/// Validate a NEM address /// Validate a NEM address
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nem_validate_address(mp_obj_t address, mp_obj_t network) { STATIC mp_obj_t mod_trezorcrypto_nem_validate_address(mp_obj_t address,
mp_obj_t network) {
mp_buffer_info_t addr;
mp_get_buffer_raise(address, &addr, MP_BUFFER_READ);
mp_buffer_info_t addr; uint32_t n = trezor_obj_get_uint(network);
mp_get_buffer_raise(address, &addr, MP_BUFFER_READ); return mp_obj_new_bool(nem_validate_address(addr.buf, n));
uint32_t n = trezor_obj_get_uint(network);
return mp_obj_new_bool(nem_validate_address(addr.buf, n));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nem_validate_address_obj, mod_trezorcrypto_nem_validate_address); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nem_validate_address_obj,
mod_trezorcrypto_nem_validate_address);
/// def compute_address(public_key: bytes, network: int) -> str: /// def compute_address(public_key: bytes, network: int) -> str:
/// ''' /// '''
/// Compute a NEM address from a public key /// Compute a NEM address from a public key
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nem_compute_address(mp_obj_t public_key, mp_obj_t network) { STATIC mp_obj_t mod_trezorcrypto_nem_compute_address(mp_obj_t public_key,
mp_buffer_info_t p; mp_obj_t network) {
mp_get_buffer_raise(public_key, &p, MP_BUFFER_READ); mp_buffer_info_t p;
mp_get_buffer_raise(public_key, &p, MP_BUFFER_READ);
uint32_t n = trezor_obj_get_uint(network); uint32_t n = trezor_obj_get_uint(network);
char address[NEM_ADDRESS_SIZE + 1]; // + 1 for the 0 byte char address[NEM_ADDRESS_SIZE + 1]; // + 1 for the 0 byte
if (!nem_get_address(p.buf, n, address)) { if (!nem_get_address(p.buf, n, address)) {
mp_raise_ValueError("Failed to compute a NEM address from provided public key"); mp_raise_ValueError(
} "Failed to compute a NEM address from provided public key");
return mp_obj_new_str_of_type(&mp_type_str, (const uint8_t *)address, strlen(address)); }
return mp_obj_new_str_of_type(&mp_type_str, (const uint8_t *)address,
strlen(address));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nem_compute_address_obj, mod_trezorcrypto_nem_compute_address); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nem_compute_address_obj,
mod_trezorcrypto_nem_compute_address);
// objects definition // objects definition
STATIC const mp_rom_map_elem_t mod_trezorcrypto_nem_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_nem_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_validate_address), MP_ROM_PTR(&mod_trezorcrypto_nem_validate_address_obj) }, {MP_ROM_QSTR(MP_QSTR_validate_address),
{ MP_ROM_QSTR(MP_QSTR_compute_address), MP_ROM_PTR(&mod_trezorcrypto_nem_compute_address_obj) }, MP_ROM_PTR(&mod_trezorcrypto_nem_validate_address_obj)},
{MP_ROM_QSTR(MP_QSTR_compute_address),
MP_ROM_PTR(&mod_trezorcrypto_nem_compute_address_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_nem_globals, mod_trezorcrypto_nem_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_nem_globals,
mod_trezorcrypto_nem_globals_table);
// module definition // module definition
STATIC const mp_obj_module_t mod_trezorcrypto_nem_module = { STATIC const mp_obj_module_t mod_trezorcrypto_nem_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_nem_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_nem_globals,
}; };

@ -29,158 +29,199 @@
/// Generate secret key. /// Generate secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_generate_secret() { STATIC mp_obj_t mod_trezorcrypto_nist256p1_generate_secret() {
uint8_t out[32]; uint8_t out[32];
for (;;) { for (;;) {
random_buffer(out, 32); random_buffer(out, 32);
// check whether secret > 0 && secret < curve_order // check whether secret > 0 && secret < curve_order
if (0 == memcmp(out, "\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)) continue; if (0 ==
if (0 <= memcmp(out, "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51", 32)) continue; memcmp(
break; out,
} "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
return mp_obj_new_bytes(out, sizeof(out)); "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
32))
continue;
if (0 <=
memcmp(
out,
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
"\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51",
32))
continue;
break;
}
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_nist256p1_generate_secret_obj, mod_trezorcrypto_nist256p1_generate_secret); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_nist256p1_generate_secret_obj,
mod_trezorcrypto_nist256p1_generate_secret);
/// def publickey(secret_key: bytes, compressed: bool = True) -> bytes: /// def publickey(secret_key: bytes, compressed: bool = True) -> bytes:
/// ''' /// '''
/// Computes public key from secret key. /// Computes public key from secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_publickey(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_nist256p1_publickey(size_t n_args,
mp_buffer_info_t sk; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk;
if (sk.len != 32) { mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
bool compressed = n_args < 2 || args[1] == mp_const_true; }
if (compressed) { bool compressed = n_args < 2 || args[1] == mp_const_true;
uint8_t out[33]; if (compressed) {
ecdsa_get_public_key33(&nist256p1, (const uint8_t *)sk.buf, out); uint8_t out[33];
return mp_obj_new_bytes(out, sizeof(out)); ecdsa_get_public_key33(&nist256p1, (const uint8_t *)sk.buf, out);
} else { return mp_obj_new_bytes(out, sizeof(out));
uint8_t out[65]; } else {
ecdsa_get_public_key65(&nist256p1, (const uint8_t *)sk.buf, out); uint8_t out[65];
return mp_obj_new_bytes(out, sizeof(out)); ecdsa_get_public_key65(&nist256p1, (const uint8_t *)sk.buf, out);
} return mp_obj_new_bytes(out, sizeof(out));
}
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_nist256p1_publickey_obj, 1, 2, mod_trezorcrypto_nist256p1_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorcrypto_nist256p1_publickey_obj, 1, 2,
mod_trezorcrypto_nist256p1_publickey);
/// def sign(secret_key: bytes, digest: bytes, compressed: bool = True) -> bytes: /// def sign(secret_key: bytes, digest: bytes, compressed: bool = True) ->
/// bytes:
/// ''' /// '''
/// Uses secret key to produce the signature of the digest. /// Uses secret key to produce the signature of the digest.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_sign(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_nist256p1_sign(size_t n_args,
mp_buffer_info_t sk, dig; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
bool compressed = n_args < 3 || args[2] == mp_const_true; mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
if (sk.len != 32) { bool compressed = n_args < 3 || args[2] == mp_const_true;
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); if (dig.len != 32) {
} mp_raise_ValueError("Invalid length of digest");
uint8_t out[65], pby; }
if (0 != ecdsa_sign_digest(&nist256p1, (const uint8_t *)sk.buf, (const uint8_t *)dig.buf, out + 1, &pby, NULL)) { uint8_t out[65], pby;
mp_raise_ValueError("Signing failed"); if (0 != ecdsa_sign_digest(&nist256p1, (const uint8_t *)sk.buf,
} (const uint8_t *)dig.buf, out + 1, &pby, NULL)) {
out[0] = 27 + pby + compressed * 4; mp_raise_ValueError("Signing failed");
return mp_obj_new_bytes(out, sizeof(out)); }
out[0] = 27 + pby + compressed * 4;
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_nist256p1_sign_obj, 2, 3, mod_trezorcrypto_nist256p1_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_nist256p1_sign_obj,
2, 3,
mod_trezorcrypto_nist256p1_sign);
/// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool: /// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
/// ''' /// '''
/// Uses public key to verify the signature of the digest. /// Uses public key to verify the signature of the digest.
/// Returns True on success. /// Returns True on success.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_verify(mp_obj_t public_key, mp_obj_t signature, mp_obj_t digest) { STATIC mp_obj_t mod_trezorcrypto_nist256p1_verify(mp_obj_t public_key,
mp_buffer_info_t pk, sig, dig; mp_obj_t signature,
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_obj_t digest) {
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ); mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ); mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) { mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of public key"); mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
} if (pk.len != 33 && pk.len != 65) {
if (sig.len != 64 && sig.len != 65) { mp_raise_ValueError("Invalid length of public key");
mp_raise_ValueError("Invalid length of signature"); }
} if (sig.len != 64 && sig.len != 65) {
int offset = sig.len - 64; mp_raise_ValueError("Invalid length of signature");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); int offset = sig.len - 64;
} if (dig.len != 32) {
return mp_obj_new_bool(0 == ecdsa_verify_digest(&nist256p1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf + offset, (const uint8_t *)dig.buf)); mp_raise_ValueError("Invalid length of digest");
}
return mp_obj_new_bool(
0 == ecdsa_verify_digest(&nist256p1, (const uint8_t *)pk.buf,
(const uint8_t *)sig.buf + offset,
(const uint8_t *)dig.buf));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_nist256p1_verify_obj, mod_trezorcrypto_nist256p1_verify); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_nist256p1_verify_obj,
mod_trezorcrypto_nist256p1_verify);
/// def verify_recover(signature: bytes, digest: bytes) -> bytes: /// def verify_recover(signature: bytes, digest: bytes) -> bytes:
/// ''' /// '''
/// Uses signature of the digest to verify the digest and recover the public key. /// Uses signature of the digest to verify the digest and recover the public
/// Returns public key on success, None on failure. /// key. Returns public key on success, None on failure.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_verify_recover(mp_obj_t signature, mp_obj_t digest) { STATIC mp_obj_t mod_trezorcrypto_nist256p1_verify_recover(mp_obj_t signature,
mp_buffer_info_t sig, dig; mp_obj_t digest) {
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ); mp_buffer_info_t sig, dig;
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ); mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
if (sig.len != 65) { mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of signature"); if (sig.len != 65) {
} mp_raise_ValueError("Invalid length of signature");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); if (dig.len != 32) {
} mp_raise_ValueError("Invalid length of digest");
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27; }
if (recid >= 8) { uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
mp_raise_ValueError("Invalid recid in signature"); if (recid >= 8) {
} mp_raise_ValueError("Invalid recid in signature");
bool compressed = (recid >= 4); }
recid &= 3; bool compressed = (recid >= 4);
uint8_t out[65]; recid &= 3;
if (0 == ecdsa_recover_pub_from_sig(&nist256p1, out, (const uint8_t *)sig.buf + 1, (const uint8_t *)dig.buf, recid)) { uint8_t out[65];
if (compressed) { if (0 == ecdsa_recover_pub_from_sig(&nist256p1, out,
out[0] = 0x02 | (out[64] & 1); (const uint8_t *)sig.buf + 1,
return mp_obj_new_bytes(out, 33); (const uint8_t *)dig.buf, recid)) {
} if (compressed) {
return mp_obj_new_bytes(out, sizeof(out)); out[0] = 0x02 | (out[64] & 1);
} else { return mp_obj_new_bytes(out, 33);
return mp_const_none;
} }
return mp_obj_new_bytes(out, sizeof(out));
} else {
return mp_const_none;
}
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nist256p1_verify_recover_obj, mod_trezorcrypto_nist256p1_verify_recover); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nist256p1_verify_recover_obj,
mod_trezorcrypto_nist256p1_verify_recover);
/// def multiply(secret_key: bytes, public_key: bytes) -> bytes: /// def multiply(secret_key: bytes, public_key: bytes) -> bytes:
/// ''' /// '''
/// Multiplies point defined by public_key with scalar defined by secret_key. /// Multiplies point defined by public_key with scalar defined by
/// Useful for ECDH. /// secret_key. Useful for ECDH.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_multiply(mp_obj_t secret_key, mp_obj_t public_key) { STATIC mp_obj_t mod_trezorcrypto_nist256p1_multiply(mp_obj_t secret_key,
mp_buffer_info_t sk, pk; mp_obj_t public_key) {
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_buffer_info_t sk, pk;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (pk.len != 33 && pk.len != 65) { }
mp_raise_ValueError("Invalid length of public key"); if (pk.len != 33 && pk.len != 65) {
} mp_raise_ValueError("Invalid length of public key");
uint8_t out[65]; }
if (0 != ecdh_multiply(&nist256p1, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf, out)) { uint8_t out[65];
mp_raise_ValueError("Multiply failed"); if (0 != ecdh_multiply(&nist256p1, (const uint8_t *)sk.buf,
} (const uint8_t *)pk.buf, out)) {
return mp_obj_new_bytes(out, sizeof(out)); mp_raise_ValueError("Multiply failed");
}
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nist256p1_multiply_obj, mod_trezorcrypto_nist256p1_multiply); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_nist256p1_multiply_obj,
mod_trezorcrypto_nist256p1_multiply);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_nist256p1_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_nist256p1_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_nist256p1) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_nist256p1)},
{ MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_generate_secret_obj) }, {MP_ROM_QSTR(MP_QSTR_generate_secret),
{ MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_publickey_obj) }, MP_ROM_PTR(&mod_trezorcrypto_nist256p1_generate_secret_obj)},
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_sign_obj) }, {MP_ROM_QSTR(MP_QSTR_publickey),
{ MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_verify_obj) }, MP_ROM_PTR(&mod_trezorcrypto_nist256p1_publickey_obj)},
{ MP_ROM_QSTR(MP_QSTR_verify_recover), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_verify_recover_obj) }, {MP_ROM_QSTR(MP_QSTR_sign),
{ MP_ROM_QSTR(MP_QSTR_multiply), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_multiply_obj) }, MP_ROM_PTR(&mod_trezorcrypto_nist256p1_sign_obj)},
{MP_ROM_QSTR(MP_QSTR_verify),
MP_ROM_PTR(&mod_trezorcrypto_nist256p1_verify_obj)},
{MP_ROM_QSTR(MP_QSTR_verify_recover),
MP_ROM_PTR(&mod_trezorcrypto_nist256p1_verify_recover_obj)},
{MP_ROM_QSTR(MP_QSTR_multiply),
MP_ROM_PTR(&mod_trezorcrypto_nist256p1_multiply_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_nist256p1_globals, mod_trezorcrypto_nist256p1_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_nist256p1_globals,
mod_trezorcrypto_nist256p1_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_nist256p1_module = { STATIC const mp_obj_module_t mod_trezorcrypto_nist256p1_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_nist256p1_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_nist256p1_globals,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "pbkdf2.h"
#include "memzero.h" #include "memzero.h"
#include "pbkdf2.h"
#define PRF_HMAC_SHA256 256 #define PRF_HMAC_SHA256 256
#define PRF_HMAC_SHA512 512 #define PRF_HMAC_SHA512 512
@ -32,121 +32,132 @@
/// PBKDF2 context. /// PBKDF2 context.
/// ''' /// '''
typedef struct _mp_obj_Pbkdf2_t { typedef struct _mp_obj_Pbkdf2_t {
mp_obj_base_t base; mp_obj_base_t base;
union { union {
PBKDF2_HMAC_SHA256_CTX ctx256; PBKDF2_HMAC_SHA256_CTX ctx256;
PBKDF2_HMAC_SHA512_CTX ctx512; PBKDF2_HMAC_SHA512_CTX ctx512;
}; };
uint32_t prf; uint32_t prf;
} mp_obj_Pbkdf2_t; } mp_obj_Pbkdf2_t;
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self, mp_obj_t data);
/// def __init__(self, prf: int, password: bytes, salt: bytes, iterations: int = None, blocknr: int = 1) -> None: /// def __init__(self, prf: int, password: bytes, salt: bytes, iterations: int =
/// None, blocknr: int = 1) -> None:
/// ''' /// '''
/// Create a PBKDF2 context. /// Create a PBKDF2 context.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 3, 4, false); size_t n_args, size_t n_kw,
mp_obj_Pbkdf2_t *o = m_new_obj(mp_obj_Pbkdf2_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 3, 4, false);
mp_obj_Pbkdf2_t *o = m_new_obj(mp_obj_Pbkdf2_t);
mp_buffer_info_t password; o->base.type = type;
mp_get_buffer_raise(args[1], &password, MP_BUFFER_READ);
mp_buffer_info_t salt; mp_buffer_info_t password;
mp_get_buffer_raise(args[2], &salt, MP_BUFFER_READ); mp_get_buffer_raise(args[1], &password, MP_BUFFER_READ);
mp_buffer_info_t salt;
if (password.len == 0) { mp_get_buffer_raise(args[2], &salt, MP_BUFFER_READ);
password.buf = "";
} if (password.len == 0) {
if (salt.len == 0) { password.buf = "";
salt.buf = ""; }
} if (salt.len == 0) {
salt.buf = "";
uint32_t blocknr = 1; }
if (n_args > 4) { // blocknr is set
blocknr = trezor_obj_get_uint(args[4]); uint32_t blocknr = 1;
} if (n_args > 4) { // blocknr is set
blocknr = trezor_obj_get_uint(args[4]);
o->prf = trezor_obj_get_uint(args[0]); }
if (o->prf == PRF_HMAC_SHA256) {
pbkdf2_hmac_sha256_Init(&(o->ctx256), password.buf, password.len, salt.buf, salt.len, blocknr); o->prf = trezor_obj_get_uint(args[0]);
} else if (o->prf == PRF_HMAC_SHA256) {
if (o->prf == PRF_HMAC_SHA512) { pbkdf2_hmac_sha256_Init(&(o->ctx256), password.buf, password.len, salt.buf,
pbkdf2_hmac_sha512_Init(&(o->ctx512), password.buf, password.len, salt.buf, salt.len, blocknr); salt.len, blocknr);
} else { } else if (o->prf == PRF_HMAC_SHA512) {
mp_raise_ValueError("Invalid PRF"); pbkdf2_hmac_sha512_Init(&(o->ctx512), password.buf, password.len, salt.buf,
} salt.len, blocknr);
// constructor called with iterations as fourth parameter } else {
if (n_args > 3) { mp_raise_ValueError("Invalid PRF");
mod_trezorcrypto_Pbkdf2_update(MP_OBJ_FROM_PTR(o), args[3]); }
} // constructor called with iterations as fourth parameter
return MP_OBJ_FROM_PTR(o); if (n_args > 3) {
mod_trezorcrypto_Pbkdf2_update(MP_OBJ_FROM_PTR(o), args[3]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, iterations: int) -> None: /// def update(self, iterations: int) -> None:
/// ''' /// '''
/// Update a PBKDF2 context. /// Update a PBKDF2 context.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self, mp_obj_t iterations) { STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self,
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self); mp_obj_t iterations) {
uint32_t iter = trezor_obj_get_uint(iterations); mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
if (o->prf == PRF_HMAC_SHA256) { uint32_t iter = trezor_obj_get_uint(iterations);
pbkdf2_hmac_sha256_Update(&(o->ctx256), iter); if (o->prf == PRF_HMAC_SHA256) {
} pbkdf2_hmac_sha256_Update(&(o->ctx256), iter);
if (o->prf == PRF_HMAC_SHA512) { }
pbkdf2_hmac_sha512_Update(&(o->ctx512), iter); if (o->prf == PRF_HMAC_SHA512) {
} pbkdf2_hmac_sha512_Update(&(o->ctx512), iter);
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Pbkdf2_update_obj, mod_trezorcrypto_Pbkdf2_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Pbkdf2_update_obj,
mod_trezorcrypto_Pbkdf2_update);
/// def key(self) -> bytes: /// def key(self) -> bytes:
/// ''' /// '''
/// Retrieve derived key. /// Retrieve derived key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_key(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_key(mp_obj_t self) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self); mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
if (o->prf == PRF_HMAC_SHA256) { if (o->prf == PRF_HMAC_SHA256) {
PBKDF2_HMAC_SHA256_CTX ctx; PBKDF2_HMAC_SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX)); memcpy(&ctx, &(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
uint8_t out[SHA256_DIGEST_LENGTH]; uint8_t out[SHA256_DIGEST_LENGTH];
pbkdf2_hmac_sha256_Final(&ctx, out); pbkdf2_hmac_sha256_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
if (o->prf == PRF_HMAC_SHA512) { if (o->prf == PRF_HMAC_SHA512) {
PBKDF2_HMAC_SHA512_CTX ctx; PBKDF2_HMAC_SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX)); memcpy(&ctx, &(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
uint8_t out[SHA512_DIGEST_LENGTH]; uint8_t out[SHA512_DIGEST_LENGTH];
pbkdf2_hmac_sha512_Final(&ctx, out); pbkdf2_hmac_sha512_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); memzero(&ctx, sizeof(PBKDF2_HMAC_SHA512_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Pbkdf2_key_obj, mod_trezorcrypto_Pbkdf2_key); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Pbkdf2_key_obj,
mod_trezorcrypto_Pbkdf2_key);
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Pbkdf2___del__(mp_obj_t self) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self); mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX)); memzero(&(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
memzero(&(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX)); memzero(&(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Pbkdf2___del___obj, mod_trezorcrypto_Pbkdf2___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Pbkdf2___del___obj,
mod_trezorcrypto_Pbkdf2___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Pbkdf2_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Pbkdf2_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_key), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_key_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2___del___obj) }, {MP_ROM_QSTR(MP_QSTR_key), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_key_obj)},
{ MP_ROM_QSTR(MP_QSTR_HMAC_SHA256), MP_OBJ_NEW_SMALL_INT(PRF_HMAC_SHA256) }, {MP_ROM_QSTR(MP_QSTR___del__),
{ MP_ROM_QSTR(MP_QSTR_HMAC_SHA512), MP_OBJ_NEW_SMALL_INT(PRF_HMAC_SHA512) }, MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2___del___obj)},
{MP_ROM_QSTR(MP_QSTR_HMAC_SHA256), MP_OBJ_NEW_SMALL_INT(PRF_HMAC_SHA256)},
{MP_ROM_QSTR(MP_QSTR_HMAC_SHA512), MP_OBJ_NEW_SMALL_INT(PRF_HMAC_SHA512)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Pbkdf2_locals_dict, mod_trezorcrypto_Pbkdf2_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Pbkdf2_locals_dict,
mod_trezorcrypto_Pbkdf2_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Pbkdf2_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Pbkdf2_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Pbkdf2, .name = MP_QSTR_Pbkdf2,
.make_new = mod_trezorcrypto_Pbkdf2_make_new, .make_new = mod_trezorcrypto_Pbkdf2_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Pbkdf2_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Pbkdf2_locals_dict,
}; };

@ -30,65 +30,72 @@
/// Compute uniform random number from interval 0 ... n - 1. /// Compute uniform random number from interval 0 ... n - 1.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_random_uniform(mp_obj_t n) { STATIC mp_obj_t mod_trezorcrypto_random_uniform(mp_obj_t n) {
uint32_t nn = trezor_obj_get_uint(n); uint32_t nn = trezor_obj_get_uint(n);
if (nn == 0) { if (nn == 0) {
mp_raise_ValueError("Maximum can't be zero"); mp_raise_ValueError("Maximum can't be zero");
} }
return mp_obj_new_int_from_uint(random_uniform(nn)); return mp_obj_new_int_from_uint(random_uniform(nn));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_uniform_obj, mod_trezorcrypto_random_uniform); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_uniform_obj,
mod_trezorcrypto_random_uniform);
/// def bytes(len: int) -> bytes: /// def bytes(len: int) -> bytes:
/// ''' /// '''
/// Generate random bytes sequence of length len. /// Generate random bytes sequence of length len.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_random_bytes(mp_obj_t len) { STATIC mp_obj_t mod_trezorcrypto_random_bytes(mp_obj_t len) {
uint32_t l = trezor_obj_get_uint(len); uint32_t l = trezor_obj_get_uint(len);
if (l > 1024) { if (l > 1024) {
mp_raise_ValueError("Maximum requested size is 1024"); mp_raise_ValueError("Maximum requested size is 1024");
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, l); vstr_init_len(&vstr, l);
random_buffer((uint8_t *)vstr.buf, l); random_buffer((uint8_t *)vstr.buf, l);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_bytes_obj, mod_trezorcrypto_random_bytes); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_bytes_obj,
mod_trezorcrypto_random_bytes);
/// def shuffle(data: list) -> None: /// def shuffle(data: list) -> None:
/// ''' /// '''
/// Shuffles items of given list (in-place). /// Shuffles items of given list (in-place).
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_random_shuffle(mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_random_shuffle(mp_obj_t data) {
size_t count; size_t count;
mp_obj_t *items; mp_obj_t *items;
mp_obj_get_array(data, &count, &items); mp_obj_get_array(data, &count, &items);
if (count > 256) { if (count > 256) {
mp_raise_ValueError("Maximum list size is 256 items"); mp_raise_ValueError("Maximum list size is 256 items");
} }
if (count <= 1) { if (count <= 1) {
return mp_const_none;
}
// Fisher-Yates shuffle
mp_obj_t t;
for (size_t i = count - 1; i >= 1; i--) {
size_t j = random_uniform(i + 1);
t = items[i];
items[i] = items[j];
items[j] = t;
}
return mp_const_none; return mp_const_none;
}
// Fisher-Yates shuffle
mp_obj_t t;
for (size_t i = count - 1; i >= 1; i--) {
size_t j = random_uniform(i + 1);
t = items[i];
items[i] = items[j];
items[j] = t;
}
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_shuffle_obj, mod_trezorcrypto_random_shuffle); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_shuffle_obj,
mod_trezorcrypto_random_shuffle);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_random_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_random_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random)},
{ MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_trezorcrypto_random_uniform_obj) }, {MP_ROM_QSTR(MP_QSTR_uniform),
{ MP_ROM_QSTR(MP_QSTR_bytes), MP_ROM_PTR(&mod_trezorcrypto_random_bytes_obj) }, MP_ROM_PTR(&mod_trezorcrypto_random_uniform_obj)},
{ MP_ROM_QSTR(MP_QSTR_shuffle), MP_ROM_PTR(&mod_trezorcrypto_random_shuffle_obj) }, {MP_ROM_QSTR(MP_QSTR_bytes),
MP_ROM_PTR(&mod_trezorcrypto_random_bytes_obj)},
{MP_ROM_QSTR(MP_QSTR_shuffle),
MP_ROM_PTR(&mod_trezorcrypto_random_shuffle_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_random_globals, mod_trezorcrypto_random_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_random_globals,
mod_trezorcrypto_random_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_random_module = { STATIC const mp_obj_module_t mod_trezorcrypto_random_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_random_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_random_globals,
}; };

@ -28,29 +28,31 @@
/// RFC6979 context. /// RFC6979 context.
/// ''' /// '''
typedef struct _mp_obj_Rfc6979_t { typedef struct _mp_obj_Rfc6979_t {
mp_obj_base_t base; mp_obj_base_t base;
rfc6979_state rng; rfc6979_state rng;
} mp_obj_Rfc6979_t; } mp_obj_Rfc6979_t;
/// def __init__(self, secret_key: bytes, hash: bytes) -> None: /// def __init__(self, secret_key: bytes, hash: bytes) -> None:
/// ''' /// '''
/// Initialize RFC6979 context from secret key and a hash. /// Initialize RFC6979 context from secret key and a hash.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Rfc6979_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Rfc6979_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 2, 2, false); size_t n_args, size_t n_kw,
mp_obj_Rfc6979_t *o = m_new_obj(mp_obj_Rfc6979_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_buffer_info_t pkey, hash; mp_obj_Rfc6979_t *o = m_new_obj(mp_obj_Rfc6979_t);
mp_get_buffer_raise(args[0], &pkey, MP_BUFFER_READ); o->base.type = type;
mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ); mp_buffer_info_t pkey, hash;
if (pkey.len != 32) { mp_get_buffer_raise(args[0], &pkey, MP_BUFFER_READ);
mp_raise_ValueError("Secret key has to be 32 bytes long"); mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ);
} if (pkey.len != 32) {
if (hash.len != 32) { mp_raise_ValueError("Secret key has to be 32 bytes long");
mp_raise_ValueError("Hash has to be 32 bytes long"); }
} if (hash.len != 32) {
init_rfc6979((const uint8_t *)pkey.buf, (const uint8_t *)hash.buf, &(o->rng)); mp_raise_ValueError("Hash has to be 32 bytes long");
return MP_OBJ_FROM_PTR(o); }
init_rfc6979((const uint8_t *)pkey.buf, (const uint8_t *)hash.buf, &(o->rng));
return MP_OBJ_FROM_PTR(o);
} }
/// def next(self) -> bytes: /// def next(self) -> bytes:
@ -58,21 +60,23 @@ STATIC mp_obj_t mod_trezorcrypto_Rfc6979_make_new(const mp_obj_type_t *type, siz
/// Compute next 32-bytes of pseudorandom data. /// Compute next 32-bytes of pseudorandom data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Rfc6979_next(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Rfc6979_next(mp_obj_t self) {
mp_obj_Rfc6979_t *o = MP_OBJ_TO_PTR(self); mp_obj_Rfc6979_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[32]; uint8_t out[32];
generate_rfc6979(out, &(o->rng)); generate_rfc6979(out, &(o->rng));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Rfc6979_next_obj, mod_trezorcrypto_Rfc6979_next); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Rfc6979_next_obj,
mod_trezorcrypto_Rfc6979_next);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Rfc6979_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Rfc6979_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_next_obj) }, {MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_next_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Rfc6979_locals_dict, mod_trezorcrypto_Rfc6979_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Rfc6979_locals_dict,
mod_trezorcrypto_Rfc6979_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Rfc6979_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Rfc6979_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Rfc6979, .name = MP_QSTR_Rfc6979,
.make_new = mod_trezorcrypto_Rfc6979_make_new, .make_new = mod_trezorcrypto_Rfc6979_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Rfc6979_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Rfc6979_locals_dict,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "ripemd160.h"
#include "memzero.h" #include "memzero.h"
#include "ripemd160.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// RIPEMD160 context. /// RIPEMD160 context.
/// ''' /// '''
typedef struct _mp_obj_Ripemd160_t { typedef struct _mp_obj_Ripemd160_t {
mp_obj_base_t base; mp_obj_base_t base;
RIPEMD160_CTX ctx; RIPEMD160_CTX ctx;
} mp_obj_Ripemd160_t; } mp_obj_Ripemd160_t;
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data);
@ -39,67 +39,80 @@ STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Ripemd160_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Ripemd160_t *o = m_new_obj(mp_obj_Ripemd160_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
ripemd160_Init(&(o->ctx)); mp_obj_Ripemd160_t *o = m_new_obj(mp_obj_Ripemd160_t);
// constructor called with bytes/str as first parameter o->base.type = type;
if (n_args == 1) { ripemd160_Init(&(o->ctx));
mod_trezorcrypto_Ripemd160_update(MP_OBJ_FROM_PTR(o), args[0]); // constructor called with bytes/str as first parameter
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Ripemd160_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
/// ''' /// '''
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self,
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); mp_obj_t data) {
mp_buffer_info_t msg; mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_buffer_info_t msg;
if (msg.len > 0) { mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
ripemd160_Update(&(o->ctx), msg.buf, msg.len); if (msg.len > 0) {
} ripemd160_Update(&(o->ctx), msg.buf, msg.len);
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Ripemd160_update_obj, mod_trezorcrypto_Ripemd160_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Ripemd160_update_obj,
mod_trezorcrypto_Ripemd160_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Ripemd160_digest(mp_obj_t self) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[RIPEMD160_DIGEST_LENGTH]; uint8_t out[RIPEMD160_DIGEST_LENGTH];
RIPEMD160_CTX ctx; RIPEMD160_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(RIPEMD160_CTX)); memcpy(&ctx, &(o->ctx), sizeof(RIPEMD160_CTX));
ripemd160_Final(&ctx, out); ripemd160_Final(&ctx, out);
memzero(&ctx, sizeof(RIPEMD160_CTX)); memzero(&ctx, sizeof(RIPEMD160_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160_digest_obj, mod_trezorcrypto_Ripemd160_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160_digest_obj,
mod_trezorcrypto_Ripemd160_digest);
STATIC mp_obj_t mod_trezorcrypto_Ripemd160___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Ripemd160___del__(mp_obj_t self) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(RIPEMD160_CTX)); memzero(&(o->ctx), sizeof(RIPEMD160_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160___del___obj, mod_trezorcrypto_Ripemd160___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160___del___obj,
mod_trezorcrypto_Ripemd160___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Ripemd160_locals_dict_table[] = { STATIC const mp_rom_map_elem_t
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_update_obj) }, mod_trezorcrypto_Ripemd160_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_digest_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Ripemd160___del___obj) }, MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_update_obj)},
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(RIPEMD160_BLOCK_LENGTH) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(RIPEMD160_DIGEST_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_digest_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Ripemd160___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(RIPEMD160_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(RIPEMD160_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Ripemd160_locals_dict, mod_trezorcrypto_Ripemd160_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Ripemd160_locals_dict,
mod_trezorcrypto_Ripemd160_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Ripemd160_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Ripemd160_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Ripemd160, .name = MP_QSTR_Ripemd160,
.make_new = mod_trezorcrypto_Ripemd160_make_new, .make_new = mod_trezorcrypto_Ripemd160_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Ripemd160_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Ripemd160_locals_dict,
}; };

@ -29,176 +29,218 @@
/// Generate secret key. /// Generate secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_generate_secret() { STATIC mp_obj_t mod_trezorcrypto_secp256k1_generate_secret() {
uint8_t out[32]; uint8_t out[32];
for (;;) { for (;;) {
random_buffer(out, 32); random_buffer(out, 32);
// check whether secret > 0 && secret < curve_order // check whether secret > 0 && secret < curve_order
if (0 == memcmp(out, "\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)) continue; if (0 ==
if (0 <= memcmp(out, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xBA\xAE\xDC\xE6\xAF\x48\xA0\x3B\xBF\xD2\x5E\x8C\xD0\x36\x41\x41", 32)) continue; memcmp(
break; out,
} "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
return mp_obj_new_bytes(out, sizeof(out)); "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
32))
continue;
if (0 <=
memcmp(
out,
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE"
"\xBA\xAE\xDC\xE6\xAF\x48\xA0\x3B\xBF\xD2\x5E\x8C\xD0\x36\x41\x41",
32))
continue;
break;
}
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_secp256k1_generate_secret_obj, mod_trezorcrypto_secp256k1_generate_secret); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_secp256k1_generate_secret_obj,
mod_trezorcrypto_secp256k1_generate_secret);
/// def publickey(secret_key: bytes, compressed: bool = True) -> bytes: /// def publickey(secret_key: bytes, compressed: bool = True) -> bytes:
/// ''' /// '''
/// Computes public key from secret key. /// Computes public key from secret key.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_publickey(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_secp256k1_publickey(size_t n_args,
mp_buffer_info_t sk; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk;
if (sk.len != 32) { mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
bool compressed = n_args < 2 || args[1] == mp_const_true; }
if (compressed) { bool compressed = n_args < 2 || args[1] == mp_const_true;
uint8_t out[33]; if (compressed) {
ecdsa_get_public_key33(&secp256k1, (const uint8_t *)sk.buf, out); uint8_t out[33];
return mp_obj_new_bytes(out, sizeof(out)); ecdsa_get_public_key33(&secp256k1, (const uint8_t *)sk.buf, out);
} else { return mp_obj_new_bytes(out, sizeof(out));
uint8_t out[65]; } else {
ecdsa_get_public_key65(&secp256k1, (const uint8_t *)sk.buf, out); uint8_t out[65];
return mp_obj_new_bytes(out, sizeof(out)); ecdsa_get_public_key65(&secp256k1, (const uint8_t *)sk.buf, out);
} return mp_obj_new_bytes(out, sizeof(out));
}
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_secp256k1_publickey_obj, 1, 2, mod_trezorcrypto_secp256k1_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorcrypto_secp256k1_publickey_obj, 1, 2,
mod_trezorcrypto_secp256k1_publickey);
static int ethereum_is_canonical(uint8_t v, uint8_t signature[64]) static int ethereum_is_canonical(uint8_t v, uint8_t signature[64]) {
{ (void)signature;
(void)signature; return (v & 2) == 0;
return (v & 2) == 0;
} }
enum { enum {
CANONICAL_SIG_ETHEREUM = 1, CANONICAL_SIG_ETHEREUM = 1,
}; };
/// def sign(secret_key: bytes, digest: bytes, compressed: bool = True, canonical: int = None) -> bytes: /// def sign(secret_key: bytes, digest: bytes, compressed: bool = True,
/// canonical: int = None) -> bytes:
/// ''' /// '''
/// Uses secret key to produce the signature of the digest. /// Uses secret key to produce the signature of the digest.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_sign(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_secp256k1_sign(size_t n_args,
mp_buffer_info_t sk, dig; const mp_obj_t *args) {
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ); mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
bool compressed = (n_args < 3) || (args[2] == mp_const_true); mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
mp_int_t canonical = (n_args > 3) ? mp_obj_get_int(args[3]) : 0; bool compressed = (n_args < 3) || (args[2] == mp_const_true);
int (*is_canonical)(uint8_t by, uint8_t sig[64]) = NULL; mp_int_t canonical = (n_args > 3) ? mp_obj_get_int(args[3]) : 0;
switch (canonical) { int (*is_canonical)(uint8_t by, uint8_t sig[64]) = NULL;
case CANONICAL_SIG_ETHEREUM: switch (canonical) {
is_canonical = ethereum_is_canonical; case CANONICAL_SIG_ETHEREUM:
break; is_canonical = ethereum_is_canonical;
} break;
if (sk.len != 32) { }
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); if (dig.len != 32) {
} mp_raise_ValueError("Invalid length of digest");
uint8_t out[65], pby; }
if (0 != ecdsa_sign_digest(&secp256k1, (const uint8_t *)sk.buf, (const uint8_t *)dig.buf, out + 1, &pby, is_canonical)) { uint8_t out[65], pby;
mp_raise_ValueError("Signing failed"); if (0 != ecdsa_sign_digest(&secp256k1, (const uint8_t *)sk.buf,
} (const uint8_t *)dig.buf, out + 1, &pby,
out[0] = 27 + pby + compressed * 4; is_canonical)) {
return mp_obj_new_bytes(out, sizeof(out)); mp_raise_ValueError("Signing failed");
}
out[0] = 27 + pby + compressed * 4;
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_secp256k1_sign_obj, 2, 4, mod_trezorcrypto_secp256k1_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_secp256k1_sign_obj,
2, 4,
mod_trezorcrypto_secp256k1_sign);
/// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool: /// def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
/// ''' /// '''
/// Uses public key to verify the signature of the digest. /// Uses public key to verify the signature of the digest.
/// Returns True on success. /// Returns True on success.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_verify(mp_obj_t public_key, mp_obj_t signature, mp_obj_t digest) { STATIC mp_obj_t mod_trezorcrypto_secp256k1_verify(mp_obj_t public_key,
mp_buffer_info_t pk, sig, dig; mp_obj_t signature,
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_obj_t digest) {
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ); mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ); mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) { mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of public key"); mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
} if (pk.len != 33 && pk.len != 65) {
if (sig.len != 64 && sig.len != 65) { mp_raise_ValueError("Invalid length of public key");
mp_raise_ValueError("Invalid length of signature"); }
} if (sig.len != 64 && sig.len != 65) {
int offset = sig.len - 64; mp_raise_ValueError("Invalid length of signature");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); int offset = sig.len - 64;
} if (dig.len != 32) {
return mp_obj_new_bool(0 == ecdsa_verify_digest(&secp256k1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf + offset, (const uint8_t *)dig.buf)); mp_raise_ValueError("Invalid length of digest");
}
return mp_obj_new_bool(
0 == ecdsa_verify_digest(&secp256k1, (const uint8_t *)pk.buf,
(const uint8_t *)sig.buf + offset,
(const uint8_t *)dig.buf));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_secp256k1_verify_obj, mod_trezorcrypto_secp256k1_verify); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_secp256k1_verify_obj,
mod_trezorcrypto_secp256k1_verify);
/// def verify_recover(signature: bytes, digest: bytes) -> bytes: /// def verify_recover(signature: bytes, digest: bytes) -> bytes:
/// ''' /// '''
/// Uses signature of the digest to verify the digest and recover the public key. /// Uses signature of the digest to verify the digest and recover the public
/// Returns public key on success, None on failure. /// key. Returns public key on success, None on failure.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_verify_recover(mp_obj_t signature, mp_obj_t digest) { STATIC mp_obj_t mod_trezorcrypto_secp256k1_verify_recover(mp_obj_t signature,
mp_buffer_info_t sig, dig; mp_obj_t digest) {
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ); mp_buffer_info_t sig, dig;
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ); mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
if (sig.len != 65) { mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of signature"); if (sig.len != 65) {
} mp_raise_ValueError("Invalid length of signature");
if (dig.len != 32) { }
mp_raise_ValueError("Invalid length of digest"); if (dig.len != 32) {
} mp_raise_ValueError("Invalid length of digest");
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27; }
if (recid >= 8) { uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
mp_raise_ValueError("Invalid recid in signature"); if (recid >= 8) {
} mp_raise_ValueError("Invalid recid in signature");
bool compressed = (recid >= 4); }
recid &= 3; bool compressed = (recid >= 4);
uint8_t out[65]; recid &= 3;
if (0 == ecdsa_recover_pub_from_sig(&secp256k1, out, (const uint8_t *)sig.buf + 1, (const uint8_t *)dig.buf, recid)) { uint8_t out[65];
if (compressed) { if (0 == ecdsa_recover_pub_from_sig(&secp256k1, out,
out[0] = 0x02 | (out[64] & 1); (const uint8_t *)sig.buf + 1,
return mp_obj_new_bytes(out, 33); (const uint8_t *)dig.buf, recid)) {
} if (compressed) {
return mp_obj_new_bytes(out, sizeof(out)); out[0] = 0x02 | (out[64] & 1);
} else { return mp_obj_new_bytes(out, 33);
return mp_const_none;
} }
return mp_obj_new_bytes(out, sizeof(out));
} else {
return mp_const_none;
}
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_secp256k1_verify_recover_obj, mod_trezorcrypto_secp256k1_verify_recover); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_secp256k1_verify_recover_obj,
mod_trezorcrypto_secp256k1_verify_recover);
/// def multiply(secret_key: bytes, public_key: bytes) -> bytes: /// def multiply(secret_key: bytes, public_key: bytes) -> bytes:
/// ''' /// '''
/// Multiplies point defined by public_key with scalar defined by secret_key. /// Multiplies point defined by public_key with scalar defined by
/// Useful for ECDH. /// secret_key. Useful for ECDH.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_multiply(mp_obj_t secret_key, mp_obj_t public_key) { STATIC mp_obj_t mod_trezorcrypto_secp256k1_multiply(mp_obj_t secret_key,
mp_buffer_info_t sk, pk; mp_obj_t public_key) {
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_buffer_info_t sk, pk;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) { mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_raise_ValueError("Invalid length of secret key"); if (sk.len != 32) {
} mp_raise_ValueError("Invalid length of secret key");
if (pk.len != 33 && pk.len != 65) { }
mp_raise_ValueError("Invalid length of public key"); if (pk.len != 33 && pk.len != 65) {
} mp_raise_ValueError("Invalid length of public key");
uint8_t out[65]; }
if (0 != ecdh_multiply(&secp256k1, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf, out)) { uint8_t out[65];
mp_raise_ValueError("Multiply failed"); if (0 != ecdh_multiply(&secp256k1, (const uint8_t *)sk.buf,
} (const uint8_t *)pk.buf, out)) {
return mp_obj_new_bytes(out, sizeof(out)); mp_raise_ValueError("Multiply failed");
}
return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_secp256k1_multiply_obj, mod_trezorcrypto_secp256k1_multiply); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_secp256k1_multiply_obj,
mod_trezorcrypto_secp256k1_multiply);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_secp256k1_globals_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_secp256k1_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_secp256k1) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_secp256k1)},
{ MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_generate_secret_obj) }, {MP_ROM_QSTR(MP_QSTR_generate_secret),
{ MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_publickey_obj) }, MP_ROM_PTR(&mod_trezorcrypto_secp256k1_generate_secret_obj)},
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_sign_obj) }, {MP_ROM_QSTR(MP_QSTR_publickey),
{ MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_verify_obj) }, MP_ROM_PTR(&mod_trezorcrypto_secp256k1_publickey_obj)},
{ MP_ROM_QSTR(MP_QSTR_verify_recover), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_verify_recover_obj) }, {MP_ROM_QSTR(MP_QSTR_sign),
{ MP_ROM_QSTR(MP_QSTR_multiply), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_multiply_obj) }, MP_ROM_PTR(&mod_trezorcrypto_secp256k1_sign_obj)},
{ MP_ROM_QSTR(MP_QSTR_CANONICAL_SIG_ETHEREUM), MP_OBJ_NEW_SMALL_INT(CANONICAL_SIG_ETHEREUM) }, {MP_ROM_QSTR(MP_QSTR_verify),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_verify_obj)},
{MP_ROM_QSTR(MP_QSTR_verify_recover),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_verify_recover_obj)},
{MP_ROM_QSTR(MP_QSTR_multiply),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_multiply_obj)},
{MP_ROM_QSTR(MP_QSTR_CANONICAL_SIG_ETHEREUM),
MP_OBJ_NEW_SMALL_INT(CANONICAL_SIG_ETHEREUM)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_secp256k1_globals, mod_trezorcrypto_secp256k1_globals_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_secp256k1_globals,
mod_trezorcrypto_secp256k1_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_secp256k1_module = { STATIC const mp_obj_module_t mod_trezorcrypto_secp256k1_module = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_secp256k1_globals, .globals = (mp_obj_dict_t *)&mod_trezorcrypto_secp256k1_globals,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "sha2.h"
#include "memzero.h" #include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA1 context. /// SHA1 context.
/// ''' /// '''
typedef struct _mp_obj_Sha1_t { typedef struct _mp_obj_Sha1_t {
mp_obj_base_t base; mp_obj_base_t base;
SHA1_CTX ctx; SHA1_CTX ctx;
} mp_obj_Sha1_t; } mp_obj_Sha1_t;
STATIC mp_obj_t mod_trezorcrypto_Sha1_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Sha1_update(mp_obj_t self, mp_obj_t data);
@ -39,16 +39,18 @@ STATIC mp_obj_t mod_trezorcrypto_Sha1_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha1_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Sha1_t *o = m_new_obj(mp_obj_Sha1_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
sha1_Init(&(o->ctx)); mp_obj_Sha1_t *o = m_new_obj(mp_obj_Sha1_t);
// constructor called with bytes/str as first parameter o->base.type = type;
if (n_args == 1) { sha1_Init(&(o->ctx));
mod_trezorcrypto_Sha1_update(MP_OBJ_FROM_PTR(o), args[0]); // constructor called with bytes/str as first parameter
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -56,50 +58,58 @@ STATIC mp_obj_t mod_trezorcrypto_Sha1_make_new(const mp_obj_type_t *type, size_t
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha1_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Sha1_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
sha1_Update(&(o->ctx), msg.buf, msg.len); sha1_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha1_update_obj, mod_trezorcrypto_Sha1_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha1_update_obj,
mod_trezorcrypto_Sha1_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha1_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha1_digest(mp_obj_t self) {
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA1_DIGEST_LENGTH]; uint8_t out[SHA1_DIGEST_LENGTH];
SHA1_CTX ctx; SHA1_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA1_CTX)); memcpy(&ctx, &(o->ctx), sizeof(SHA1_CTX));
sha1_Final(&ctx, out); sha1_Final(&ctx, out);
memzero(&ctx, sizeof(SHA1_CTX)); memzero(&ctx, sizeof(SHA1_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha1_digest_obj, mod_trezorcrypto_Sha1_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha1_digest_obj,
mod_trezorcrypto_Sha1_digest);
STATIC mp_obj_t mod_trezorcrypto_Sha1___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha1___del__(mp_obj_t self) {
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA1_CTX)); memzero(&(o->ctx), sizeof(SHA1_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha1___del___obj, mod_trezorcrypto_Sha1___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha1___del___obj,
mod_trezorcrypto_Sha1___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha1_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha1_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha1_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha1_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha1_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Sha1___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA1_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Sha1_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(SHA1_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Sha1___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA1_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(SHA1_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha1_locals_dict, mod_trezorcrypto_Sha1_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha1_locals_dict,
mod_trezorcrypto_Sha1_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Sha1_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Sha1_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Sha1, .name = MP_QSTR_Sha1,
.make_new = mod_trezorcrypto_Sha1_make_new, .make_new = mod_trezorcrypto_Sha1_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Sha1_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Sha1_locals_dict,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "sha2.h"
#include "memzero.h" #include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA256 context. /// SHA256 context.
/// ''' /// '''
typedef struct _mp_obj_Sha256_t { typedef struct _mp_obj_Sha256_t {
mp_obj_base_t base; mp_obj_base_t base;
SHA256_CTX ctx; SHA256_CTX ctx;
} mp_obj_Sha256_t; } mp_obj_Sha256_t;
STATIC mp_obj_t mod_trezorcrypto_Sha256_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Sha256_update(mp_obj_t self, mp_obj_t data);
@ -39,16 +39,18 @@ STATIC mp_obj_t mod_trezorcrypto_Sha256_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha256_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Sha256_t *o = m_new_obj(mp_obj_Sha256_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
sha256_Init(&(o->ctx)); mp_obj_Sha256_t *o = m_new_obj(mp_obj_Sha256_t);
// constructor called with bytes/str as first parameter o->base.type = type;
if (n_args == 1) { sha256_Init(&(o->ctx));
mod_trezorcrypto_Sha256_update(MP_OBJ_FROM_PTR(o), args[0]); // constructor called with bytes/str as first parameter
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -56,50 +58,59 @@ STATIC mp_obj_t mod_trezorcrypto_Sha256_make_new(const mp_obj_type_t *type, size
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha256_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Sha256_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
sha256_Update(&(o->ctx), msg.buf, msg.len); sha256_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha256_update_obj, mod_trezorcrypto_Sha256_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha256_update_obj,
mod_trezorcrypto_Sha256_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha256_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha256_digest(mp_obj_t self) {
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA256_DIGEST_LENGTH]; uint8_t out[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx; SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA256_CTX)); memcpy(&ctx, &(o->ctx), sizeof(SHA256_CTX));
sha256_Final(&ctx, out); sha256_Final(&ctx, out);
memzero(&ctx, sizeof(SHA256_CTX)); memzero(&ctx, sizeof(SHA256_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha256_digest_obj, mod_trezorcrypto_Sha256_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha256_digest_obj,
mod_trezorcrypto_Sha256_digest);
STATIC mp_obj_t mod_trezorcrypto_Sha256___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha256___del__(mp_obj_t self) {
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA256_CTX)); memzero(&(o->ctx), sizeof(SHA256_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha256___del___obj, mod_trezorcrypto_Sha256___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha256___del___obj,
mod_trezorcrypto_Sha256___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha256_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha256_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha256_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha256_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha256_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Sha256___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA256_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Sha256_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(SHA256_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Sha256___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(SHA256_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(SHA256_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha256_locals_dict, mod_trezorcrypto_Sha256_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha256_locals_dict,
mod_trezorcrypto_Sha256_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Sha256_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Sha256_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Sha256, .name = MP_QSTR_Sha256,
.make_new = mod_trezorcrypto_Sha256_make_new, .make_new = mod_trezorcrypto_Sha256_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Sha256_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Sha256_locals_dict,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "sha3.h"
#include "memzero.h" #include "memzero.h"
#include "sha3.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,9 +29,9 @@
/// SHA3_256 context. /// SHA3_256 context.
/// ''' /// '''
typedef struct _mp_obj_Sha3_256_t { typedef struct _mp_obj_Sha3_256_t {
mp_obj_base_t base; mp_obj_base_t base;
SHA3_CTX ctx; SHA3_CTX ctx;
bool keccak; bool keccak;
} mp_obj_Sha3_256_t; } mp_obj_Sha3_256_t;
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data);
@ -40,27 +40,30 @@ STATIC mp_obj_t mod_trezorcrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha3_256_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, true); size_t n_args, size_t n_kw,
mp_obj_Sha3_256_t *o = m_new_obj(mp_obj_Sha3_256_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, true);
o->keccak = 0; mp_obj_Sha3_256_t *o = m_new_obj(mp_obj_Sha3_256_t);
sha3_256_Init(&(o->ctx)); o->base.type = type;
o->keccak = 0;
sha3_256_Init(&(o->ctx));
STATIC const mp_arg_t allowed_args[] = { STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none}},
{ MP_QSTR_keccak, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, {MP_QSTR_keccak, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}},
}; };
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
if (vals[1].u_obj != MP_OBJ_NULL){ allowed_args, vals);
o->keccak = mp_obj_is_true(vals[1].u_obj); if (vals[1].u_obj != MP_OBJ_NULL) {
} o->keccak = mp_obj_is_true(vals[1].u_obj);
}
if (vals[0].u_obj != mp_const_none){ if (vals[0].u_obj != mp_const_none) {
mod_trezorcrypto_Sha3_256_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj); mod_trezorcrypto_Sha3_256_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
} }
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -68,70 +71,82 @@ STATIC mp_obj_t mod_trezorcrypto_Sha3_256_make_new(const mp_obj_type_t *type, si
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len); sha3_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha3_256_update_obj, mod_trezorcrypto_Sha3_256_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha3_256_update_obj,
mod_trezorcrypto_Sha3_256_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha3_256_digest(mp_obj_t self) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_256_DIGEST_LENGTH]; uint8_t out[SHA3_256_DIGEST_LENGTH];
SHA3_CTX ctx; SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX)); memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) { if (o->keccak) {
keccak_Final(&ctx, out); keccak_Final(&ctx, out);
} else { } else {
sha3_Final(&ctx, out); sha3_Final(&ctx, out);
} }
memzero(&ctx, sizeof(SHA3_CTX)); memzero(&ctx, sizeof(SHA3_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_256_digest_obj, mod_trezorcrypto_Sha3_256_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_256_digest_obj,
mod_trezorcrypto_Sha3_256_digest);
/// def copy(self) -> sha3: /// def copy(self) -> sha3:
/// ''' /// '''
/// Returns the copy of the digest object with the current state /// Returns the copy of the digest object with the current state
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_copy(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha3_256_copy(size_t n_args,
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(args[0]); const mp_obj_t *args) {
mp_obj_Sha3_256_t *out = m_new_obj(mp_obj_Sha3_256_t); mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(args[0]);
out->base.type = o->base.type; mp_obj_Sha3_256_t *out = m_new_obj(mp_obj_Sha3_256_t);
out->keccak = o->keccak; out->base.type = o->base.type;
memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX)); out->keccak = o->keccak;
return MP_OBJ_FROM_PTR(out); memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX));
return MP_OBJ_FROM_PTR(out);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_Sha3_256_copy_obj, 1, 1, mod_trezorcrypto_Sha3_256_copy); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_Sha3_256_copy_obj,
1, 1,
mod_trezorcrypto_Sha3_256_copy);
STATIC mp_obj_t mod_trezorcrypto_Sha3_256___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha3_256___del__(mp_obj_t self) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX)); memzero(&(o->ctx), sizeof(SHA3_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_256___del___obj, mod_trezorcrypto_Sha3_256___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_256___del___obj,
mod_trezorcrypto_Sha3_256___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha3_256_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha3_256_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_update_obj)},
{ MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_copy_obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256___del___obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA3_256_BLOCK_LENGTH) }, {MP_ROM_QSTR(MP_QSTR_copy),
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(SHA3_256_DIGEST_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_copy_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_256___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(SHA3_256_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(SHA3_256_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha3_256_locals_dict, mod_trezorcrypto_Sha3_256_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha3_256_locals_dict,
mod_trezorcrypto_Sha3_256_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Sha3_256_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Sha3_256_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Sha3_256, .name = MP_QSTR_Sha3_256,
.make_new = mod_trezorcrypto_Sha3_256_make_new, .make_new = mod_trezorcrypto_Sha3_256_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Sha3_256_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Sha3_256_locals_dict,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "sha3.h"
#include "memzero.h" #include "memzero.h"
#include "sha3.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,9 +29,9 @@
/// SHA3_512 context. /// SHA3_512 context.
/// ''' /// '''
typedef struct _mp_obj_Sha3_512_t { typedef struct _mp_obj_Sha3_512_t {
mp_obj_base_t base; mp_obj_base_t base;
SHA3_CTX ctx; SHA3_CTX ctx;
bool keccak; bool keccak;
} mp_obj_Sha3_512_t; } mp_obj_Sha3_512_t;
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data);
@ -40,27 +40,30 @@ STATIC mp_obj_t mod_trezorcrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha3_512_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, true); size_t n_args, size_t n_kw,
mp_obj_Sha3_512_t *o = m_new_obj(mp_obj_Sha3_512_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, true);
o->keccak = 0; mp_obj_Sha3_512_t *o = m_new_obj(mp_obj_Sha3_512_t);
sha3_512_Init(&(o->ctx)); o->base.type = type;
o->keccak = 0;
sha3_512_Init(&(o->ctx));
STATIC const mp_arg_t allowed_args[] = { STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none}},
{ MP_QSTR_keccak, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, {MP_QSTR_keccak, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}},
}; };
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
if (vals[1].u_obj != MP_OBJ_NULL){ allowed_args, vals);
o->keccak = mp_obj_is_true(vals[1].u_obj); if (vals[1].u_obj != MP_OBJ_NULL) {
} o->keccak = mp_obj_is_true(vals[1].u_obj);
}
if (vals[0].u_obj != mp_const_none){ if (vals[0].u_obj != mp_const_none) {
mod_trezorcrypto_Sha3_512_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj); mod_trezorcrypto_Sha3_512_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
} }
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
} }
/// def update(self, data: bytes) -> None: /// def update(self, data: bytes) -> None:
@ -68,70 +71,82 @@ STATIC mp_obj_t mod_trezorcrypto_Sha3_512_make_new(const mp_obj_type_t *type, si
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len); sha3_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha3_512_update_obj, mod_trezorcrypto_Sha3_512_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha3_512_update_obj,
mod_trezorcrypto_Sha3_512_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha3_512_digest(mp_obj_t self) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_512_DIGEST_LENGTH]; uint8_t out[SHA3_512_DIGEST_LENGTH];
SHA3_CTX ctx; SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX)); memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) { if (o->keccak) {
keccak_Final(&ctx, out); keccak_Final(&ctx, out);
} else { } else {
sha3_Final(&ctx, out); sha3_Final(&ctx, out);
} }
memzero(&ctx, sizeof(SHA3_CTX)); memzero(&ctx, sizeof(SHA3_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_512_digest_obj, mod_trezorcrypto_Sha3_512_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_512_digest_obj,
mod_trezorcrypto_Sha3_512_digest);
/// def copy(self) -> sha3: /// def copy(self) -> sha3:
/// ''' /// '''
/// Returns the copy of the digest object with the current state /// Returns the copy of the digest object with the current state
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_copy(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha3_512_copy(size_t n_args,
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(args[0]); const mp_obj_t *args) {
mp_obj_Sha3_512_t *out = m_new_obj(mp_obj_Sha3_512_t); mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(args[0]);
out->base.type = o->base.type; mp_obj_Sha3_512_t *out = m_new_obj(mp_obj_Sha3_512_t);
out->keccak = o->keccak; out->base.type = o->base.type;
memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX)); out->keccak = o->keccak;
return MP_OBJ_FROM_PTR(out); memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX));
return MP_OBJ_FROM_PTR(out);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_Sha3_512_copy_obj, 1, 1, mod_trezorcrypto_Sha3_512_copy); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_Sha3_512_copy_obj,
1, 1,
mod_trezorcrypto_Sha3_512_copy);
STATIC mp_obj_t mod_trezorcrypto_Sha3_512___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha3_512___del__(mp_obj_t self) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX)); memzero(&(o->ctx), sizeof(SHA3_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_512___del___obj, mod_trezorcrypto_Sha3_512___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha3_512___del___obj,
mod_trezorcrypto_Sha3_512___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha3_512_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha3_512_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_update_obj)},
{ MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_copy_obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512___del___obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA3_512_BLOCK_LENGTH) }, {MP_ROM_QSTR(MP_QSTR_copy),
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(SHA3_512_DIGEST_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_copy_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_512___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(SHA3_512_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(SHA3_512_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha3_512_locals_dict, mod_trezorcrypto_Sha3_512_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha3_512_locals_dict,
mod_trezorcrypto_Sha3_512_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Sha3_512_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Sha3_512_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Sha3_512, .name = MP_QSTR_Sha3_512,
.make_new = mod_trezorcrypto_Sha3_512_make_new, .make_new = mod_trezorcrypto_Sha3_512_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Sha3_512_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Sha3_512_locals_dict,
}; };

@ -19,8 +19,8 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "sha2.h"
#include "memzero.h" #include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__ /// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA512 context. /// SHA512 context.
/// ''' /// '''
typedef struct _mp_obj_Sha512_t { typedef struct _mp_obj_Sha512_t {
mp_obj_base_t base; mp_obj_base_t base;
SHA512_CTX ctx; SHA512_CTX ctx;
} mp_obj_Sha512_t; } mp_obj_Sha512_t;
STATIC mp_obj_t mod_trezorcrypto_Sha512_update(mp_obj_t self, mp_obj_t data); STATIC mp_obj_t mod_trezorcrypto_Sha512_update(mp_obj_t self, mp_obj_t data);
@ -39,15 +39,17 @@ STATIC mp_obj_t mod_trezorcrypto_Sha512_update(mp_obj_t self, mp_obj_t data);
/// ''' /// '''
/// Creates a hash context object. /// Creates a hash context object.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha512_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorcrypto_Sha512_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 1, false); size_t n_args, size_t n_kw,
mp_obj_Sha512_t *o = m_new_obj(mp_obj_Sha512_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 1, false);
sha512_Init(&(o->ctx)); mp_obj_Sha512_t *o = m_new_obj(mp_obj_Sha512_t);
if (n_args == 1) { o->base.type = type;
mod_trezorcrypto_Sha512_update(MP_OBJ_FROM_PTR(o), args[0]); sha512_Init(&(o->ctx));
} if (n_args == 1) {
return MP_OBJ_FROM_PTR(o); mod_trezorcrypto_Sha512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
} }
/// def hash(self, data: bytes) -> None: /// def hash(self, data: bytes) -> None:
@ -55,50 +57,59 @@ STATIC mp_obj_t mod_trezorcrypto_Sha512_make_new(const mp_obj_type_t *type, size
/// Update the hash context with hashed data. /// Update the hash context with hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha512_update(mp_obj_t self, mp_obj_t data) { STATIC mp_obj_t mod_trezorcrypto_Sha512_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg; mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) { if (msg.len > 0) {
sha512_Update(&(o->ctx), msg.buf, msg.len); sha512_Update(&(o->ctx), msg.buf, msg.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha512_update_obj, mod_trezorcrypto_Sha512_update); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_Sha512_update_obj,
mod_trezorcrypto_Sha512_update);
/// def digest(self) -> bytes: /// def digest(self) -> bytes:
/// ''' /// '''
/// Returns the digest of hashed data. /// Returns the digest of hashed data.
/// ''' /// '''
STATIC mp_obj_t mod_trezorcrypto_Sha512_digest(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha512_digest(mp_obj_t self) {
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA512_DIGEST_LENGTH]; uint8_t out[SHA512_DIGEST_LENGTH];
SHA512_CTX ctx; SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA512_CTX)); memcpy(&ctx, &(o->ctx), sizeof(SHA512_CTX));
sha512_Final(&ctx, out); sha512_Final(&ctx, out);
memzero(&ctx, sizeof(SHA512_CTX)); memzero(&ctx, sizeof(SHA512_CTX));
return mp_obj_new_bytes(out, sizeof(out)); return mp_obj_new_bytes(out, sizeof(out));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha512_digest_obj, mod_trezorcrypto_Sha512_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha512_digest_obj,
mod_trezorcrypto_Sha512_digest);
STATIC mp_obj_t mod_trezorcrypto_Sha512___del__(mp_obj_t self) { STATIC mp_obj_t mod_trezorcrypto_Sha512___del__(mp_obj_t self) {
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self); mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA512_CTX)); memzero(&(o->ctx), sizeof(SHA512_CTX));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha512___del___obj, mod_trezorcrypto_Sha512___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Sha512___del___obj,
mod_trezorcrypto_Sha512___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha512_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorcrypto_Sha512_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha512_update_obj) }, {MP_ROM_QSTR(MP_QSTR_update),
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha512_digest_obj) }, MP_ROM_PTR(&mod_trezorcrypto_Sha512_update_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_Sha512___del___obj) }, {MP_ROM_QSTR(MP_QSTR_digest),
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SHA512_BLOCK_LENGTH) }, MP_ROM_PTR(&mod_trezorcrypto_Sha512_digest_obj)},
{ MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(SHA512_DIGEST_LENGTH) }, {MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_Sha512___del___obj)},
{MP_ROM_QSTR(MP_QSTR_block_size),
MP_OBJ_NEW_SMALL_INT(SHA512_BLOCK_LENGTH)},
{MP_ROM_QSTR(MP_QSTR_digest_size),
MP_OBJ_NEW_SMALL_INT(SHA512_DIGEST_LENGTH)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha512_locals_dict, mod_trezorcrypto_Sha512_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_Sha512_locals_dict,
mod_trezorcrypto_Sha512_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_Sha512_type = { STATIC const mp_obj_type_t mod_trezorcrypto_Sha512_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Sha512, .name = MP_QSTR_Sha512,
.make_new = mod_trezorcrypto_Sha512_make_new, .make_new = mod_trezorcrypto_Sha512_make_new,
.locals_dict = (void*)&mod_trezorcrypto_Sha512_locals_dict, .locals_dict = (void *)&mod_trezorcrypto_Sha512_locals_dict,
}; };

@ -17,9 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include "py/runtime.h" #include "py/runtime.h"
@ -35,9 +35,10 @@
#include "modtrezorcrypto-crc.h" #include "modtrezorcrypto-crc.h"
#include "modtrezorcrypto-curve25519.h" #include "modtrezorcrypto-curve25519.h"
#include "modtrezorcrypto-ed25519.h" #include "modtrezorcrypto-ed25519.h"
#include "modtrezorcrypto-nist256p1.h"
#include "modtrezorcrypto-groestl.h" #include "modtrezorcrypto-groestl.h"
#include "modtrezorcrypto-monero.h"
#include "modtrezorcrypto-nem.h" #include "modtrezorcrypto-nem.h"
#include "modtrezorcrypto-nist256p1.h"
#include "modtrezorcrypto-pbkdf2.h" #include "modtrezorcrypto-pbkdf2.h"
#include "modtrezorcrypto-random.h" #include "modtrezorcrypto-random.h"
#include "modtrezorcrypto-rfc6979.h" #include "modtrezorcrypto-rfc6979.h"
@ -45,43 +46,53 @@
#include "modtrezorcrypto-secp256k1.h" #include "modtrezorcrypto-secp256k1.h"
#include "modtrezorcrypto-sha1.h" #include "modtrezorcrypto-sha1.h"
#include "modtrezorcrypto-sha256.h" #include "modtrezorcrypto-sha256.h"
#include "modtrezorcrypto-sha512.h"
#include "modtrezorcrypto-sha3-256.h" #include "modtrezorcrypto-sha3-256.h"
#include "modtrezorcrypto-sha3-512.h" #include "modtrezorcrypto-sha3-512.h"
#include "modtrezorcrypto-monero.h" #include "modtrezorcrypto-sha512.h"
STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorcrypto) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorcrypto)},
{ MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&mod_trezorcrypto_AES_type) }, {MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&mod_trezorcrypto_AES_type)},
{ MP_ROM_QSTR(MP_QSTR_bip32), MP_ROM_PTR(&mod_trezorcrypto_bip32_module) }, {MP_ROM_QSTR(MP_QSTR_bip32), MP_ROM_PTR(&mod_trezorcrypto_bip32_module)},
{ MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&mod_trezorcrypto_bip39_module) }, {MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&mod_trezorcrypto_bip39_module)},
{ MP_ROM_QSTR(MP_QSTR_blake256), MP_ROM_PTR(&mod_trezorcrypto_Blake256_type) }, {MP_ROM_QSTR(MP_QSTR_blake256),
{ MP_ROM_QSTR(MP_QSTR_blake2b), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_type) }, MP_ROM_PTR(&mod_trezorcrypto_Blake256_type)},
{ MP_ROM_QSTR(MP_QSTR_blake2s), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_type) }, {MP_ROM_QSTR(MP_QSTR_blake2b), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_type)},
{ MP_ROM_QSTR(MP_QSTR_chacha20poly1305), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_type) }, {MP_ROM_QSTR(MP_QSTR_blake2s), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_type)},
{ MP_ROM_QSTR(MP_QSTR_crc), MP_ROM_PTR(&mod_trezorcrypto_crc_module) }, {MP_ROM_QSTR(MP_QSTR_chacha20poly1305),
{ MP_ROM_QSTR(MP_QSTR_curve25519), MP_ROM_PTR(&mod_trezorcrypto_curve25519_module) }, MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_type)},
{ MP_ROM_QSTR(MP_QSTR_ed25519), MP_ROM_PTR(&mod_trezorcrypto_ed25519_module) }, {MP_ROM_QSTR(MP_QSTR_crc), MP_ROM_PTR(&mod_trezorcrypto_crc_module)},
{ MP_ROM_QSTR(MP_QSTR_monero), MP_ROM_PTR(&mod_trezorcrypto_monero_module) }, {MP_ROM_QSTR(MP_QSTR_curve25519),
{ MP_ROM_QSTR(MP_QSTR_nist256p1), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_module) }, MP_ROM_PTR(&mod_trezorcrypto_curve25519_module)},
{ MP_ROM_QSTR(MP_QSTR_groestl512), MP_ROM_PTR(&mod_trezorcrypto_Groestl512_type) }, {MP_ROM_QSTR(MP_QSTR_ed25519),
{ MP_ROM_QSTR(MP_QSTR_nem), MP_ROM_PTR(&mod_trezorcrypto_nem_module) }, MP_ROM_PTR(&mod_trezorcrypto_ed25519_module)},
{ MP_ROM_QSTR(MP_QSTR_pbkdf2), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_type) }, {MP_ROM_QSTR(MP_QSTR_monero), MP_ROM_PTR(&mod_trezorcrypto_monero_module)},
{ MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_trezorcrypto_random_module) }, {MP_ROM_QSTR(MP_QSTR_nist256p1),
{ MP_ROM_QSTR(MP_QSTR_rfc6979), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_type) }, MP_ROM_PTR(&mod_trezorcrypto_nist256p1_module)},
{ MP_ROM_QSTR(MP_QSTR_ripemd160), MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_type) }, {MP_ROM_QSTR(MP_QSTR_groestl512),
{ MP_ROM_QSTR(MP_QSTR_secp256k1), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_module) }, MP_ROM_PTR(&mod_trezorcrypto_Groestl512_type)},
{ MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&mod_trezorcrypto_Sha1_type) }, {MP_ROM_QSTR(MP_QSTR_nem), MP_ROM_PTR(&mod_trezorcrypto_nem_module)},
{ MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&mod_trezorcrypto_Sha256_type) }, {MP_ROM_QSTR(MP_QSTR_pbkdf2), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_type)},
{ MP_ROM_QSTR(MP_QSTR_sha512), MP_ROM_PTR(&mod_trezorcrypto_Sha512_type) }, {MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_trezorcrypto_random_module)},
{ MP_ROM_QSTR(MP_QSTR_sha3_256), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_type) }, {MP_ROM_QSTR(MP_QSTR_rfc6979), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_type)},
{ MP_ROM_QSTR(MP_QSTR_sha3_512), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_type) }, {MP_ROM_QSTR(MP_QSTR_ripemd160),
MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_type)},
{MP_ROM_QSTR(MP_QSTR_secp256k1),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_module)},
{MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&mod_trezorcrypto_Sha1_type)},
{MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&mod_trezorcrypto_Sha256_type)},
{MP_ROM_QSTR(MP_QSTR_sha512), MP_ROM_PTR(&mod_trezorcrypto_Sha512_type)},
{MP_ROM_QSTR(MP_QSTR_sha3_256),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_type)},
{MP_ROM_QSTR(MP_QSTR_sha3_512),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_type)},
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorcrypto_globals, mp_module_trezorcrypto_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_trezorcrypto_globals,
mp_module_trezorcrypto_globals_table);
const mp_obj_module_t mp_module_trezorcrypto = { const mp_obj_module_t mp_module_trezorcrypto = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mp_module_trezorcrypto_globals, .globals = (mp_obj_dict_t*)&mp_module_trezorcrypto_globals,
}; };
#endif // MICROPY_PY_TREZORCRYPTO #endif // MICROPY_PY_TREZORCRYPTO

@ -20,7 +20,4 @@
#include "rand.h" #include "rand.h"
#include "rng.h" #include "rng.h"
uint32_t random32(void) uint32_t random32(void) { return rng_get(); }
{
return rng_get();
}

@ -25,85 +25,95 @@
/// ''' /// '''
/// ''' /// '''
typedef struct _mp_obj_FlashOTP_t { typedef struct _mp_obj_FlashOTP_t {
mp_obj_base_t base; mp_obj_base_t base;
} mp_obj_FlashOTP_t; } mp_obj_FlashOTP_t;
/// def __init__(self) -> None: /// def __init__(self) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_FlashOTP_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 0, false); size_t n_args, size_t n_kw,
mp_obj_FlashOTP_t *o = m_new_obj(mp_obj_FlashOTP_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 0, false);
return MP_OBJ_FROM_PTR(o); mp_obj_FlashOTP_t *o = m_new_obj(mp_obj_FlashOTP_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
} }
/// def FlashOTP.write(self, block: int, offset: int, data: bytes) -> None: /// def FlashOTP.write(self, block: int, offset: int, data: bytes) -> None:
/// ''' /// '''
/// Writes data to OTP flash /// Writes data to OTP flash
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_write(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_FlashOTP_write(size_t n_args,
uint8_t block = trezor_obj_get_uint8(args[1]); const mp_obj_t *args) {
uint8_t offset = trezor_obj_get_uint8(args[2]); uint8_t block = trezor_obj_get_uint8(args[1]);
mp_buffer_info_t data; uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ); mp_buffer_info_t data;
if (sectrue != flash_otp_write(block, offset, data.buf, data.len)) { mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ);
mp_raise_ValueError("write failed"); if (sectrue != flash_otp_write(block, offset, data.buf, data.len)) {
} mp_raise_ValueError("write failed");
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_write_obj, 4, 4, mod_trezorio_FlashOTP_write); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_write_obj, 4,
4, mod_trezorio_FlashOTP_write);
/// def FlashOTP.read(self, block: int, offset: int, data: bytearray) -> None: /// def FlashOTP.read(self, block: int, offset: int, data: bytearray) -> None:
/// ''' /// '''
/// Reads data from OTP flash /// Reads data from OTP flash
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_read(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_FlashOTP_read(size_t n_args,
uint8_t block = trezor_obj_get_uint8(args[1]); const mp_obj_t *args) {
uint8_t offset = trezor_obj_get_uint8(args[2]); uint8_t block = trezor_obj_get_uint8(args[1]);
mp_buffer_info_t data; uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_get_buffer_raise(args[3], &data, MP_BUFFER_WRITE); mp_buffer_info_t data;
if (sectrue != flash_otp_read(block, offset, data.buf, data.len)) { mp_get_buffer_raise(args[3], &data, MP_BUFFER_WRITE);
mp_raise_ValueError("read failed"); if (sectrue != flash_otp_read(block, offset, data.buf, data.len)) {
} mp_raise_ValueError("read failed");
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_read_obj, 4, 4, mod_trezorio_FlashOTP_read); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashOTP_read_obj, 4, 4,
mod_trezorio_FlashOTP_read);
/// def FlashOTP.lock(self, block: int) -> None: /// def FlashOTP.lock(self, block: int) -> None:
/// ''' /// '''
/// Lock OTP flash block /// Lock OTP flash block
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_lock(mp_obj_t self, mp_obj_t block) { STATIC mp_obj_t mod_trezorio_FlashOTP_lock(mp_obj_t self, mp_obj_t block) {
uint8_t b = trezor_obj_get_uint8(block); uint8_t b = trezor_obj_get_uint8(block);
if (sectrue != flash_otp_lock(b)) { if (sectrue != flash_otp_lock(b)) {
mp_raise_ValueError("lock failed"); mp_raise_ValueError("lock failed");
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_lock_obj, mod_trezorio_FlashOTP_lock); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_lock_obj,
mod_trezorio_FlashOTP_lock);
/// def FlashOTP.is_locked(self, block: int) -> bool: /// def FlashOTP.is_locked(self, block: int) -> bool:
/// ''' /// '''
/// Is OTP flash block locked? /// Is OTP flash block locked?
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_is_locked(mp_obj_t self, mp_obj_t block) { STATIC mp_obj_t mod_trezorio_FlashOTP_is_locked(mp_obj_t self, mp_obj_t block) {
uint8_t b = trezor_obj_get_uint8(block); uint8_t b = trezor_obj_get_uint8(block);
return (sectrue == flash_otp_is_locked(b)) ? mp_const_true : mp_const_false; return (sectrue == flash_otp_is_locked(b)) ? mp_const_true : mp_const_false;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_is_locked_obj, mod_trezorio_FlashOTP_is_locked); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashOTP_is_locked_obj,
mod_trezorio_FlashOTP_is_locked);
STATIC const mp_rom_map_elem_t mod_trezorio_FlashOTP_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_FlashOTP_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_FlashOTP_read_obj) }, {MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_FlashOTP_read_obj)},
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_FlashOTP_write_obj) }, {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_FlashOTP_write_obj)},
{ MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorio_FlashOTP_lock_obj) }, {MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorio_FlashOTP_lock_obj)},
{ MP_ROM_QSTR(MP_QSTR_is_locked), MP_ROM_PTR(&mod_trezorio_FlashOTP_is_locked_obj) }, {MP_ROM_QSTR(MP_QSTR_is_locked),
MP_ROM_PTR(&mod_trezorio_FlashOTP_is_locked_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_FlashOTP_locals_dict, mod_trezorio_FlashOTP_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_FlashOTP_locals_dict,
mod_trezorio_FlashOTP_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_FlashOTP_type = { STATIC const mp_obj_type_t mod_trezorio_FlashOTP_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_FlashOTP, .name = MP_QSTR_FlashOTP,
.make_new = mod_trezorio_FlashOTP_make_new, .make_new = mod_trezorio_FlashOTP_make_new,
.locals_dict = (void*)&mod_trezorio_FlashOTP_locals_dict, .locals_dict = (void *)&mod_trezorio_FlashOTP_locals_dict,
}; };

@ -22,8 +22,8 @@
/// USB HID interface configuration. /// USB HID interface configuration.
/// ''' /// '''
typedef struct _mp_obj_HID_t { typedef struct _mp_obj_HID_t {
mp_obj_base_t base; mp_obj_base_t base;
usb_hid_info_t info; usb_hid_info_t info;
} mp_obj_HID_t; } mp_obj_HID_t;
/// def __init__(self, /// def __init__(self,
@ -37,57 +37,68 @@ typedef struct _mp_obj_HID_t {
/// max_packet_len: int = 64) -> None: /// max_packet_len: int = 64) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_HID_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_HID_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
STATIC const mp_arg_t allowed_args[] = {
{MP_QSTR_iface_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_in,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_out,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1}},
{MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64}},
{MP_QSTR_report_desc,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = MP_OBJ_NULL}},
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
allowed_args, vals);
STATIC const mp_arg_t allowed_args[] = { const mp_int_t iface_num = vals[0].u_int;
{ MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_in = vals[1].u_int;
{ MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_out = vals[2].u_int;
{ MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t subclass = vals[3].u_int;
{ MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t protocol = vals[4].u_int;
{ MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t polling_interval = vals[5].u_int;
{ MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, const mp_int_t max_packet_len = vals[6].u_int;
{ MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, mp_buffer_info_t report_desc;
{ MP_QSTR_report_desc, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ);
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
const mp_int_t iface_num = vals[0].u_int; if (report_desc.buf == NULL || report_desc.len == 0 ||
const mp_int_t ep_in = vals[1].u_int; report_desc.len > 255) {
const mp_int_t ep_out = vals[2].u_int; mp_raise_ValueError("report_desc is invalid");
const mp_int_t subclass = vals[3].u_int; }
const mp_int_t protocol = vals[4].u_int; CHECK_PARAM_RANGE(iface_num, 0, 32)
const mp_int_t polling_interval = vals[5].u_int; CHECK_PARAM_RANGE(ep_in, 0, 255)
const mp_int_t max_packet_len = vals[6].u_int; CHECK_PARAM_RANGE(ep_out, 0, 255)
mp_buffer_info_t report_desc; CHECK_PARAM_RANGE(subclass, 0, 255)
mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ); CHECK_PARAM_RANGE(protocol, 0, 255)
CHECK_PARAM_RANGE(polling_interval, 1, 255)
CHECK_PARAM_RANGE(max_packet_len, 64, 64)
if (report_desc.buf == NULL || report_desc.len == 0 || report_desc.len > 255) { mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t);
mp_raise_ValueError("report_desc is invalid"); o->base.type = type;
}
CHECK_PARAM_RANGE(iface_num, 0, 32)
CHECK_PARAM_RANGE(ep_in, 0, 255)
CHECK_PARAM_RANGE(ep_out, 0, 255)
CHECK_PARAM_RANGE(subclass, 0, 255)
CHECK_PARAM_RANGE(protocol, 0, 255)
CHECK_PARAM_RANGE(polling_interval, 1, 255)
CHECK_PARAM_RANGE(max_packet_len, 64, 64)
mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t); o->info.rx_buffer = m_new(uint8_t, max_packet_len);
o->base.type = type; o->info.report_desc = report_desc.buf;
o->info.iface_num = (uint8_t)(iface_num);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.subclass = (uint8_t)(subclass);
o->info.protocol = (uint8_t)(protocol);
o->info.polling_interval = (uint8_t)(polling_interval);
o->info.max_packet_len = (uint8_t)(max_packet_len);
o->info.report_desc_len = (uint8_t)(report_desc.len);
o->info.rx_buffer = m_new(uint8_t, max_packet_len); return MP_OBJ_FROM_PTR(o);
o->info.report_desc = report_desc.buf;
o->info.iface_num = (uint8_t)(iface_num);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.subclass = (uint8_t)(subclass);
o->info.protocol = (uint8_t)(protocol);
o->info.polling_interval = (uint8_t)(polling_interval);
o->info.max_packet_len = (uint8_t)(max_packet_len);
o->info.report_desc_len = (uint8_t)(report_desc.len);
return MP_OBJ_FROM_PTR(o);
} }
/// def iface_num(self) -> int: /// def iface_num(self) -> int:
@ -95,33 +106,37 @@ STATIC mp_obj_t mod_trezorio_HID_make_new(const mp_obj_type_t *type, size_t n_ar
/// Returns the configured number of this interface. /// Returns the configured number of this interface.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_HID_iface_num(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_HID_iface_num(mp_obj_t self) {
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self); mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num); return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_HID_iface_num_obj, mod_trezorio_HID_iface_num); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_HID_iface_num_obj,
mod_trezorio_HID_iface_num);
/// def write(self, msg: bytes) -> int: /// def write(self, msg: bytes) -> int:
/// ''' /// '''
/// Sends message using USB HID (device) or UDP (emulator). /// Sends message using USB HID (device) or UDP (emulator).
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_HID_write(mp_obj_t self, mp_obj_t msg) { STATIC mp_obj_t mod_trezorio_HID_write(mp_obj_t self, mp_obj_t msg) {
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self); mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf; mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ); mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_hid_write(o->info.iface_num, buf.buf, buf.len); ssize_t r = usb_hid_write(o->info.iface_num, buf.buf, buf.len);
return MP_OBJ_NEW_SMALL_INT(r); return MP_OBJ_NEW_SMALL_INT(r);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_HID_write_obj, mod_trezorio_HID_write); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_HID_write_obj,
mod_trezorio_HID_write);
STATIC const mp_rom_map_elem_t mod_trezorio_HID_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_HID_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_iface_num), MP_ROM_PTR(&mod_trezorio_HID_iface_num_obj) }, {MP_ROM_QSTR(MP_QSTR_iface_num),
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_HID_write_obj) }, MP_ROM_PTR(&mod_trezorio_HID_iface_num_obj)},
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_HID_write_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_HID_locals_dict, mod_trezorio_HID_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_HID_locals_dict,
mod_trezorio_HID_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_HID_type = { STATIC const mp_obj_type_t mod_trezorio_HID_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_HID, .name = MP_QSTR_HID,
.make_new = mod_trezorio_HID_make_new, .make_new = mod_trezorio_HID_make_new,
.locals_dict = (void*)&mod_trezorio_HID_locals_dict, .locals_dict = (void *)&mod_trezorio_HID_locals_dict,
}; };

@ -18,21 +18,13 @@
*/ */
#include <string.h> #include <string.h>
#include <unistd.h>
#include "embed/extmod/trezorobj.h" #include "embed/extmod/trezorobj.h"
#include "usb.h"
#define TOUCH_IFACE (255) #define TOUCH_IFACE (255)
#define POLL_READ (0x0000) #define POLL_READ (0x0000)
#define POLL_WRITE (0x0100) #define POLL_WRITE (0x0100)
#define CHECK_PARAM_RANGE(value, minimum, maximum) \
if (value < minimum || value > maximum) { \
mp_raise_ValueError(#value " is out of range"); \
}
/// def poll(ifaces: Iterable[int], list_ref: List, timeout_us: int) -> bool: /// def poll(ifaces: Iterable[int], list_ref: List, timeout_us: int) -> bool:
/// ''' /// '''
/// Wait until one of `ifaces` is ready to read or write (using masks /// Wait until one of `ifaces` is ready to read or write (using masks
@ -40,80 +32,82 @@
/// `list_ref`: /// `list_ref`:
/// ///
/// `list_ref[0]` - the interface number, including the mask /// `list_ref[0]` - the interface number, including the mask
/// `list_ref[1]` - for touch event, tuple of (event_type, x_position, y_position) /// `list_ref[1]` - for touch event, tuple of (event_type, x_position,
/// y_position)
/// - for USB read event, received bytes /// - for USB read event, received bytes
/// ///
/// If timeout occurs, False is returned, True otherwise. /// If timeout occurs, False is returned, True otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, mp_obj_t timeout_us) { STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); mp_obj_t timeout_us) {
if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 2) { mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
mp_raise_TypeError("invalid list_ref"); if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 2) {
} mp_raise_TypeError("invalid list_ref");
}
const mp_uint_t timeout = trezor_obj_get_uint(timeout_us); const mp_uint_t timeout = trezor_obj_get_uint(timeout_us);
const mp_uint_t deadline = mp_hal_ticks_us() + timeout; const mp_uint_t deadline = mp_hal_ticks_us() + timeout;
mp_obj_iter_buf_t iterbuf; mp_obj_iter_buf_t iterbuf;
for (;;) { for (;;) {
mp_obj_t iter = mp_getiter(ifaces, &iterbuf); mp_obj_t iter = mp_getiter(ifaces, &iterbuf);
mp_obj_t item; mp_obj_t item;
while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
const mp_uint_t i = trezor_obj_get_uint(item); const mp_uint_t i = trezor_obj_get_uint(item);
const mp_uint_t iface = i & 0x00FF; const mp_uint_t iface = i & 0x00FF;
const mp_uint_t mode = i & 0xFF00; const mp_uint_t mode = i & 0xFF00;
if (iface == TOUCH_IFACE) { if (iface == TOUCH_IFACE) {
const uint32_t evt = touch_read(); const uint32_t evt = touch_read();
if (evt) { if (evt) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
tuple->items[0] = MP_OBJ_NEW_SMALL_INT((evt >> 24) & 0xFFU); // event type tuple->items[0] =
tuple->items[1] = MP_OBJ_NEW_SMALL_INT((evt >> 12) & 0xFFFU); // x position MP_OBJ_NEW_SMALL_INT((evt >> 24) & 0xFFU); // event type
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(evt & 0xFFFU); // y position tuple->items[1] =
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); MP_OBJ_NEW_SMALL_INT((evt >> 12) & 0xFFFU); // x position
ret->items[1] = MP_OBJ_FROM_PTR(tuple); tuple->items[2] = MP_OBJ_NEW_SMALL_INT(evt & 0xFFFU); // y position
return mp_const_true; ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
} ret->items[1] = MP_OBJ_FROM_PTR(tuple);
} else return mp_const_true;
if (mode == POLL_READ) {
if (sectrue == usb_hid_can_read(iface)) {
uint8_t buf[64];
int len = usb_hid_read(iface, buf, sizeof(buf));
if (len > 0) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_obj_new_bytes(buf, len);
return mp_const_true;
}
} else if (sectrue == usb_webusb_can_read(iface)) {
uint8_t buf[64];
int len = usb_webusb_read(iface, buf, sizeof(buf));
if (len > 0) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_obj_new_bytes(buf, len);
return mp_const_true;
}
}
} else
if (mode == POLL_WRITE) {
if (sectrue == usb_hid_can_write(iface)) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_const_none;
return mp_const_true;
} else if (sectrue == usb_webusb_can_write(iface)) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_const_none;
return mp_const_true;
}
}
} }
} else if (mode == POLL_READ) {
if (mp_hal_ticks_us() >= deadline) { if (sectrue == usb_hid_can_read(iface)) {
break; uint8_t buf[64];
} else { int len = usb_hid_read(iface, buf, sizeof(buf));
MICROPY_EVENT_POLL_HOOK if (len > 0) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_obj_new_bytes(buf, len);
return mp_const_true;
}
} else if (sectrue == usb_webusb_can_read(iface)) {
uint8_t buf[64];
int len = usb_webusb_read(iface, buf, sizeof(buf));
if (len > 0) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_obj_new_bytes(buf, len);
return mp_const_true;
}
}
} else if (mode == POLL_WRITE) {
if (sectrue == usb_hid_can_write(iface)) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_const_none;
return mp_const_true;
} else if (sectrue == usb_webusb_can_write(iface)) {
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = mp_const_none;
return mp_const_true;
} }
}
}
if (mp_hal_ticks_us() >= deadline) {
break;
} else {
MICROPY_EVENT_POLL_HOOK
} }
}
return mp_const_false; return mp_const_false;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_poll_obj, mod_trezorio_poll); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_poll_obj, mod_trezorio_poll);

@ -23,38 +23,43 @@
/// ''' /// '''
/// ''' /// '''
typedef struct _mp_obj_SBU_t { typedef struct _mp_obj_SBU_t {
mp_obj_base_t base; mp_obj_base_t base;
} mp_obj_SBU_t; } mp_obj_SBU_t;
/// def __init__(self) -> None: /// def __init__(self) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SBU_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_SBU_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 0, false); size_t n_args, size_t n_kw,
mp_obj_SBU_t *o = m_new_obj(mp_obj_SBU_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 0, false);
sbu_init(); mp_obj_SBU_t *o = m_new_obj(mp_obj_SBU_t);
return MP_OBJ_FROM_PTR(o); o->base.type = type;
sbu_init();
return MP_OBJ_FROM_PTR(o);
} }
/// def set(self, sbu1: bool, sbu2: bool) -> None: /// def set(self, sbu1: bool, sbu2: bool) -> None:
/// ''' /// '''
/// Sets SBU wires to sbu1 and sbu2 values respectively /// Sets SBU wires to sbu1 and sbu2 values respectively
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SBU_set(mp_obj_t self, mp_obj_t sbu1, mp_obj_t sbu2) { STATIC mp_obj_t mod_trezorio_SBU_set(mp_obj_t self, mp_obj_t sbu1,
sbu_set(sectrue * mp_obj_is_true(sbu1), sectrue * mp_obj_is_true(sbu2)); mp_obj_t sbu2) {
return mp_const_none; sbu_set(sectrue * mp_obj_is_true(sbu1), sectrue * mp_obj_is_true(sbu2));
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SBU_set_obj, mod_trezorio_SBU_set); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SBU_set_obj,
mod_trezorio_SBU_set);
STATIC const mp_rom_map_elem_t mod_trezorio_SBU_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_SBU_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorio_SBU_set_obj) }, {MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorio_SBU_set_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_SBU_locals_dict, mod_trezorio_SBU_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_SBU_locals_dict,
mod_trezorio_SBU_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_SBU_type = { STATIC const mp_obj_type_t mod_trezorio_SBU_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_SBU, .name = MP_QSTR_SBU,
.make_new = mod_trezorio_SBU_make_new, .make_new = mod_trezorio_SBU_make_new,
.locals_dict = (void*)&mod_trezorio_SBU_locals_dict, .locals_dict = (void *)&mod_trezorio_SBU_locals_dict,
}; };

@ -25,20 +25,22 @@
/// ''' /// '''
/// ''' /// '''
typedef struct _mp_obj_SDCard_t { typedef struct _mp_obj_SDCard_t {
mp_obj_base_t base; mp_obj_base_t base;
} mp_obj_SDCard_t; } mp_obj_SDCard_t;
/// def __init__(self) -> None: /// def __init__(self) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_SDCard_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 0, false); size_t n_args, size_t n_kw,
mp_obj_SDCard_t *o = m_new_obj(mp_obj_SDCard_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_SDCard_t *o = m_new_obj(mp_obj_SDCard_t);
o->base.type = type;
#ifdef TREZOR_EMULATOR #ifdef TREZOR_EMULATOR
sdcard_init(); sdcard_init();
#endif #endif
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
} }
/// def present(self) -> bool: /// def present(self) -> bool:
@ -46,9 +48,10 @@ STATIC mp_obj_t mod_trezorio_SDCard_make_new(const mp_obj_type_t *type, size_t n
/// Returns True if SD card is detected, False otherwise. /// Returns True if SD card is detected, False otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_present(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_SDCard_present(mp_obj_t self) {
return mp_obj_new_bool(sdcard_is_present()); return mp_obj_new_bool(sdcard_is_present());
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SDCard_present_obj, mod_trezorio_SDCard_present); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SDCard_present_obj,
mod_trezorio_SDCard_present);
/// def power(self, state: bool) -> bool: /// def power(self, state: bool) -> bool:
/// ''' /// '''
@ -56,65 +59,76 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SDCard_present_obj, mod_trezorio_S
/// Returns True if in case of success, False otherwise. /// Returns True if in case of success, False otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_power(mp_obj_t self, mp_obj_t state) { STATIC mp_obj_t mod_trezorio_SDCard_power(mp_obj_t self, mp_obj_t state) {
if (mp_obj_is_true(state)) { if (mp_obj_is_true(state)) {
return mp_obj_new_bool(sdcard_power_on()); return mp_obj_new_bool(sdcard_power_on());
} else { } else {
sdcard_power_off(); sdcard_power_off();
return mp_const_true; return mp_const_true;
} }
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_SDCard_power_obj, mod_trezorio_SDCard_power); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_SDCard_power_obj,
mod_trezorio_SDCard_power);
/// def capacity(self) -> int: /// def capacity(self) -> int:
/// ''' /// '''
/// Returns capacity of the SD card in bytes, or zero if not present. /// Returns capacity of the SD card in bytes, or zero if not present.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_capacity(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_SDCard_capacity(mp_obj_t self) {
return mp_obj_new_int_from_ull(sdcard_get_capacity_in_bytes()); return mp_obj_new_int_from_ull(sdcard_get_capacity_in_bytes());
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SDCard_capacity_obj, mod_trezorio_SDCard_capacity); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_SDCard_capacity_obj,
mod_trezorio_SDCard_capacity);
/// def read(self, block_num: int, buf: bytearray) -> bool: /// def read(self, block_num: int, buf: bytearray) -> bool:
/// ''' /// '''
/// Reads blocks starting with block_num from the SD card into buf. /// Reads blocks starting with block_num from the SD card into buf.
/// Number of bytes read is length of buf rounded down to multiply of SDCARD_BLOCK_SIZE. /// Number of bytes read is length of buf rounded down to multiply of
/// Returns True if in case of success, False otherwise. /// SDCARD_BLOCK_SIZE. Returns True if in case of success, False otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_read(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { STATIC mp_obj_t mod_trezorio_SDCard_read(mp_obj_t self, mp_obj_t block_num,
uint32_t block = trezor_obj_get_uint(block_num); mp_obj_t buf) {
mp_buffer_info_t bufinfo; uint32_t block = trezor_obj_get_uint(block_num);
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); mp_buffer_info_t bufinfo;
return mp_obj_new_bool(sdcard_read_blocks(bufinfo.buf, block, bufinfo.len / SDCARD_BLOCK_SIZE)); mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
return mp_obj_new_bool(
sdcard_read_blocks(bufinfo.buf, block, bufinfo.len / SDCARD_BLOCK_SIZE));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SDCard_read_obj, mod_trezorio_SDCard_read); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SDCard_read_obj,
mod_trezorio_SDCard_read);
/// def write(self, block_num: int, buf: bytes) -> bool: /// def write(self, block_num: int, buf: bytes) -> bool:
/// ''' /// '''
/// Writes blocks starting with block_num from buf to the SD card. /// Writes blocks starting with block_num from buf to the SD card.
/// Number of bytes written is length of buf rounded down to multiply of SDCARD_BLOCK_SIZE. /// Number of bytes written is length of buf rounded down to multiply of
/// Returns True if in case of success, False otherwise. /// SDCARD_BLOCK_SIZE. Returns True if in case of success, False otherwise.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_SDCard_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { STATIC mp_obj_t mod_trezorio_SDCard_write(mp_obj_t self, mp_obj_t block_num,
uint32_t block = trezor_obj_get_uint(block_num); mp_obj_t buf) {
mp_buffer_info_t bufinfo; uint32_t block = trezor_obj_get_uint(block_num);
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); mp_buffer_info_t bufinfo;
return mp_obj_new_bool(sdcard_write_blocks(bufinfo.buf, block, bufinfo.len / SDCARD_BLOCK_SIZE)); mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
return mp_obj_new_bool(
sdcard_write_blocks(bufinfo.buf, block, bufinfo.len / SDCARD_BLOCK_SIZE));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SDCard_write_obj, mod_trezorio_SDCard_write); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_SDCard_write_obj,
mod_trezorio_SDCard_write);
STATIC const mp_rom_map_elem_t mod_trezorio_SDCard_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_SDCard_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_present), MP_ROM_PTR(&mod_trezorio_SDCard_present_obj) }, {MP_ROM_QSTR(MP_QSTR_present),
{ MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&mod_trezorio_SDCard_power_obj) }, MP_ROM_PTR(&mod_trezorio_SDCard_present_obj)},
{ MP_ROM_QSTR(MP_QSTR_capacity), MP_ROM_PTR(&mod_trezorio_SDCard_capacity_obj) }, {MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&mod_trezorio_SDCard_power_obj)},
{ MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE) }, {MP_ROM_QSTR(MP_QSTR_capacity),
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_SDCard_read_obj) }, MP_ROM_PTR(&mod_trezorio_SDCard_capacity_obj)},
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_SDCard_write_obj) }, {MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE)},
{MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_SDCard_read_obj)},
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_SDCard_write_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_SDCard_locals_dict, mod_trezorio_SDCard_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_SDCard_locals_dict,
mod_trezorio_SDCard_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_SDCard_type = { STATIC const mp_obj_type_t mod_trezorio_SDCard_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_SDCard, .name = MP_QSTR_SDCard,
.make_new = mod_trezorio_SDCard_make_new, .make_new = mod_trezorio_SDCard_make_new,
.locals_dict = (void*)&mod_trezorio_SDCard_locals_dict, .locals_dict = (void *)&mod_trezorio_SDCard_locals_dict,
}; };

@ -20,8 +20,8 @@
void mp_hal_set_vcp_iface(int iface_num); void mp_hal_set_vcp_iface(int iface_num);
enum { enum {
USB_CLOSED = 0, USB_CLOSED = 0,
USB_OPENED = 1, USB_OPENED = 1,
}; };
/// class USB: /// class USB:
@ -29,24 +29,24 @@ enum {
/// USB device configuration. /// USB device configuration.
/// ''' /// '''
typedef struct _mp_obj_USB_t { typedef struct _mp_obj_USB_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_obj_list_t ifaces; mp_obj_list_t ifaces;
usb_dev_info_t info; usb_dev_info_t info;
mp_int_t state; mp_int_t state;
} mp_obj_USB_t; } mp_obj_USB_t;
static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) { static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) {
size_t len; size_t len;
const char *s = mp_obj_str_get_data(o, &len); const char *s = mp_obj_str_get_data(o, &len);
if ((len >= min_len) && (len <= max_len)) { if ((len >= min_len) && (len <= max_len)) {
if (len == 0 && s == NULL) { if (len == 0 && s == NULL) {
return ""; return "";
} else {
return s;
}
} else { } else {
return NULL; return s;
} }
} else {
return NULL;
}
} }
/// def __init__(self, /// def __init__(self,
@ -64,78 +64,94 @@ static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) {
/// usb21_landing: bool=True) -> None: /// usb21_landing: bool=True) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_USB_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_USB_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
STATIC const mp_arg_t allowed_args[] = { const mp_obj_t *args) {
{ MP_QSTR_device_class, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, STATIC const mp_arg_t allowed_args[] = {
{ MP_QSTR_device_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, {MP_QSTR_device_class, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{ MP_QSTR_device_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, {MP_QSTR_device_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{ MP_QSTR_vendor_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, {MP_QSTR_device_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{ MP_QSTR_product_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, {MP_QSTR_vendor_id,
{ MP_QSTR_release_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{ MP_QSTR_manufacturer, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {.u_int = 0}},
{ MP_QSTR_product, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {MP_QSTR_product_id,
{ MP_QSTR_serial_number, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{ MP_QSTR_interface, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, {.u_int = 0}},
{ MP_QSTR_usb21_enabled, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, {MP_QSTR_release_num,
{ MP_QSTR_usb21_landing, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
}; {.u_int = 0}},
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; {MP_QSTR_manufacturer,
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
const mp_int_t device_class = vals[0].u_int; {MP_QSTR_product,
const mp_int_t device_subclass = vals[1].u_int; MP_ARG_KW_ONLY | MP_ARG_OBJ,
const mp_int_t device_protocol = vals[2].u_int; {.u_obj = mp_const_empty_bytes}},
const mp_int_t vendor_id = vals[3].u_int; {MP_QSTR_serial_number,
const mp_int_t product_id = vals[4].u_int; MP_ARG_KW_ONLY | MP_ARG_OBJ,
const mp_int_t release_num = vals[5].u_int; {.u_obj = mp_const_empty_bytes}},
const char *manufacturer = get_0str(vals[6].u_obj, 0, 32); {MP_QSTR_interface,
const char *product = get_0str(vals[7].u_obj, 0, 32); MP_ARG_KW_ONLY | MP_ARG_OBJ,
const char *serial_number = get_0str(vals[8].u_obj, 0, 32); {.u_obj = mp_const_empty_bytes}},
const char *interface = get_0str(vals[9].u_obj, 0, 32); {MP_QSTR_usb21_enabled, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true}},
const secbool usb21_enabled = vals[10].u_bool ? sectrue : secfalse; {MP_QSTR_usb21_landing, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true}},
const secbool usb21_landing = vals[11].u_bool ? sectrue : secfalse; };
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
CHECK_PARAM_RANGE(device_class, 0, 255) mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
CHECK_PARAM_RANGE(device_subclass, 0, 255) allowed_args, vals);
CHECK_PARAM_RANGE(device_protocol, 0, 255)
CHECK_PARAM_RANGE(vendor_id, 0, 65535) const mp_int_t device_class = vals[0].u_int;
CHECK_PARAM_RANGE(product_id, 0, 65535) const mp_int_t device_subclass = vals[1].u_int;
CHECK_PARAM_RANGE(release_num, 0, 65535) const mp_int_t device_protocol = vals[2].u_int;
if (manufacturer == NULL) { const mp_int_t vendor_id = vals[3].u_int;
mp_raise_ValueError("manufacturer is invalid"); const mp_int_t product_id = vals[4].u_int;
} const mp_int_t release_num = vals[5].u_int;
if (product == NULL) { const char *manufacturer = get_0str(vals[6].u_obj, 0, 32);
mp_raise_ValueError("product is invalid"); const char *product = get_0str(vals[7].u_obj, 0, 32);
} const char *serial_number = get_0str(vals[8].u_obj, 0, 32);
if (serial_number == NULL) { const char *interface = get_0str(vals[9].u_obj, 0, 32);
mp_raise_ValueError("serial_number is invalid"); const secbool usb21_enabled = vals[10].u_bool ? sectrue : secfalse;
} const secbool usb21_landing = vals[11].u_bool ? sectrue : secfalse;
if (interface == NULL) {
mp_raise_ValueError("interface is invalid"); CHECK_PARAM_RANGE(device_class, 0, 255)
} CHECK_PARAM_RANGE(device_subclass, 0, 255)
CHECK_PARAM_RANGE(device_protocol, 0, 255)
mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t); CHECK_PARAM_RANGE(vendor_id, 0, 65535)
o->base.type = type; CHECK_PARAM_RANGE(product_id, 0, 65535)
CHECK_PARAM_RANGE(release_num, 0, 65535)
o->state = USB_CLOSED; if (manufacturer == NULL) {
mp_raise_ValueError("manufacturer is invalid");
o->info.device_class = (uint8_t)(device_class); }
o->info.device_subclass = (uint8_t)(device_subclass); if (product == NULL) {
o->info.device_protocol = (uint8_t)(device_protocol); mp_raise_ValueError("product is invalid");
o->info.vendor_id = (uint16_t)(vendor_id); }
o->info.product_id = (uint16_t)(product_id); if (serial_number == NULL) {
o->info.release_num = (uint16_t)(release_num); mp_raise_ValueError("serial_number is invalid");
o->info.manufacturer = manufacturer; }
o->info.product = product; if (interface == NULL) {
o->info.serial_number = serial_number; mp_raise_ValueError("interface is invalid");
o->info.interface = interface; }
o->info.usb21_enabled = usb21_enabled;
o->info.usb21_landing = usb21_landing; mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t);
o->base.type = type;
mp_obj_list_init(&o->ifaces, 0);
o->state = USB_CLOSED;
return MP_OBJ_FROM_PTR(o);
o->info.device_class = (uint8_t)(device_class);
o->info.device_subclass = (uint8_t)(device_subclass);
o->info.device_protocol = (uint8_t)(device_protocol);
o->info.vendor_id = (uint16_t)(vendor_id);
o->info.product_id = (uint16_t)(product_id);
o->info.release_num = (uint16_t)(release_num);
o->info.manufacturer = manufacturer;
o->info.product = product;
o->info.serial_number = serial_number;
o->info.interface = interface;
o->info.usb21_enabled = usb21_enabled;
o->info.usb21_landing = usb21_landing;
mp_obj_list_init(&o->ifaces, 0);
return MP_OBJ_FROM_PTR(o);
} }
/// def add(self, iface: Union[HID, VCP, WebUSB]) -> None: /// def add(self, iface: Union[HID, VCP, WebUSB]) -> None:
@ -143,126 +159,131 @@ STATIC mp_obj_t mod_trezorio_USB_make_new(const mp_obj_type_t *type, size_t n_ar
/// Registers passed interface into the USB stack. /// Registers passed interface into the USB stack.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_USB_add(mp_obj_t self, mp_obj_t iface) { STATIC mp_obj_t mod_trezorio_USB_add(mp_obj_t self, mp_obj_t iface) {
mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); mp_obj_USB_t *o = MP_OBJ_TO_PTR(self);
if (o->state != USB_CLOSED) { if (o->state != USB_CLOSED) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized"); mp_raise_msg(&mp_type_RuntimeError, "already initialized");
} }
mp_obj_list_append(MP_OBJ_FROM_PTR(&o->ifaces), iface); mp_obj_list_append(MP_OBJ_FROM_PTR(&o->ifaces), iface);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_USB_add_obj, mod_trezorio_USB_add); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_USB_add_obj,
mod_trezorio_USB_add);
/// def open(self) -> None: /// def open(self) -> None:
/// ''' /// '''
/// Initializes the USB stack. /// Initializes the USB stack.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_USB_open(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_USB_open(mp_obj_t self) {
mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); mp_obj_USB_t *o = MP_OBJ_TO_PTR(self);
if (o->state != USB_CLOSED) { if (o->state != USB_CLOSED) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized"); mp_raise_msg(&mp_type_RuntimeError, "already initialized");
} }
size_t iface_cnt; size_t iface_cnt;
mp_obj_t *iface_objs; mp_obj_t *iface_objs;
mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs); mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs);
// Initialize the USB stack // Initialize the USB stack
usb_init(&o->info); usb_init(&o->info);
int vcp_iface_num = -1; int vcp_iface_num = -1;
// Add all interfaces // Add all interfaces
for (size_t i = 0; i < iface_cnt; i++) { for (size_t i = 0; i < iface_cnt; i++) {
mp_obj_t iface = iface_objs[i]; mp_obj_t iface = iface_objs[i];
if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_HID_type)) { if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_HID_type)) {
mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface); mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_hid_add(&hid->info)) { if (sectrue != usb_hid_add(&hid->info)) {
usb_deinit(); usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add HID interface"); mp_raise_msg(&mp_type_RuntimeError, "failed to add HID interface");
} }
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_WebUSB_type)) { } else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_WebUSB_type)) {
mp_obj_WebUSB_t *webusb = MP_OBJ_TO_PTR(iface); mp_obj_WebUSB_t *webusb = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_webusb_add(&webusb->info)) { if (sectrue != usb_webusb_add(&webusb->info)) {
usb_deinit(); usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add WebUSB interface"); mp_raise_msg(&mp_type_RuntimeError, "failed to add WebUSB interface");
} }
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_VCP_type)) { } else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_VCP_type)) {
mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface); mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_vcp_add(&vcp->info)) { if (sectrue != usb_vcp_add(&vcp->info)) {
usb_deinit(); usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface"); mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface");
} }
vcp_iface_num = vcp->info.iface_num; vcp_iface_num = vcp->info.iface_num;
} else { } else {
usb_deinit(); usb_deinit();
mp_raise_TypeError("expected HID, WebUSB or VCP type"); mp_raise_TypeError("expected HID, WebUSB or VCP type");
}
} }
}
// Start the USB stack // Start the USB stack
usb_start(); usb_start();
o->state = USB_OPENED; o->state = USB_OPENED;
// If we found any VCP interfaces, use the last one for stdio, // If we found any VCP interfaces, use the last one for stdio,
// otherwise disable the stdio support // otherwise disable the stdio support
mp_hal_set_vcp_iface(vcp_iface_num); mp_hal_set_vcp_iface(vcp_iface_num);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_open_obj, mod_trezorio_USB_open); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_open_obj,
mod_trezorio_USB_open);
/// def close(self) -> None: /// def close(self) -> None:
/// ''' /// '''
/// Cleans up the USB stack. /// Cleans up the USB stack.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_USB_close(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_USB_close(mp_obj_t self) {
mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); mp_obj_USB_t *o = MP_OBJ_TO_PTR(self);
if (o->state != USB_OPENED) {
mp_raise_msg(&mp_type_RuntimeError, "not initialized");
}
usb_stop();
usb_deinit();
mp_obj_list_set_len(MP_OBJ_FROM_PTR(&o->ifaces), 0);
mp_seq_clear(o->ifaces.items, 0, o->ifaces.alloc, sizeof(*o->ifaces.items));
o->info.vendor_id = 0;
o->info.product_id = 0;
o->info.release_num = 0;
o->info.manufacturer = NULL;
o->info.product = NULL;
o->info.serial_number = NULL;
o->state = USB_CLOSED;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_close_obj,
mod_trezorio_USB_close);
if (o->state != USB_OPENED) { STATIC mp_obj_t mod_trezorio_USB___del__(mp_obj_t self) {
mp_raise_msg(&mp_type_RuntimeError, "not initialized"); mp_obj_USB_t *o = MP_OBJ_TO_PTR(self);
} if (o->state != USB_CLOSED) {
usb_stop(); usb_stop();
usb_deinit(); usb_deinit();
mp_obj_list_set_len(MP_OBJ_FROM_PTR(&o->ifaces), 0);
mp_seq_clear(o->ifaces.items, 0, o->ifaces.alloc, sizeof(*o->ifaces.items));
o->info.vendor_id = 0;
o->info.product_id = 0;
o->info.release_num = 0;
o->info.manufacturer = NULL;
o->info.product = NULL;
o->info.serial_number = NULL;
o->state = USB_CLOSED; o->state = USB_CLOSED;
}
return mp_const_none; return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_close_obj, mod_trezorio_USB_close);
STATIC mp_obj_t mod_trezorio_USB___del__(mp_obj_t self) {
mp_obj_USB_t *o = MP_OBJ_TO_PTR(self);
if (o->state != USB_CLOSED) {
usb_stop();
usb_deinit();
o->state = USB_CLOSED;
}
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB___del___obj, mod_trezorio_USB___del__); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB___del___obj,
mod_trezorio_USB___del__);
STATIC const mp_rom_map_elem_t mod_trezorio_USB_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_USB_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&mod_trezorio_USB_add_obj) }, {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&mod_trezorio_USB_add_obj)},
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_USB_open_obj) }, {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_USB_open_obj)},
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mod_trezorio_USB_close_obj) }, {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mod_trezorio_USB_close_obj)},
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorio_USB___del___obj) }, {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorio_USB___del___obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_USB_locals_dict, mod_trezorio_USB_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_USB_locals_dict,
mod_trezorio_USB_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_USB_type = { STATIC const mp_obj_type_t mod_trezorio_USB_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_USB, .name = MP_QSTR_USB,
.make_new = mod_trezorio_USB_make_new, .make_new = mod_trezorio_USB_make_new,
.locals_dict = (void*)&mod_trezorio_USB_locals_dict, .locals_dict = (void *)&mod_trezorio_USB_locals_dict,
}; };

@ -24,8 +24,8 @@ void pendsv_kbd_intr(void);
/// USB VCP interface configuration. /// USB VCP interface configuration.
/// ''' /// '''
typedef struct _mp_obj_VCP_t { typedef struct _mp_obj_VCP_t {
mp_obj_base_t base; mp_obj_base_t base;
usb_vcp_info_t info; usb_vcp_info_t info;
} mp_obj_VCP_t; } mp_obj_VCP_t;
/// def __init__(self, /// def __init__(self,
@ -36,53 +36,65 @@ typedef struct _mp_obj_VCP_t {
/// ep_cmd: int) -> None: /// ep_cmd: int) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_VCP_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_VCP_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
STATIC const mp_arg_t allowed_args[] = {
{MP_QSTR_iface_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_data_iface_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_in,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_out,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_cmd,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
allowed_args, vals);
STATIC const mp_arg_t allowed_args[] = { const mp_int_t iface_num = vals[0].u_int;
{ MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t data_iface_num = vals[1].u_int;
{ MP_QSTR_data_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_in = vals[2].u_int;
{ MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_out = vals[3].u_int;
{ MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_cmd = vals[4].u_int;
{ MP_QSTR_ep_cmd, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
const mp_int_t iface_num = vals[0].u_int; CHECK_PARAM_RANGE(iface_num, 0, 32)
const mp_int_t data_iface_num = vals[1].u_int; CHECK_PARAM_RANGE(data_iface_num, 0, 32)
const mp_int_t ep_in = vals[2].u_int; CHECK_PARAM_RANGE(ep_in, 0, 255)
const mp_int_t ep_out = vals[3].u_int; CHECK_PARAM_RANGE(ep_out, 0, 255)
const mp_int_t ep_cmd = vals[4].u_int; CHECK_PARAM_RANGE(ep_cmd, 0, 255)
CHECK_PARAM_RANGE(iface_num, 0, 32) const size_t vcp_buffer_len = 1024;
CHECK_PARAM_RANGE(data_iface_num, 0, 32) const size_t vcp_packet_len = 64;
CHECK_PARAM_RANGE(ep_in, 0, 255)
CHECK_PARAM_RANGE(ep_out, 0, 255)
CHECK_PARAM_RANGE(ep_cmd, 0, 255)
const size_t vcp_buffer_len = 1024; mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t);
const size_t vcp_packet_len = 64; o->base.type = type;
mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t); o->info.tx_packet = m_new(uint8_t, vcp_packet_len);
o->base.type = type; o->info.tx_buffer = m_new(uint8_t, vcp_buffer_len);
o->info.rx_packet = m_new(uint8_t, vcp_packet_len);
o->info.rx_buffer = m_new(uint8_t, vcp_buffer_len);
o->info.tx_buffer_len = vcp_buffer_len;
o->info.rx_buffer_len = vcp_buffer_len;
o->info.rx_intr_fn = pendsv_kbd_intr;
o->info.rx_intr_byte = 3; // Ctrl-C
o->info.iface_num = (uint8_t)(iface_num);
o->info.data_iface_num = (uint8_t)(data_iface_num);
o->info.ep_cmd = (uint8_t)(ep_cmd);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.polling_interval = 10;
o->info.max_packet_len = (uint8_t)(vcp_packet_len);
o->info.tx_packet = m_new(uint8_t, vcp_packet_len); return MP_OBJ_FROM_PTR(o);
o->info.tx_buffer = m_new(uint8_t, vcp_buffer_len);
o->info.rx_packet = m_new(uint8_t, vcp_packet_len);
o->info.rx_buffer = m_new(uint8_t, vcp_buffer_len);
o->info.tx_buffer_len = vcp_buffer_len;
o->info.rx_buffer_len = vcp_buffer_len;
o->info.rx_intr_fn = pendsv_kbd_intr;
o->info.rx_intr_byte = 3; // Ctrl-C
o->info.iface_num = (uint8_t)(iface_num);
o->info.data_iface_num = (uint8_t)(data_iface_num);
o->info.ep_cmd = (uint8_t)(ep_cmd);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.polling_interval = 10;
o->info.max_packet_len = (uint8_t)(vcp_packet_len);
return MP_OBJ_FROM_PTR(o);
} }
/// def iface_num(self) -> int: /// def iface_num(self) -> int:
@ -90,19 +102,22 @@ STATIC mp_obj_t mod_trezorio_VCP_make_new(const mp_obj_type_t *type, size_t n_ar
/// Returns the configured number of this interface. /// Returns the configured number of this interface.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_VCP_iface_num(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_VCP_iface_num(mp_obj_t self) {
mp_obj_VCP_t *o = MP_OBJ_TO_PTR(self); mp_obj_VCP_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num); return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_VCP_iface_num_obj, mod_trezorio_VCP_iface_num); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_VCP_iface_num_obj,
mod_trezorio_VCP_iface_num);
STATIC const mp_rom_map_elem_t mod_trezorio_VCP_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_VCP_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_iface_num), MP_ROM_PTR(&mod_trezorio_VCP_iface_num_obj) }, {MP_ROM_QSTR(MP_QSTR_iface_num),
MP_ROM_PTR(&mod_trezorio_VCP_iface_num_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_VCP_locals_dict, mod_trezorio_VCP_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_VCP_locals_dict,
mod_trezorio_VCP_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_VCP_type = { STATIC const mp_obj_type_t mod_trezorio_VCP_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_VCP, .name = MP_QSTR_VCP,
.make_new = mod_trezorio_VCP_make_new, .make_new = mod_trezorio_VCP_make_new,
.locals_dict = (void*)&mod_trezorio_VCP_locals_dict, .locals_dict = (void *)&mod_trezorio_VCP_locals_dict,
}; };

@ -22,8 +22,8 @@
/// USB WebUSB interface configuration. /// USB WebUSB interface configuration.
/// ''' /// '''
typedef struct _mp_obj_WebUSB_t { typedef struct _mp_obj_WebUSB_t {
mp_obj_base_t base; mp_obj_base_t base;
usb_webusb_info_t info; usb_webusb_info_t info;
} mp_obj_WebUSB_t; } mp_obj_WebUSB_t;
/// def __init__(self, /// def __init__(self,
@ -36,49 +36,57 @@ typedef struct _mp_obj_WebUSB_t {
/// max_packet_len: int = 64) -> None: /// max_packet_len: int = 64) -> None:
/// ''' /// '''
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_WebUSB_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorio_WebUSB_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
STATIC const mp_arg_t allowed_args[] = {
{MP_QSTR_iface_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_in,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_ep_out,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1}},
{MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64}},
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
allowed_args, vals);
STATIC const mp_arg_t allowed_args[] = { const mp_int_t iface_num = vals[0].u_int;
{ MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_in = vals[1].u_int;
{ MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t ep_out = vals[2].u_int;
{ MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t subclass = vals[3].u_int;
{ MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t protocol = vals[4].u_int;
{ MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, const mp_int_t polling_interval = vals[5].u_int;
{ MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, const mp_int_t max_packet_len = vals[6].u_int;
{ MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
const mp_int_t iface_num = vals[0].u_int; CHECK_PARAM_RANGE(iface_num, 0, 32)
const mp_int_t ep_in = vals[1].u_int; CHECK_PARAM_RANGE(ep_in, 0, 255)
const mp_int_t ep_out = vals[2].u_int; CHECK_PARAM_RANGE(ep_out, 0, 255)
const mp_int_t subclass = vals[3].u_int; CHECK_PARAM_RANGE(subclass, 0, 255)
const mp_int_t protocol = vals[4].u_int; CHECK_PARAM_RANGE(protocol, 0, 255)
const mp_int_t polling_interval = vals[5].u_int; CHECK_PARAM_RANGE(polling_interval, 1, 255)
const mp_int_t max_packet_len = vals[6].u_int; CHECK_PARAM_RANGE(max_packet_len, 64, 64)
CHECK_PARAM_RANGE(iface_num, 0, 32) mp_obj_WebUSB_t *o = m_new_obj(mp_obj_WebUSB_t);
CHECK_PARAM_RANGE(ep_in, 0, 255) o->base.type = type;
CHECK_PARAM_RANGE(ep_out, 0, 255)
CHECK_PARAM_RANGE(subclass, 0, 255)
CHECK_PARAM_RANGE(protocol, 0, 255)
CHECK_PARAM_RANGE(polling_interval, 1, 255)
CHECK_PARAM_RANGE(max_packet_len, 64, 64)
mp_obj_WebUSB_t *o = m_new_obj(mp_obj_WebUSB_t); o->info.rx_buffer = m_new(uint8_t, max_packet_len);
o->base.type = type; o->info.iface_num = (uint8_t)(iface_num);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.subclass = (uint8_t)(subclass);
o->info.protocol = (uint8_t)(protocol);
o->info.polling_interval = (uint8_t)(polling_interval);
o->info.max_packet_len = (uint8_t)(max_packet_len);
o->info.rx_buffer = m_new(uint8_t, max_packet_len); return MP_OBJ_FROM_PTR(o);
o->info.iface_num = (uint8_t)(iface_num);
o->info.ep_in = (uint8_t)(ep_in);
o->info.ep_out = (uint8_t)(ep_out);
o->info.subclass = (uint8_t)(subclass);
o->info.protocol = (uint8_t)(protocol);
o->info.polling_interval = (uint8_t)(polling_interval);
o->info.max_packet_len = (uint8_t)(max_packet_len);
return MP_OBJ_FROM_PTR(o);
} }
/// def iface_num(self) -> int: /// def iface_num(self) -> int:
@ -86,33 +94,37 @@ STATIC mp_obj_t mod_trezorio_WebUSB_make_new(const mp_obj_type_t *type, size_t n
/// Returns the configured number of this interface. /// Returns the configured number of this interface.
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_WebUSB_iface_num(mp_obj_t self) { STATIC mp_obj_t mod_trezorio_WebUSB_iface_num(mp_obj_t self) {
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self); mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num); return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_WebUSB_iface_num_obj, mod_trezorio_WebUSB_iface_num); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_WebUSB_iface_num_obj,
mod_trezorio_WebUSB_iface_num);
/// def write(self, msg: bytes) -> int: /// def write(self, msg: bytes) -> int:
/// ''' /// '''
/// Sends message using USB WebUSB (device) or UDP (emulator). /// Sends message using USB WebUSB (device) or UDP (emulator).
/// ''' /// '''
STATIC mp_obj_t mod_trezorio_WebUSB_write(mp_obj_t self, mp_obj_t msg) { STATIC mp_obj_t mod_trezorio_WebUSB_write(mp_obj_t self, mp_obj_t msg) {
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self); mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf; mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ); mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_webusb_write(o->info.iface_num, buf.buf, buf.len); ssize_t r = usb_webusb_write(o->info.iface_num, buf.buf, buf.len);
return MP_OBJ_NEW_SMALL_INT(r); return MP_OBJ_NEW_SMALL_INT(r);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_WebUSB_write_obj, mod_trezorio_WebUSB_write); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_WebUSB_write_obj,
mod_trezorio_WebUSB_write);
STATIC const mp_rom_map_elem_t mod_trezorio_WebUSB_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorio_WebUSB_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_iface_num), MP_ROM_PTR(&mod_trezorio_WebUSB_iface_num_obj) }, {MP_ROM_QSTR(MP_QSTR_iface_num),
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_WebUSB_write_obj) }, MP_ROM_PTR(&mod_trezorio_WebUSB_iface_num_obj)},
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_WebUSB_write_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_WebUSB_locals_dict, mod_trezorio_WebUSB_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorio_WebUSB_locals_dict,
mod_trezorio_WebUSB_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_WebUSB_type = { STATIC const mp_obj_type_t mod_trezorio_WebUSB_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_WebUSB, .name = MP_QSTR_WebUSB,
.make_new = mod_trezorio_WebUSB_make_new, .make_new = mod_trezorio_WebUSB_make_new,
.locals_dict = (void*)&mod_trezorio_WebUSB_locals_dict, .locals_dict = (void *)&mod_trezorio_WebUSB_locals_dict,
}; };

@ -17,52 +17,66 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "py/runtime.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "py/objstr.h" #include "py/objstr.h"
#include "py/runtime.h"
#if MICROPY_PY_TREZORIO #if MICROPY_PY_TREZORIO
#include <unistd.h>
#include "touch.h" #include "touch.h"
#include "usb.h"
#define CHECK_PARAM_RANGE(value, minimum, maximum) \
if (value < minimum || value > maximum) { \
mp_raise_ValueError(#value " is out of range"); \
}
// clang-format off
#include "modtrezorio-flash.h" #include "modtrezorio-flash.h"
#include "modtrezorio-hid.h"
#include "modtrezorio-poll.h"
#include "modtrezorio-sbu.h" #include "modtrezorio-sbu.h"
#include "modtrezorio-sdcard.h" #include "modtrezorio-sdcard.h"
#include "modtrezorio-poll.h"
#include "modtrezorio-hid.h"
#include "modtrezorio-vcp.h" #include "modtrezorio-vcp.h"
#include "modtrezorio-webusb.h" #include "modtrezorio-webusb.h"
#include "modtrezorio-usb.h" #include "modtrezorio-usb.h"
// clang-format on
STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorio) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorio)},
{ MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type) }, {MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type)},
{ MP_ROM_QSTR(MP_QSTR_SBU), MP_ROM_PTR(&mod_trezorio_SBU_type) }, {MP_ROM_QSTR(MP_QSTR_SBU), MP_ROM_PTR(&mod_trezorio_SBU_type)},
{ MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&mod_trezorio_SDCard_type) }, {MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&mod_trezorio_SDCard_type)},
{ MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_trezorio_USB_type) }, {MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_trezorio_USB_type)},
{ MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_trezorio_HID_type) }, {MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_trezorio_HID_type)},
{ MP_ROM_QSTR(MP_QSTR_VCP), MP_ROM_PTR(&mod_trezorio_VCP_type) }, {MP_ROM_QSTR(MP_QSTR_VCP), MP_ROM_PTR(&mod_trezorio_VCP_type)},
{ MP_ROM_QSTR(MP_QSTR_WebUSB), MP_ROM_PTR(&mod_trezorio_WebUSB_type) }, {MP_ROM_QSTR(MP_QSTR_WebUSB), MP_ROM_PTR(&mod_trezorio_WebUSB_type)},
{ MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mod_trezorio_poll_obj) }, {MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mod_trezorio_poll_obj)},
{ MP_ROM_QSTR(MP_QSTR_POLL_READ), MP_OBJ_NEW_SMALL_INT(POLL_READ) }, {MP_ROM_QSTR(MP_QSTR_POLL_READ), MP_OBJ_NEW_SMALL_INT(POLL_READ)},
{ MP_ROM_QSTR(MP_QSTR_POLL_WRITE), MP_OBJ_NEW_SMALL_INT(POLL_WRITE) }, {MP_ROM_QSTR(MP_QSTR_POLL_WRITE), MP_OBJ_NEW_SMALL_INT(POLL_WRITE)},
{ MP_ROM_QSTR(MP_QSTR_TOUCH), MP_OBJ_NEW_SMALL_INT(TOUCH_IFACE) }, {MP_ROM_QSTR(MP_QSTR_TOUCH), MP_OBJ_NEW_SMALL_INT(TOUCH_IFACE)},
{ MP_ROM_QSTR(MP_QSTR_TOUCH_START), MP_OBJ_NEW_SMALL_INT((TOUCH_START >> 24) & 0xFFU) }, {MP_ROM_QSTR(MP_QSTR_TOUCH_START),
{ MP_ROM_QSTR(MP_QSTR_TOUCH_MOVE), MP_OBJ_NEW_SMALL_INT((TOUCH_MOVE >> 24) & 0xFFU) }, MP_OBJ_NEW_SMALL_INT((TOUCH_START >> 24) & 0xFFU)},
{ MP_ROM_QSTR(MP_QSTR_TOUCH_END), MP_OBJ_NEW_SMALL_INT((TOUCH_END >> 24) & 0xFFU) }, {MP_ROM_QSTR(MP_QSTR_TOUCH_MOVE),
MP_OBJ_NEW_SMALL_INT((TOUCH_MOVE >> 24) & 0xFFU)},
{MP_ROM_QSTR(MP_QSTR_TOUCH_END),
MP_OBJ_NEW_SMALL_INT((TOUCH_END >> 24) & 0xFFU)},
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorio_globals, mp_module_trezorio_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_trezorio_globals,
mp_module_trezorio_globals_table);
const mp_obj_module_t mp_module_trezorio = { const mp_obj_module_t mp_module_trezorio = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mp_module_trezorio_globals, .globals = (mp_obj_dict_t*)&mp_module_trezorio_globals,
}; };
#endif // MICROPY_PY_TREZORIO #endif // MICROPY_PY_TREZORIO

@ -19,231 +19,226 @@
#include STM32_HAL_H #include STM32_HAL_H
#define OLED_BUFSIZE (DISPLAY_RESX * DISPLAY_RESY / 8) #define OLED_BUFSIZE (DISPLAY_RESX * DISPLAY_RESY / 8)
#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y)/8) * DISPLAY_RESX) #define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y) / 8) * DISPLAY_RESX)
#define OLED_MASK(x, y) (1 << (7 - (y) % 8)) #define OLED_MASK(x, y) (1 << (7 - (y) % 8))
#define OLED_SETCONTRAST 0x81 #define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4 #define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5 #define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6 #define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7 #define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE #define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF #define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3 #define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA #define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB #define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5 #define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9 #define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8 #define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00 #define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10 #define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40 #define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20 #define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0 #define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8 #define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0 #define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D #define OLED_CHARGEPUMP 0x8D
#define OLED_DC_PORT GPIOB #define OLED_DC_PORT GPIOB
#define OLED_DC_PIN GPIO_PIN_0 // PB0 | Data/Command #define OLED_DC_PIN GPIO_PIN_0 // PB0 | Data/Command
#define OLED_CS_PORT GPIOA #define OLED_CS_PORT GPIOA
#define OLED_CS_PIN GPIO_PIN_4 // PA4 | SPI Select #define OLED_CS_PIN GPIO_PIN_4 // PA4 | SPI Select
#define OLED_RST_PORT GPIOB #define OLED_RST_PORT GPIOB
#define OLED_RST_PIN GPIO_PIN_1 // PB1 | Reset display #define OLED_RST_PIN GPIO_PIN_1 // PB1 | Reset display
static uint8_t OLED_BUFFER[OLED_BUFSIZE]; static uint8_t OLED_BUFFER[OLED_BUFSIZE];
static struct { static struct {
struct { struct {
uint16_t x, y; uint16_t x, y;
} start; } start;
struct { struct {
uint16_t x, y; uint16_t x, y;
} end; } end;
struct { struct {
uint16_t x, y; uint16_t x, y;
} pos; } pos;
} PIXELWINDOW; } PIXELWINDOW;
void PIXELDATA(uint16_t c) { void PIXELDATA(uint16_t c) {
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) { if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x &&
// set to white if highest bits of all R, G, B values are set to 1 PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
// bin(10000 100000 10000) = hex(0x8410) // set to white if highest bits of all R, G, B values are set to 1
// otherwise set to black // bin(10000 100000 10000) = hex(0x8410)
if (c & 0x8410) { // otherwise set to black
OLED_BUFFER[OLED_OFFSET(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y)] |= OLED_MASK(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y); if (c & 0x8410) {
} else { OLED_BUFFER[OLED_OFFSET(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y)] |=
OLED_BUFFER[OLED_OFFSET(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y)] &= ~OLED_MASK(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y); OLED_MASK(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y);
} } else {
} OLED_BUFFER[OLED_OFFSET(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y)] &=
PIXELWINDOW.pos.x++; ~OLED_MASK(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y);
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
} }
}
PIXELWINDOW.pos.x++;
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
}
} }
static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
{ uint16_t y1) {
PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0; PIXELWINDOW.start.x = x0;
PIXELWINDOW.end.x = x1; PIXELWINDOW.end.y = y1; PIXELWINDOW.start.y = y0;
PIXELWINDOW.pos.x = x0; PIXELWINDOW.pos.y = y0; PIXELWINDOW.end.x = x1;
PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0;
PIXELWINDOW.pos.y = y0;
} }
static void display_set_orientation(int degrees) static void display_set_orientation(int degrees) { display_refresh(); }
{
display_refresh();
}
static void display_set_backlight(int val) static void display_set_backlight(int val) {}
{
}
SPI_HandleTypeDef spi_handle; SPI_HandleTypeDef spi_handle;
static inline void spi_send(const uint8_t *data, int len) static inline void spi_send(const uint8_t *data, int len) {
{ HAL_Delay(1);
HAL_Delay(1); if (HAL_OK != HAL_SPI_Transmit(&spi_handle, (uint8_t *)data, len, 1000)) {
if (HAL_OK != HAL_SPI_Transmit(&spi_handle, (uint8_t *)data, len, 1000)) { // TODO: error
// TODO: error return;
return; }
} while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&spi_handle)) {
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&spi_handle)) { }
}
} }
void display_init(void) void display_init(void) {
{ __HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// set GPIO for OLED display
// set GPIO for OLED display GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Alternate = 0; GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.Pin = GPIO_PIN_4; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_4;
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_4; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_4, GPIO_PIN_RESET); HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// enable SPI 1 for OLED display
// enable SPI 1 for OLED display GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1; GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
spi_handle.Instance = SPI1;
spi_handle.Instance = SPI1; spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
spi_handle.Init.Direction = SPI_DIRECTION_2LINES; spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE; spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW; spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; spi_handle.Init.CRCPolynomial = 7;
spi_handle.Init.CRCPolynomial = 7; spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
spi_handle.Init.DataSize = SPI_DATASIZE_8BIT; spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB; spi_handle.Init.NSS = SPI_NSS_HARD_OUTPUT;
spi_handle.Init.NSS = SPI_NSS_HARD_OUTPUT; spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
spi_handle.Init.TIMode = SPI_TIMODE_DISABLE; spi_handle.Init.Mode = SPI_MODE_MASTER;
spi_handle.Init.Mode = SPI_MODE_MASTER; if (HAL_OK != HAL_SPI_Init(&spi_handle)) {
if (HAL_OK != HAL_SPI_Init(&spi_handle)) { // TODO: error
// TODO: error return;
return; }
}
// initialize display
// initialize display
static const uint8_t s[25] = {OLED_DISPLAYOFF,
static const uint8_t s[25] = { OLED_SETDISPLAYCLOCKDIV,
OLED_DISPLAYOFF, 0x80,
OLED_SETDISPLAYCLOCKDIV, OLED_SETMULTIPLEX,
0x80, 0x3F, // 128x64
OLED_SETMULTIPLEX, OLED_SETDISPLAYOFFSET,
0x3F, // 128x64 0x00,
OLED_SETDISPLAYOFFSET, OLED_SETSTARTLINE | 0x00,
0x00, OLED_CHARGEPUMP,
OLED_SETSTARTLINE | 0x00, 0x14,
OLED_CHARGEPUMP, OLED_MEMORYMODE,
0x14, 0x00,
OLED_MEMORYMODE, OLED_SEGREMAP | 0x01,
0x00, OLED_COMSCANDEC,
OLED_SEGREMAP | 0x01, OLED_SETCOMPINS,
OLED_COMSCANDEC, 0x12, // 128x64
OLED_SETCOMPINS, OLED_SETCONTRAST,
0x12, // 128x64 0xCF,
OLED_SETCONTRAST, OLED_SETPRECHARGE,
0xCF, 0xF1,
OLED_SETPRECHARGE, OLED_SETVCOMDETECT,
0xF1, 0x40,
OLED_SETVCOMDETECT, OLED_DISPLAYALLON_RESUME,
0x40, OLED_NORMALDISPLAY,
OLED_DISPLAYALLON_RESUME, OLED_DISPLAYON};
OLED_NORMALDISPLAY,
OLED_DISPLAYON HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD
}; HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD // Reset the LCD
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
HAL_Delay(40);
// Reset the LCD HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); HAL_Delay(400);
HAL_Delay(40); HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(400); // init
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
spi_send(s, 25);
// init HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
spi_send(s, 25); display_clear();
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect display_refresh();
display_clear();
display_refresh();
} }
static inline uint8_t reverse_byte(uint8_t b) { static inline uint8_t reverse_byte(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2; b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1; b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b; return b;
} }
static void rotate_oled_buffer(void) static void rotate_oled_buffer(void) {
{ for (int i = 0; i < OLED_BUFSIZE / 2; i++) {
for (int i = 0; i < OLED_BUFSIZE / 2; i++) { uint8_t b = OLED_BUFFER[i];
uint8_t b = OLED_BUFFER[i]; OLED_BUFFER[i] = reverse_byte(OLED_BUFFER[OLED_BUFSIZE - i]);
OLED_BUFFER[i] = reverse_byte(OLED_BUFFER[OLED_BUFSIZE - i]); OLED_BUFFER[OLED_BUFSIZE - i] = reverse_byte(b);
OLED_BUFFER[OLED_BUFSIZE - i] = reverse_byte(b); }
}
} }
void display_refresh(void) void display_refresh(void) {
{ static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00,
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; OLED_SETHIGHCOLUMN | 0x00,
OLED_SETSTARTLINE | 0x00};
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
spi_send(s, 3); HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect spi_send(s, 3);
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET); // set to DATA
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET); // set to DATA
if (DISPLAY_ORIENTATION == 180) { // rotate buffer if needed HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
rotate_oled_buffer(); if (DISPLAY_ORIENTATION == 180) { // rotate buffer if needed
} rotate_oled_buffer();
spi_send(OLED_BUFFER, OLED_BUFSIZE); }
if (DISPLAY_ORIENTATION == 180) { // rotate buffer back to original position spi_send(OLED_BUFFER, OLED_BUFSIZE);
rotate_oled_buffer(); if (DISPLAY_ORIENTATION == 180) { // rotate buffer back to original position
} rotate_oled_buffer();
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect }
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD
} }
void display_save(const char *prefix) void display_save(const char *prefix) {}
{
}

@ -20,332 +20,482 @@
#include STM32_HAL_H #include STM32_HAL_H
// FSMC/FMC Bank 1 - NOR/PSRAM 1 // FSMC/FMC Bank 1 - NOR/PSRAM 1
#define DISPLAY_MEMORY_BASE 0x60000000 #define DISPLAY_MEMORY_BASE 0x60000000
#define DISPLAY_MEMORY_PIN 16 #define DISPLAY_MEMORY_PIN 16
#define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X)) #define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X))
#define ADDR (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | (1 << DISPLAY_MEMORY_PIN))))) #define ADDR \
#define DATA(X) (ADDR) = (X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \
#define PIXELDATA(X) DATA((X) >> 8); DATA((X) & 0xFF) (1 << DISPLAY_MEMORY_PIN)))))
#define DATA(X) (ADDR) = (X)
#define PIXELDATA(X) \
DATA((X) >> 8); \
DATA((X)&0xFF)
#define LED_PWM_TIM_PERIOD (10000) #define LED_PWM_TIM_PERIOD (10000)
#define DISPLAY_ID_ST7789V 0x858552U // section "9.1.3 RDDID (04h): Read Display ID" of ST7789V datasheet #define DISPLAY_ID_ST7789V \
#define DISPLAY_ID_GC9307 0x009307U // section "6.2.1. Read display identification information (04h)" of GC9307 datasheet 0x858552U // section "9.1.3 RDDID (04h): Read Display ID" of ST7789V
#define DISPLAY_ID_ILI9341V 0x009341U // section "8.3.23 Read ID4 (D3h)" of ILI9341V datasheet // datasheet
#define DISPLAY_ID_GC9307 \
0x009307U // section "6.2.1. Read display identification information (04h)"
// of GC9307 datasheet
#define DISPLAY_ID_ILI9341V \
0x009341U // section "8.3.23 Read ID4 (D3h)" of ILI9341V datasheet
static uint32_t read_display_id(uint8_t command) { static uint32_t read_display_id(uint8_t command) {
volatile uint8_t c; volatile uint8_t c;
uint32_t id = 0; uint32_t id = 0;
CMD(command); CMD(command);
c = ADDR; // first returned value is a dummy value and should be discarded c = ADDR; // first returned value is a dummy value and should be discarded
c = ADDR; id |= (c << 16); c = ADDR;
c = ADDR; id |= (c << 8); id |= (c << 16);
c = ADDR; id |= c; c = ADDR;
return id; id |= (c << 8);
c = ADDR;
id |= c;
return id;
} }
static uint32_t display_identify(void) static uint32_t display_identify(void) {
{ static uint32_t id = 0x000000U;
static uint32_t id = 0x000000U; static char id_set = 0;
static char id_set = 0;
if (id_set) return id; // return if id has been already set
if (id_set) return id; // return if id has been already set
id = read_display_id(0x04); // RDDID: Read Display ID
id = read_display_id(0x04); // RDDID: Read Display ID // the default RDDID for ILI9341 should be 0x8000.
// the default RDDID for ILI9341 should be 0x8000. // some display modules return 0x0.
// some display modules return 0x0. // the ILI9341 has an extra id, let's check it here.
// the ILI9341 has an extra id, let's check it here. if ((id != DISPLAY_ID_ST7789V) &&
if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) { // if not ST7789V and not GC9307 (id != DISPLAY_ID_GC9307)) { // if not ST7789V and not GC9307
uint32_t id4 = read_display_id(0xD3); // Read ID4 uint32_t id4 = read_display_id(0xD3); // Read ID4
if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341 if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
id = id4; id = id4;
}
} }
id_set = 1; }
return id; id_set = 1;
return id;
} }
static void __attribute__((unused)) display_sleep(void) static void __attribute__((unused)) display_sleep(void) {
{ uint32_t id = display_identify();
uint32_t id = display_identify(); if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) { (id == DISPLAY_ID_ST7789V)) {
CMD(0x28); // DISPOFF: Display Off CMD(0x28); // DISPOFF: Display Off
CMD(0x10); // SLPIN: Sleep in CMD(0x10); // SLPIN: Sleep in
HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before sending any new commands HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before
} // sending any new commands
}
} }
static void display_unsleep(void) static void display_unsleep(void) {
{ uint32_t id = display_identify();
uint32_t id = display_identify(); if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) { (id == DISPLAY_ID_ST7789V)) {
CMD(0x11); // SLPOUT: Sleep Out CMD(0x11); // SLPOUT: Sleep Out
HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before sending any new commands HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before
CMD(0x29); // DISPON: Display On // sending any new commands
} CMD(0x29); // DISPON: Display On
}
} }
static struct { static struct { uint16_t x, y; } BUFFER_OFFSET;
uint16_t x, y;
} BUFFER_OFFSET; static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
uint16_t y1) {
static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) x0 += BUFFER_OFFSET.x;
{ x1 += BUFFER_OFFSET.x;
x0 += BUFFER_OFFSET.x; x1 += BUFFER_OFFSET.x; y0 += BUFFER_OFFSET.y;
y0 += BUFFER_OFFSET.y; y1 += BUFFER_OFFSET.y; y1 += BUFFER_OFFSET.y;
uint32_t id = display_identify(); uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) { if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
CMD(0x2A); DATA(x0 >> 8); DATA(x0 & 0xFF); DATA(x1 >> 8); DATA(x1 & 0xFF); // column addr set (id == DISPLAY_ID_ST7789V)) {
CMD(0x2B); DATA(y0 >> 8); DATA(y0 & 0xFF); DATA(y1 >> 8); DATA(y1 & 0xFF); // row addr set CMD(0x2A);
CMD(0x2C); DATA(x0 >> 8);
} DATA(x0 & 0xFF);
DATA(x1 >> 8);
DATA(x1 & 0xFF); // column addr set
CMD(0x2B);
DATA(y0 >> 8);
DATA(y0 & 0xFF);
DATA(y1 >> 8);
DATA(y1 & 0xFF); // row addr set
CMD(0x2C);
}
} }
static void display_set_orientation(int degrees) static void display_set_orientation(int degrees) {
{ char BX = 0, BY = 0;
char BX = 0, BY = 0; uint32_t id = display_identify();
uint32_t id = display_identify(); if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) { (id == DISPLAY_ID_ST7789V)) {
#define RGB (1 << 3) #define RGB (1 << 3)
#define MV (1 << 5) #define MV (1 << 5)
#define MX (1 << 6) #define MX (1 << 6)
#define MY (1 << 7) #define MY (1 << 7)
// MADCTL: Memory Data Access Control - reference: // MADCTL: Memory Data Access Control - reference:
// section 9.3 in the ILI9341 manual // section 9.3 in the ILI9341 manual
// section 6.2.18 in the GC9307 manual // section 6.2.18 in the GC9307 manual
// section 8.12 in the ST7789V manual // section 8.12 in the ST7789V manual
uint8_t display_command_parameter = 0; uint8_t display_command_parameter = 0;
switch (degrees) { switch (degrees) {
case 0: case 0:
display_command_parameter = 0; display_command_parameter = 0;
BY = (id == DISPLAY_ID_GC9307); BY = (id == DISPLAY_ID_GC9307);
break; break;
case 90: case 90:
display_command_parameter = MV | MX; display_command_parameter = MV | MX;
BX = (id == DISPLAY_ID_GC9307); BX = (id == DISPLAY_ID_GC9307);
break; break;
case 180: case 180:
display_command_parameter = MX | MY; display_command_parameter = MX | MY;
BY = (id != DISPLAY_ID_GC9307); BY = (id != DISPLAY_ID_GC9307);
break; break;
case 270: case 270:
display_command_parameter = MV | MY; display_command_parameter = MV | MY;
BX = (id != DISPLAY_ID_GC9307); BX = (id != DISPLAY_ID_GC9307);
break; break;
} }
if (id == DISPLAY_ID_GC9307) { if (id == DISPLAY_ID_GC9307) {
display_command_parameter ^= RGB | MY; // XOR RGB and MY settings display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
}
CMD(0x36); DATA(display_command_parameter);
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); // reset the column and page extents
} }
BUFFER_OFFSET.x = BX ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0; CMD(0x36);
BUFFER_OFFSET.y = BY ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0; DATA(display_command_parameter);
display_set_window(0, 0, DISPLAY_RESX - 1,
DISPLAY_RESY - 1); // reset the column and page extents
}
BUFFER_OFFSET.x = BX ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
BUFFER_OFFSET.y = BY ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
} }
static void display_set_backlight(int val) static void display_set_backlight(int val) {
{ TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
} }
static void display_hardware_reset(void) static void display_hardware_reset(void) {
{ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14 // wait 10 milliseconds. only needs to be low for 10 microseconds.
// wait 10 milliseconds. only needs to be low for 10 microseconds. // my dev display module ties display reset and touch panel reset together.
// my dev display module ties display reset and touch panel reset together. // keeping this low for max(display_reset_time, ctpm_reset_time) aids
// keeping this low for max(display_reset_time, ctpm_reset_time) aids development and does not hurt. // development and does not hurt.
HAL_Delay(10); HAL_Delay(10);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14
HAL_Delay(120); // max wait time for hardware reset is 120 milliseconds (experienced display flakiness using only 5ms wait before sending commands) HAL_Delay(120); // max wait time for hardware reset is 120 milliseconds
// identify the controller we will communicate with // (experienced display flakiness using only 5ms wait before
// sending commands)
// identify the controller we will communicate with
} }
void display_init(void) void display_init(void) {
{ // init peripherials
// init peripherials __HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_FMC_CLK_ENABLE();
__HAL_RCC_FMC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// LCD_PWM/PA7 (backlight control)
// LCD_PWM/PA7 (backlight control) GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Alternate = GPIO_AF1_TIM1;
GPIO_InitStructure.Alternate = GPIO_AF1_TIM1; GPIO_InitStructure.Pin = GPIO_PIN_7;
GPIO_InitStructure.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// enable PWM timer
// enable PWM timer TIM_HandleTypeDef TIM1_Handle;
TIM_HandleTypeDef TIM1_Handle; TIM1_Handle.Instance = TIM1;
TIM1_Handle.Instance = TIM1; TIM1_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1;
TIM1_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1; // TIM1/APB2 source frequency equals to SystemCoreClock in our configuration,
// TIM1/APB2 source frequency equals to SystemCoreClock in our configuration, we want 1 MHz // we want 1 MHz
TIM1_Handle.Init.Prescaler = SystemCoreClock / 1000000 - 1; TIM1_Handle.Init.Prescaler = SystemCoreClock / 1000000 - 1;
TIM1_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; TIM1_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM1_Handle.Init.RepetitionCounter = 0; TIM1_Handle.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&TIM1_Handle); HAL_TIM_PWM_Init(&TIM1_Handle);
TIM_OC_InitTypeDef TIM_OC_InitStructure; TIM_OC_InitTypeDef TIM_OC_InitStructure;
TIM_OC_InitStructure.Pulse = 0; TIM_OC_InitStructure.Pulse = 0;
TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM2; TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM2;
TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE; TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE;
TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET; TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET; TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET;
HAL_TIM_PWM_ConfigChannel(&TIM1_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1); HAL_TIM_PWM_ConfigChannel(&TIM1_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1);
display_backlight(0); display_backlight(0);
HAL_TIM_PWM_Start(&TIM1_Handle, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&TIM1_Handle, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&TIM1_Handle, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Start(&TIM1_Handle, TIM_CHANNEL_1);
// LCD_RST/PC14 // LCD_RST/PC14
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = 0; GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_14; GPIO_InitStructure.Pin = GPIO_PIN_14;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // default to keeping display in reset HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14,
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PIN_RESET); // default to keeping display in reset
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
// LCD_FMARK/PD12 (tearing effect)
GPIO_InitStructure.Mode = GPIO_MODE_INPUT; // LCD_FMARK/PD12 (tearing effect)
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = 0; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Pin = GPIO_PIN_12; GPIO_InitStructure.Alternate = 0;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_12;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF12_FMC; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5 GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5; // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); // LCD_WR/PD5
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1 GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1; HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10 // LCD_D3/PD1
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9
// Reference UM1725 "Description of STM32F4 HAL and LL drivers", section 64.2.1 "How to use this driver" // LCD_D7/PE10
SRAM_HandleTypeDef external_display_data_sram; GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE; HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; // Reference UM1725 "Description of STM32F4 HAL and LL drivers",
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; // section 64.2.1 "How to use this driver"
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8; SRAM_HandleTypeDef external_display_data_sram;
external_display_data_sram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
external_display_data_sram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE; external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; external_display_data_sram.Init.BurstAccessMode =
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; FMC_BURST_ACCESS_MODE_DISABLE;
external_display_data_sram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; external_display_data_sram.Init.WaitSignalPolarity =
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; FMC_WAIT_SIGNAL_POLARITY_LOW;
external_display_data_sram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE; external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6 external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
FMC_NORSRAM_TimingTypeDef normal_mode_timing; external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
normal_mode_timing.AddressSetupTime = 4; external_display_data_sram.Init.AsynchronousWait =
normal_mode_timing.AddressHoldTime = 1; FMC_ASYNCHRONOUS_WAIT_DISABLE;
normal_mode_timing.DataSetupTime = 4; external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
normal_mode_timing.BusTurnAroundDuration = 0; external_display_data_sram.Init.ContinuousClock =
normal_mode_timing.CLKDivision = 2; FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
normal_mode_timing.DataLatency = 2; external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); FMC_NORSRAM_TimingTypeDef normal_mode_timing;
normal_mode_timing.AddressSetupTime = 4;
display_hardware_reset(); normal_mode_timing.AddressHoldTime = 1;
normal_mode_timing.DataSetupTime = 4;
uint32_t id = display_identify(); normal_mode_timing.BusTurnAroundDuration = 0;
if (id == DISPLAY_ID_GC9307) { normal_mode_timing.CLKDivision = 2;
CMD(0xFE); // Inter Register Enable1 normal_mode_timing.DataLatency = 2;
CMD(0xEF); // Inter Register Enable2 normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
CMD(0x35); DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only
CMD(0x3A); DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits input) HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
// CMD(0xE8); DATA(0x12); DATA(0x00); // Frame Rate
CMD(0xC3); DATA(0x27); // Power Control 2 display_hardware_reset();
CMD(0xC4); DATA(0x18); // Power Control 3
CMD(0xC9); DATA(0x1F); // Power Control 4 uint32_t id = display_identify();
CMD(0xC5); DATA(0x0F); if (id == DISPLAY_ID_GC9307) {
CMD(0xC6); DATA(0x00); CMD(0xFE); // Inter Register Enable1
CMD(0xC7); DATA(0x10); CMD(0xEF); // Inter Register Enable2
CMD(0xC8); DATA(0x01); CMD(0x35);
CMD(0xFF); DATA(0x62); DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only
CMD(0x99); DATA(0x3E); CMD(0x3A);
CMD(0x9D); DATA(0x4B); DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB
CMD(0x8E); DATA(0x0F); // 5-6-5 bits input)
// SET_GAMMA1 // CMD(0xE8); DATA(0x12); DATA(0x00); // Frame Rate
CMD(0xF0); DATA(0x8F); DATA(0x1B); DATA(0x05); DATA(0x06); DATA(0x07); DATA(0x42); CMD(0xC3);
// SET_GAMMA3 DATA(0x27); // Power Control 2
CMD(0xF2); DATA(0x5C); DATA(0x1F); DATA(0x12); DATA(0x10); DATA(0x07); DATA(0x43); CMD(0xC4);
// SET_GAMMA2 DATA(0x18); // Power Control 3
CMD(0xF1); DATA(0x59); DATA(0xCF); DATA(0xCF); DATA(0x35); DATA(0x37); DATA(0x8F); CMD(0xC9);
// SET_GAMMA4 DATA(0x1F); // Power Control 4
CMD(0xF3); DATA(0x58); DATA(0xCF); DATA(0xCF); DATA(0x35); DATA(0x37); DATA(0x8F); CMD(0xC5);
} else DATA(0x0F);
if (id == DISPLAY_ID_ST7789V) { CMD(0xC6);
CMD(0x35); DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only DATA(0x00);
CMD(0x3A); DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits input) CMD(0xC7);
CMD(0xDF); DATA(0x5A); DATA(0x69); DATA(0x02); DATA(0x01); // CMD2EN: Commands in command table 2 can be executed when EXTC level is Low DATA(0x10);
CMD(0xC0); DATA(0x20); // LCMCTRL: LCM Control: XOR RGB setting CMD(0xC8);
CMD(0xE4); DATA(0x1D); DATA(0x0A); DATA(0x11); // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.; gate scan direction 319 -> 0 DATA(0x01);
// the above config is the most important and definitely necessary CMD(0xFF);
CMD(0xD0); DATA(0xA4); DATA(0xA1); // PWCTRL1: Power Control 1 DATA(0x62);
// gamma curve 1 CMD(0x99);
// CMD(0xE0); DATA(0x70); DATA(0x2C); DATA(0x2E); DATA(0x15); DATA(0x10); DATA(0x09); DATA(0x48); DATA(0x33); DATA(0x53); DATA(0x0B); DATA(0x19); DATA(0x18); DATA(0x20); DATA(0x25); DATA(0x3E);
// gamma curve 2 CMD(0x9D);
// CMD(0xE1); DATA(0x70); DATA(0x2C); DATA(0x2E); DATA(0x15); DATA(0x10); DATA(0x09); DATA(0x48); DATA(0x33); DATA(0x53); DATA(0x0B); DATA(0x19); DATA(0x18); DATA(0x20); DATA(0x25); DATA(0x4B);
} else CMD(0x8E);
if (id == DISPLAY_ID_ILI9341V) { DATA(0x0F);
// most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf // SET_GAMMA1
CMD(0x35); DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only CMD(0xF0);
CMD(0x3A); DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits input) DATA(0x8F);
CMD(0xB6); DATA(0x0A); DATA(0xC2); DATA(0x27); DATA(0x00); // Display Function Control: gate scan direction 319 -> 0 DATA(0x1B);
CMD(0xF6); DATA(0x09); DATA(0x30); DATA(0x00); // Interface Control: XOR BGR as ST7789V does DATA(0x05);
// the above config is the most important and definitely necessary DATA(0x06);
CMD(0xCF); DATA(0x00); DATA(0xC1); DATA(0x30); DATA(0x07);
CMD(0xED); DATA(0x64); DATA(0x03); DATA(0x12); DATA(0x81); DATA(0x42);
CMD(0xE8); DATA(0x85); DATA(0x10); DATA(0x7A); // SET_GAMMA3
CMD(0xF7); DATA(0x20); CMD(0xF2);
CMD(0xEA); DATA(0x00); DATA(0x00); DATA(0x5C);
CMD(0xC0); DATA(0x23); // power control VRH[5:0] DATA(0x1F);
CMD(0xC1); DATA(0x12); // power control SAP[2:0] BT[3:0] DATA(0x12);
CMD(0xC5); DATA(0x60); DATA(0x44); // vcm control 1 DATA(0x10);
CMD(0xC7); DATA(0x8A); // vcm control 2 DATA(0x07);
CMD(0xB1); DATA(0x00); DATA(0x18); // framerate DATA(0x43);
CMD(0xF2); DATA(0x00); // 3 gamma func disable // SET_GAMMA2
// gamma curve 1 CMD(0xF1);
CMD(0xE0); DATA(0x0F); DATA(0x2F); DATA(0x2C); DATA(0x0B); DATA(0x0F); DATA(0x09); DATA(0x56); DATA(0xD9); DATA(0x4A); DATA(0x0B); DATA(0x14); DATA(0x05); DATA(0x0C); DATA(0x06); DATA(0x00); DATA(0x59);
// gamma curve 2 DATA(0xCF);
CMD(0xE1); DATA(0x00); DATA(0x10); DATA(0x13); DATA(0x04); DATA(0x10); DATA(0x06); DATA(0x25); DATA(0x26); DATA(0x3B); DATA(0x04); DATA(0x0B); DATA(0x0A); DATA(0x33); DATA(0x39); DATA(0x0F); DATA(0xCF);
} DATA(0x35);
DATA(0x37);
display_clear(); DATA(0x8F);
display_unsleep(); // SET_GAMMA4
CMD(0xF3);
DATA(0x58);
DATA(0xCF);
DATA(0xCF);
DATA(0x35);
DATA(0x37);
DATA(0x8F);
} else if (id == DISPLAY_ID_ST7789V) {
CMD(0x35);
DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only
CMD(0x3A);
DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB
// 5-6-5 bits input)
CMD(0xDF);
DATA(0x5A);
DATA(0x69);
DATA(0x02);
DATA(0x01); // CMD2EN: Commands in command table 2 can be executed when
// EXTC level is Low
CMD(0xC0);
DATA(0x20); // LCMCTRL: LCM Control: XOR RGB setting
CMD(0xE4);
DATA(0x1D);
DATA(0x0A);
DATA(0x11); // GATECTRL: Gate Control; NL = 240 gate lines, first scan line
// is gate 80.; gate scan direction 319 -> 0
// the above config is the most important and definitely necessary
CMD(0xD0);
DATA(0xA4);
DATA(0xA1); // PWCTRL1: Power Control 1
// gamma curve 1
// CMD(0xE0); DATA(0x70); DATA(0x2C); DATA(0x2E); DATA(0x15); DATA(0x10);
// DATA(0x09); DATA(0x48); DATA(0x33); DATA(0x53); DATA(0x0B); DATA(0x19);
// DATA(0x18); DATA(0x20); DATA(0x25); gamma curve 2 CMD(0xE1); DATA(0x70);
// DATA(0x2C); DATA(0x2E); DATA(0x15); DATA(0x10); DATA(0x09); DATA(0x48);
// DATA(0x33); DATA(0x53); DATA(0x0B); DATA(0x19); DATA(0x18); DATA(0x20);
// DATA(0x25);
} else if (id == DISPLAY_ID_ILI9341V) {
// most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf
CMD(0x35);
DATA(0x00); // TEON: Tearing Effect Line On; V-blanking only
CMD(0x3A);
DATA(0x55); // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB
// 5-6-5 bits input)
CMD(0xB6);
DATA(0x0A);
DATA(0xC2);
DATA(0x27);
DATA(0x00); // Display Function Control: gate scan direction 319 -> 0
CMD(0xF6);
DATA(0x09);
DATA(0x30);
DATA(0x00); // Interface Control: XOR BGR as ST7789V does
// the above config is the most important and definitely necessary
CMD(0xCF);
DATA(0x00);
DATA(0xC1);
DATA(0x30);
CMD(0xED);
DATA(0x64);
DATA(0x03);
DATA(0x12);
DATA(0x81);
CMD(0xE8);
DATA(0x85);
DATA(0x10);
DATA(0x7A);
CMD(0xF7);
DATA(0x20);
CMD(0xEA);
DATA(0x00);
DATA(0x00);
CMD(0xC0);
DATA(0x23); // power control VRH[5:0]
CMD(0xC1);
DATA(0x12); // power control SAP[2:0] BT[3:0]
CMD(0xC5);
DATA(0x60);
DATA(0x44); // vcm control 1
CMD(0xC7);
DATA(0x8A); // vcm control 2
CMD(0xB1);
DATA(0x00);
DATA(0x18); // framerate
CMD(0xF2);
DATA(0x00); // 3 gamma func disable
// gamma curve 1
CMD(0xE0);
DATA(0x0F);
DATA(0x2F);
DATA(0x2C);
DATA(0x0B);
DATA(0x0F);
DATA(0x09);
DATA(0x56);
DATA(0xD9);
DATA(0x4A);
DATA(0x0B);
DATA(0x14);
DATA(0x05);
DATA(0x0C);
DATA(0x06);
DATA(0x00);
// gamma curve 2
CMD(0xE1);
DATA(0x00);
DATA(0x10);
DATA(0x13);
DATA(0x04);
DATA(0x10);
DATA(0x06);
DATA(0x25);
DATA(0x26);
DATA(0x3B);
DATA(0x04);
DATA(0x0B);
DATA(0x0A);
DATA(0x33);
DATA(0x39);
DATA(0x0F);
}
display_clear();
display_unsleep();
} }
void display_refresh(void) void display_refresh(void) {
{ uint32_t id = display_identify();
uint32_t id = display_identify(); if (id && (id != DISPLAY_ID_GC9307)) {
if (id && (id != DISPLAY_ID_GC9307)) { // synchronize with the panel synchronization signal in order to avoid
// synchronize with the panel synchronization signal in order to avoid visual tearing effects // visual tearing effects
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { } while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) {
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
} }
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) {
}
}
} }
void display_save(const char *prefix) void display_save(const char *prefix) {}
{
}

@ -27,23 +27,23 @@
#if TREZOR_MODEL == T #if TREZOR_MODEL == T
#ifdef TREZOR_EMULATOR_RASPI #ifdef TREZOR_EMULATOR_RASPI
#define WINDOW_WIDTH 480 #define WINDOW_WIDTH 480
#define WINDOW_HEIGHT 320 #define WINDOW_HEIGHT 320
#define TOUCH_OFFSET_X 110 #define TOUCH_OFFSET_X 110
#define TOUCH_OFFSET_Y 40 #define TOUCH_OFFSET_Y 40
#else #else
#define WINDOW_WIDTH 400 #define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 600 #define WINDOW_HEIGHT 600
#define TOUCH_OFFSET_X 80 #define TOUCH_OFFSET_X 80
#define TOUCH_OFFSET_Y 110 #define TOUCH_OFFSET_Y 110
#endif #endif
#elif TREZOR_MODEL == 1 #elif TREZOR_MODEL == 1
#define WINDOW_WIDTH 200 #define WINDOW_WIDTH 200
#define WINDOW_HEIGHT 340 #define WINDOW_HEIGHT 340
#define TOUCH_OFFSET_X 36 #define TOUCH_OFFSET_X 36
#define TOUCH_OFFSET_Y 92 #define TOUCH_OFFSET_Y 92
#else #else
#error Unknown TREZOR Model #error Unknown TREZOR Model
@ -57,162 +57,172 @@ int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
int sdl_touch_offset_x, sdl_touch_offset_y; int sdl_touch_offset_x, sdl_touch_offset_y;
static struct { static struct {
struct { struct {
uint16_t x, y; uint16_t x, y;
} start; } start;
struct { struct {
uint16_t x, y; uint16_t x, y;
} end; } end;
struct { struct {
uint16_t x, y; uint16_t x, y;
} pos; } pos;
} PIXELWINDOW; } PIXELWINDOW;
void PIXELDATA(uint16_t c) { void PIXELDATA(uint16_t c) {
#if TREZOR_MODEL == 1 #if TREZOR_MODEL == 1
// set to white if highest bits of all R, G, B values are set to 1 // set to white if highest bits of all R, G, B values are set to 1
// bin(10000 100000 10000) = hex(0x8410) // bin(10000 100000 10000) = hex(0x8410)
// otherwise set to black // otherwise set to black
c = (c & 0x8410) ? 0xFFFF : 0x0000; c = (c & 0x8410) ? 0xFFFF : 0x0000;
#endif #endif
if (!RENDERER) { if (!RENDERER) {
display_init(); display_init();
} }
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) { if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x &&
((uint16_t *)BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch / sizeof(uint16_t)] = c; PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
} ((uint16_t *)
PIXELWINDOW.pos.x++; BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch /
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) { sizeof(uint16_t)] = c;
PIXELWINDOW.pos.x = PIXELWINDOW.start.x; }
PIXELWINDOW.pos.y++; PIXELWINDOW.pos.x++;
} if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
}
} }
#else #else
#define PIXELDATA(X) (void)(X) #define PIXELDATA(X) (void)(X)
#endif #endif
void display_init(void) void display_init(void) {
{
#ifndef TREZOR_EMULATOR_NOUI #ifndef TREZOR_EMULATOR_NOUI
if (SDL_Init(SDL_INIT_VIDEO) != 0) { if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("%s\n", SDL_GetError()); printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_Init error"); ensure(secfalse, "SDL_Init error");
} }
atexit(SDL_Quit); atexit(SDL_Quit);
SDL_Window *win = SDL_CreateWindow("TREZOR Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_Window *win =
SDL_CreateWindow("TREZOR Emulator", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
#ifdef TREZOR_EMULATOR_RASPI #ifdef TREZOR_EMULATOR_RASPI
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
#else #else
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
#endif #endif
); );
if (!win) { if (!win) {
printf("%s\n", SDL_GetError()); printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_CreateWindow error"); ensure(secfalse, "SDL_CreateWindow error");
} }
RENDERER = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE); RENDERER = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
if (!RENDERER) { if (!RENDERER) {
printf("%s\n", SDL_GetError()); printf("%s\n", SDL_GetError());
SDL_DestroyWindow(win); SDL_DestroyWindow(win);
ensure(secfalse, "SDL_CreateRenderer error"); ensure(secfalse, "SDL_CreateRenderer error");
} }
SDL_SetRenderDrawColor(RENDERER, 0, 0, 0, 255); SDL_SetRenderDrawColor(RENDERER, 0, 0, 0, 255);
SDL_RenderClear(RENDERER); SDL_RenderClear(RENDERER);
BUFFER = SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16, 0xF800, 0x07E0, 0x001F, 0x0000); BUFFER = SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16,
TEXTURE = SDL_CreateTexture(RENDERER, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX, DISPLAY_RESY); 0xF800, 0x07E0, 0x001F, 0x0000);
SDL_SetTextureBlendMode(TEXTURE, SDL_BLENDMODE_BLEND); TEXTURE = SDL_CreateTexture(RENDERER, SDL_PIXELFORMAT_RGB565,
SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
DISPLAY_RESY);
SDL_SetTextureBlendMode(TEXTURE, SDL_BLENDMODE_BLEND);
#ifdef __APPLE__ #ifdef __APPLE__
// macOS Mojave SDL black screen workaround // macOS Mojave SDL black screen workaround
SDL_PumpEvents(); SDL_PumpEvents();
SDL_SetWindowSize(win, WINDOW_WIDTH, WINDOW_HEIGHT); SDL_SetWindowSize(win, WINDOW_WIDTH, WINDOW_HEIGHT);
#endif #endif
// TODO: find better way how to embed/distribute background image // TODO: find better way how to embed/distribute background image
#ifdef TREZOR_EMULATOR_RASPI #ifdef TREZOR_EMULATOR_RASPI
BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_raspi.jpg"); BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_raspi.jpg");
#else #else
BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_" XSTR(TREZOR_MODEL) ".jpg"); BACKGROUND = IMG_LoadTexture(
RENDERER, "../embed/unix/background_" XSTR(TREZOR_MODEL) ".jpg");
#endif #endif
if (BACKGROUND) { if (BACKGROUND) {
SDL_SetTextureBlendMode(BACKGROUND, SDL_BLENDMODE_NONE); SDL_SetTextureBlendMode(BACKGROUND, SDL_BLENDMODE_NONE);
sdl_touch_offset_x = TOUCH_OFFSET_X; sdl_touch_offset_x = TOUCH_OFFSET_X;
sdl_touch_offset_y = TOUCH_OFFSET_Y; sdl_touch_offset_y = TOUCH_OFFSET_Y;
} else { } else {
SDL_SetWindowSize(win, DISPLAY_RESX + 2 * EMULATOR_BORDER, DISPLAY_RESY + 2 * EMULATOR_BORDER); SDL_SetWindowSize(win, DISPLAY_RESX + 2 * EMULATOR_BORDER,
sdl_touch_offset_x = EMULATOR_BORDER; DISPLAY_RESY + 2 * EMULATOR_BORDER);
sdl_touch_offset_y = EMULATOR_BORDER; sdl_touch_offset_x = EMULATOR_BORDER;
} sdl_touch_offset_y = EMULATOR_BORDER;
DISPLAY_BACKLIGHT = 0; }
DISPLAY_BACKLIGHT = 0;
#ifdef TREZOR_EMULATOR_RASPI #ifdef TREZOR_EMULATOR_RASPI
DISPLAY_ORIENTATION = 270; DISPLAY_ORIENTATION = 270;
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
#else #else
DISPLAY_ORIENTATION = 0; DISPLAY_ORIENTATION = 0;
#endif #endif
#endif #endif
} }
static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
{ uint16_t y1) {
#ifndef TREZOR_EMULATOR_NOUI #ifndef TREZOR_EMULATOR_NOUI
if (!RENDERER) { if (!RENDERER) {
display_init(); display_init();
} }
PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0; PIXELWINDOW.start.x = x0;
PIXELWINDOW.end.x = x1; PIXELWINDOW.end.y = y1; PIXELWINDOW.start.y = y0;
PIXELWINDOW.pos.x = x0; PIXELWINDOW.pos.y = y0; PIXELWINDOW.end.x = x1;
PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0;
PIXELWINDOW.pos.y = y0;
#endif #endif
} }
void display_refresh(void) void display_refresh(void) {
{
#ifndef TREZOR_EMULATOR_NOUI #ifndef TREZOR_EMULATOR_NOUI
if (!RENDERER) { if (!RENDERER) {
display_init(); display_init();
} }
if (BACKGROUND) { if (BACKGROUND) {
SDL_RenderCopy(RENDERER, BACKGROUND, NULL, NULL); SDL_RenderCopy(RENDERER, BACKGROUND, NULL, NULL);
} else { } else {
SDL_RenderClear(RENDERER); SDL_RenderClear(RENDERER);
} }
SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch); SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch);
#define BACKLIGHT_NORMAL 150 #define BACKLIGHT_NORMAL 150
SDL_SetTextureAlphaMod(TEXTURE, MIN(255, 255 * DISPLAY_BACKLIGHT / BACKLIGHT_NORMAL)); SDL_SetTextureAlphaMod(TEXTURE,
if (BACKGROUND) { MIN(255, 255 * DISPLAY_BACKLIGHT / BACKLIGHT_NORMAL));
const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX, DISPLAY_RESY}; if (BACKGROUND) {
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0); const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX,
} else { DISPLAY_RESY};
const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX, DISPLAY_RESY}; SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0); } else {
} const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX,
SDL_RenderPresent(RENDERER); DISPLAY_RESY};
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
}
SDL_RenderPresent(RENDERER);
#endif #endif
} }
static void display_set_orientation(int degrees) static void display_set_orientation(int degrees) { display_refresh(); }
{
display_refresh();
}
static void display_set_backlight(int val) static void display_set_backlight(int val) { display_refresh(); }
{
display_refresh();
}
void display_save(const char *prefix) void display_save(const char *prefix) {
{
#ifndef TREZOR_EMULATOR_NOUI #ifndef TREZOR_EMULATOR_NOUI
if (!RENDERER) { if (!RENDERER) {
display_init(); display_init();
} }
static uint32_t cnt = 0; static uint32_t cnt = 0;
char fname[256]; char fname[256];
snprintf(fname, sizeof(fname), "%s%08d.png", prefix, cnt); snprintf(fname, sizeof(fname), "%s%08d.png", prefix, cnt);
const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY}; const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY};
SDL_Surface *crop = SDL_CreateRGBSurface(BUFFER->flags, rect.w, rect.h, BUFFER->format->BitsPerPixel, BUFFER->format->Rmask, BUFFER->format->Gmask, BUFFER->format->Bmask, BUFFER->format->Amask); SDL_Surface *crop = SDL_CreateRGBSurface(
SDL_BlitSurface(BUFFER, &rect, crop, NULL); BUFFER->flags, rect.w, rect.h, BUFFER->format->BitsPerPixel,
IMG_SavePNG(crop, fname); BUFFER->format->Rmask, BUFFER->format->Gmask, BUFFER->format->Bmask,
SDL_FreeSurface(crop); BUFFER->format->Amask);
fprintf(stderr, "Saved screenshot to %s\n", fname); SDL_BlitSurface(BUFFER, &rect, crop, NULL);
cnt++; IMG_SavePNG(crop, fname);
SDL_FreeSurface(crop);
fprintf(stderr, "Saved screenshot to %s\n", fname);
cnt++;
#endif #endif
} }

File diff suppressed because it is too large Load Diff

@ -25,42 +25,42 @@
#if TREZOR_MODEL == T #if TREZOR_MODEL == T
// ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution // ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution
#define MAX_DISPLAY_RESX 240 #define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320 #define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240 #define DISPLAY_RESX 240
#define DISPLAY_RESY 240 #define DISPLAY_RESY 240
#elif TREZOR_MODEL == 1 #elif TREZOR_MODEL == 1
#define MAX_DISPLAY_RESX 128 #define MAX_DISPLAY_RESX 128
#define MAX_DISPLAY_RESY 64 #define MAX_DISPLAY_RESY 64
#define DISPLAY_RESX 128 #define DISPLAY_RESX 128
#define DISPLAY_RESY 64 #define DISPLAY_RESY 64
#else #else
#error Unknown TREZOR Model #error Unknown TREZOR Model
#endif #endif
#define FONT_BPP 4 #define FONT_BPP 4
#define FONT_SIZE 20 #define FONT_SIZE 20
#define AVATAR_IMAGE_SIZE 144 #define AVATAR_IMAGE_SIZE 144
#define LOADER_ICON_SIZE 64 #define LOADER_ICON_SIZE 64
#define RGB16(R, G, B) ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3) #define RGB16(R, G, B) ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3)
#define COLOR_WHITE 0xFFFF #define COLOR_WHITE 0xFFFF
#define COLOR_BLACK 0x0000 #define COLOR_BLACK 0x0000
#ifdef TREZOR_FONT_NORMAL_ENABLE #ifdef TREZOR_FONT_NORMAL_ENABLE
#define FONT_NORMAL (-1) #define FONT_NORMAL (-1)
#endif #endif
#ifdef TREZOR_FONT_BOLD_ENABLE #ifdef TREZOR_FONT_BOLD_ENABLE
#define FONT_BOLD (-2) #define FONT_BOLD (-2)
#endif #endif
#ifdef TREZOR_FONT_MONO_ENABLE #ifdef TREZOR_FONT_MONO_ENABLE
#define FONT_MONO (-3) #define FONT_MONO (-3)
#endif #endif
#ifdef TREZOR_FONT_MONO_BOLD_ENABLE #ifdef TREZOR_FONT_MONO_BOLD_ENABLE
#define FONT_MONO_BOLD (-4) #define FONT_MONO_BOLD (-4)
#endif #endif
// provided by port // provided by port
@ -74,22 +74,31 @@ void display_save(const char *prefix);
void display_clear(void); void display_clear(void);
void display_bar(int x, int y, int w, int h, uint16_t c); void display_bar(int x, int y, int w, int h, uint16_t c);
void display_bar_radius(int x, int y, int w, int h, uint16_t c, uint16_t b, uint8_t r); void display_bar_radius(int x, int y, int w, int h, uint16_t c, uint16_t b,
uint8_t r);
void display_image(int x, int y, int w, int h, const void *data, int datalen); void display_image(int x, int y, int w, int h, const void *data, int datalen);
void display_avatar(int x, int y, const void *data, int datalen, uint16_t fgcolor, uint16_t bgcolor); void display_avatar(int x, int y, const void *data, int datalen,
void display_icon(int x, int y, int w, int h, const void *data, int datalen, uint16_t fgcolor, uint16_t bgcolor); uint16_t fgcolor, uint16_t bgcolor);
void display_loader(uint16_t progress, int yoffset, uint16_t fgcolor, uint16_t bgcolor, const uint8_t *icon, uint32_t iconlen, uint16_t iconfgcolor); void display_icon(int x, int y, int w, int h, const void *data, int datalen,
uint16_t fgcolor, uint16_t bgcolor);
void display_loader(uint16_t progress, int yoffset, uint16_t fgcolor,
uint16_t bgcolor, const uint8_t *icon, uint32_t iconlen,
uint16_t iconfgcolor);
#ifndef TREZOR_PRINT_DISABLE #ifndef TREZOR_PRINT_DISABLE
void display_print_color(uint16_t fgcolor, uint16_t bgcolor); void display_print_color(uint16_t fgcolor, uint16_t bgcolor);
void display_print(const char *text, int textlen); void display_print(const char *text, int textlen);
void display_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void display_printf(const char *fmt, ...)
__attribute__((__format__(__printf__, 1, 2)));
#endif #endif
void display_text(int x, int y, const char *text, int textlen, int font, uint16_t fgcolor, uint16_t bgcolor); void display_text(int x, int y, const char *text, int textlen, int font,
void display_text_center(int x, int y, const char *text, int textlen, int font, uint16_t fgcolor, uint16_t bgcolor); uint16_t fgcolor, uint16_t bgcolor);
void display_text_right(int x, int y, const char *text, int textlen, int font, uint16_t fgcolor, uint16_t bgcolor); void display_text_center(int x, int y, const char *text, int textlen, int font,
uint16_t fgcolor, uint16_t bgcolor);
void display_text_right(int x, int y, const char *text, int textlen, int font,
uint16_t fgcolor, uint16_t bgcolor);
int display_text_width(const char *text, int textlen, int font); int display_text_width(const char *text, int textlen, int font);
void display_qrcode(int x, int y, const char *data, int datalen, uint8_t scale); void display_qrcode(int x, int y, const char *data, int datalen, uint8_t scale);

@ -1,5 +1,7 @@
#include "font_bitmap.h" #include "font_bitmap.h"
// clang-format off
const uint8_t * const Font_Bitmap = (const uint8_t * const) const uint8_t * const Font_Bitmap = (const uint8_t * const)
"\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00"
"\x00\x00\x5f\x00\x00" "\x00\x00\x5f\x00\x00"

@ -1,3 +1,3 @@
#include <stdint.h> #include <stdint.h>
extern const uint8_t * const Font_Bitmap; extern const uint8_t* const Font_Bitmap;

@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// clang-format off
/* /*
* stream_inflate - tiny inflate library with output streaming * stream_inflate - tiny inflate library with output streaming
* *

@ -22,6 +22,9 @@
#include <stdint.h> #include <stdint.h>
int sinf_inflate(const uint8_t *data, uint32_t datalen, void (*write_callback)(uint8_t byte, uint32_t pos, void *userdata), void *userdata); int sinf_inflate(const uint8_t *data, uint32_t datalen,
void (*write_callback)(uint8_t byte, uint32_t pos,
void *userdata),
void *userdata);
#endif #endif

@ -1,3 +1,4 @@
// clang-format off
static const int img_loader_size = 60; static const int img_loader_size = 60;
static const uint16_t img_loader[60][60] = { static const uint16_t img_loader[60][60] = {
{31744,31488,30976,30720,30208,29952,29696,29184,28672,28416,27904,27648,27136,26624,26368,25856,25344,25088,24576,24064,23552,23040,22528,22016,21504,20992,20480,19968,19456,18944,18432,17920,17408,16640,16128,15616,14848,14336,13824,13056,12544,11776,11264,10496,9984,9216,8704,7936,7424,6656,5888,5376,4624,4128,3393,2641,2146,1378,626,114,}, {31744,31488,30976,30720,30208,29952,29696,29184,28672,28416,27904,27648,27136,26624,26368,25856,25344,25088,24576,24064,23552,23040,22528,22016,21504,20992,20480,19968,19456,18944,18432,17920,17408,16640,16128,15616,14848,14336,13824,13056,12544,11776,11264,10496,9984,9216,8704,7936,7424,6656,5888,5376,4624,4128,3393,2641,2146,1378,626,114,},

@ -26,18 +26,20 @@
/// Provide access to device display. /// Provide access to device display.
/// ''' /// '''
typedef struct _mp_obj_Display_t { typedef struct _mp_obj_Display_t {
mp_obj_base_t base; mp_obj_base_t base;
} mp_obj_Display_t; } mp_obj_Display_t;
/// def __init__(self) -> None: /// def __init__(self) -> None:
/// ''' /// '''
/// Initialize the display. /// Initialize the display.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_make_new(const mp_obj_type_t *type,
mp_arg_check_num(n_args, n_kw, 0, 0, false); size_t n_args, size_t n_kw,
mp_obj_Display_t *o = m_new_obj(mp_obj_Display_t); const mp_obj_t *args) {
o->base.type = type; mp_arg_check_num(n_args, n_kw, 0, 0, false);
return MP_OBJ_FROM_PTR(o); mp_obj_Display_t *o = m_new_obj(mp_obj_Display_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
} }
/// def clear(self) -> None: /// def clear(self) -> None:
@ -45,423 +47,481 @@ STATIC mp_obj_t mod_trezorui_Display_make_new(const mp_obj_type_t *type, size_t
/// Clear display with black color. /// Clear display with black color.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_clear(mp_obj_t self) { STATIC mp_obj_t mod_trezorui_Display_clear(mp_obj_t self) {
display_clear(); display_clear();
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_obj, mod_trezorui_Display_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_obj,
mod_trezorui_Display_clear);
/// def refresh(self) -> None: /// def refresh(self) -> None:
/// ''' /// '''
/// Refresh display (update screen). /// Refresh display (update screen).
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_refresh(mp_obj_t self) { STATIC mp_obj_t mod_trezorui_Display_refresh(mp_obj_t self) {
display_refresh(); display_refresh();
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_refresh_obj, mod_trezorui_Display_refresh); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_refresh_obj,
mod_trezorui_Display_refresh);
/// def bar(self, x: int, y: int, w: int, h: int, color: int) -> None: /// def bar(self, x: int, y: int, w: int, h: int, color: int) -> None:
/// ''' /// '''
/// Renders a bar at position (x,y = upper left corner) with width w and height h of color color. /// Renders a bar at position (x,y = upper left corner) with width w and
/// height h of color color.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_bar(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_bar(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]); mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]); mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]); mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]); mp_int_t h = mp_obj_get_int(args[4]);
uint16_t c = mp_obj_get_int(args[5]); uint16_t c = mp_obj_get_int(args[5]);
display_bar(x, y, w, h, c); display_bar(x, y, w, h, c);
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_bar_obj, 6, 6, mod_trezorui_Display_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_bar_obj, 6, 6,
mod_trezorui_Display_bar);
/// def bar_radius(self, x: int, y: int, w: int, h: int, fgcolor: int, bgcolor: int = None, radius: int = None) -> None: /// def bar_radius(self, x: int, y: int, w: int, h: int, fgcolor: int, bgcolor:
/// ''' /// int = None, radius: int = None) -> None:
/// Renders a rounded bar at position (x,y = upper left corner) with width w and height h of color fgcolor. /// '''
/// Background is set to bgcolor and corners are drawn with radius radius. /// Renders a rounded bar at position (x,y = upper left corner) with width w
/// ''' /// and height h of color fgcolor. Background is set to bgcolor and corners
STATIC mp_obj_t mod_trezorui_Display_bar_radius(size_t n_args, const mp_obj_t *args) { /// are drawn with radius radius.
mp_int_t x = mp_obj_get_int(args[1]); /// '''
mp_int_t y = mp_obj_get_int(args[2]); STATIC mp_obj_t mod_trezorui_Display_bar_radius(size_t n_args,
mp_int_t w = mp_obj_get_int(args[3]); const mp_obj_t *args) {
mp_int_t h = mp_obj_get_int(args[4]); mp_int_t x = mp_obj_get_int(args[1]);
uint16_t c = mp_obj_get_int(args[5]); mp_int_t y = mp_obj_get_int(args[2]);
uint16_t b = mp_obj_get_int(args[6]); mp_int_t w = mp_obj_get_int(args[3]);
uint8_t r = mp_obj_get_int(args[7]); mp_int_t h = mp_obj_get_int(args[4]);
display_bar_radius(x, y, w, h, c, b, r); uint16_t c = mp_obj_get_int(args[5]);
return mp_const_none; uint16_t b = mp_obj_get_int(args[6]);
uint8_t r = mp_obj_get_int(args[7]);
display_bar_radius(x, y, w, h, c, b, r);
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_bar_radius_obj, 8, 8, mod_trezorui_Display_bar_radius); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_bar_radius_obj,
8, 8,
mod_trezorui_Display_bar_radius);
/// def image(self, x: int, y: int, image: bytes) -> None: /// def image(self, x: int, y: int, image: bytes) -> None:
/// ''' /// '''
/// Renders an image at position (x,y). /// Renders an image at position (x,y).
/// The image needs to be in TREZOR Optimized Image Format (TOIF) - full-color mode. /// The image needs to be in TREZOR Optimized Image Format (TOIF) -
/// ''' /// full-color mode.
STATIC mp_obj_t mod_trezorui_Display_image(size_t n_args, const mp_obj_t *args) { /// '''
mp_int_t x = mp_obj_get_int(args[1]); STATIC mp_obj_t mod_trezorui_Display_image(size_t n_args,
mp_int_t y = mp_obj_get_int(args[2]); const mp_obj_t *args) {
mp_buffer_info_t image; mp_int_t x = mp_obj_get_int(args[1]);
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ); mp_int_t y = mp_obj_get_int(args[2]);
const uint8_t *data = image.buf; mp_buffer_info_t image;
if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) { mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
mp_raise_ValueError("Invalid image format"); const uint8_t *data = image.buf;
} if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) {
mp_int_t w = *(uint16_t *)(data + 4); mp_raise_ValueError("Invalid image format");
mp_int_t h = *(uint16_t *)(data + 6); }
mp_int_t datalen = *(uint32_t *)(data + 8); mp_int_t w = *(uint16_t *)(data + 4);
if (datalen != image.len - 12) { mp_int_t h = *(uint16_t *)(data + 6);
mp_raise_ValueError("Invalid size of data"); mp_int_t datalen = *(uint32_t *)(data + 8);
} if (datalen != image.len - 12) {
display_image(x, y, w, h, data + 12, datalen); mp_raise_ValueError("Invalid size of data");
return mp_const_none; }
display_image(x, y, w, h, data + 12, datalen);
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_image_obj, 4, 4, mod_trezorui_Display_image); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_image_obj, 4, 4,
mod_trezorui_Display_image);
/// def avatar(self, x: int, y: int, image: bytes, fgcolor: int, bgcolor: int) -> None: /// def avatar(self, x: int, y: int, image: bytes, fgcolor: int, bgcolor: int)
/// -> None:
/// ''' /// '''
/// Renders an avatar at position (x,y). /// Renders an avatar at position (x,y).
/// The image needs to be in TREZOR Optimized Image Format (TOIF) - full-color mode. /// The image needs to be in TREZOR Optimized Image Format (TOIF) -
/// Image needs to be of exactly AVATAR_IMAGE_SIZE x AVATAR_IMAGE_SIZE pixels size. /// full-color mode. Image needs to be of exactly AVATAR_IMAGE_SIZE x
/// ''' /// AVATAR_IMAGE_SIZE pixels size.
STATIC mp_obj_t mod_trezorui_Display_avatar(size_t n_args, const mp_obj_t *args) { /// '''
mp_int_t x = mp_obj_get_int(args[1]); STATIC mp_obj_t mod_trezorui_Display_avatar(size_t n_args,
mp_int_t y = mp_obj_get_int(args[2]); const mp_obj_t *args) {
mp_buffer_info_t image; mp_int_t x = mp_obj_get_int(args[1]);
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ); mp_int_t y = mp_obj_get_int(args[2]);
const uint8_t *data = image.buf; mp_buffer_info_t image;
if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) { mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
mp_raise_ValueError("Invalid image format"); const uint8_t *data = image.buf;
} if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) {
mp_int_t w = *(uint16_t *)(data + 4); mp_raise_ValueError("Invalid image format");
mp_int_t h = *(uint16_t *)(data + 6); }
if (w != AVATAR_IMAGE_SIZE || h != AVATAR_IMAGE_SIZE) { mp_int_t w = *(uint16_t *)(data + 4);
mp_raise_ValueError("Invalid image size"); mp_int_t h = *(uint16_t *)(data + 6);
} if (w != AVATAR_IMAGE_SIZE || h != AVATAR_IMAGE_SIZE) {
mp_int_t datalen = *(uint32_t *)(data + 8); mp_raise_ValueError("Invalid image size");
if (datalen != image.len - 12) { }
mp_raise_ValueError("Invalid size of data"); mp_int_t datalen = *(uint32_t *)(data + 8);
} if (datalen != image.len - 12) {
mp_int_t fgcolor = mp_obj_get_int(args[4]); mp_raise_ValueError("Invalid size of data");
mp_int_t bgcolor = mp_obj_get_int(args[5]); }
display_avatar(x, y, data + 12, datalen, fgcolor, bgcolor); mp_int_t fgcolor = mp_obj_get_int(args[4]);
return mp_const_none; mp_int_t bgcolor = mp_obj_get_int(args[5]);
display_avatar(x, y, data + 12, datalen, fgcolor, bgcolor);
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_avatar_obj, 6, 6, mod_trezorui_Display_avatar); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_avatar_obj, 6,
6, mod_trezorui_Display_avatar);
/// def icon(self, x: int, y: int, icon: bytes, fgcolor: int, bgcolor: int) -> None: /// def icon(self, x: int, y: int, icon: bytes, fgcolor: int, bgcolor: int) ->
/// None:
/// ''' /// '''
/// Renders an icon at position (x,y), fgcolor is used as foreground color, bgcolor as background. /// Renders an icon at position (x,y), fgcolor is used as foreground color,
/// The icon needs to be in TREZOR Optimized Image Format (TOIF) - gray-scale mode. /// bgcolor as background. The icon needs to be in TREZOR Optimized Image
/// Format (TOIF) - gray-scale mode.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_icon(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_icon(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]); mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]); mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t icon;
mp_get_buffer_raise(args[3], &icon, MP_BUFFER_READ);
const uint8_t *data = icon.buf;
if (icon.len < 8 || memcmp(data, "TOIg", 4) != 0) {
mp_raise_ValueError("Invalid image format");
}
mp_int_t w = *(uint16_t *)(data + 4);
mp_int_t h = *(uint16_t *)(data + 6);
mp_int_t datalen = *(uint32_t *)(data + 8);
if (datalen != icon.len - 12) {
mp_raise_ValueError("Invalid size of data");
}
mp_int_t fgcolor = mp_obj_get_int(args[4]);
mp_int_t bgcolor = mp_obj_get_int(args[5]);
display_icon(x, y, w, h, data + 12, icon.len - 12, fgcolor, bgcolor);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_icon_obj, 6, 6,
mod_trezorui_Display_icon);
/// def loader(self, progress: int, yoffset: int, fgcolor: int, bgcolor: int,
/// icon: bytes = None, iconfgcolor: int = None) -> None:
/// '''
/// Renders a rotating loader graphic.
/// Progress determines its position (0-1000), fgcolor is used as foreground
/// color, bgcolor as background. When icon and iconfgcolor are provided, an
/// icon is drawn in the middle using the color specified in iconfgcolor.
/// Icon needs to be of exactly LOADER_ICON_SIZE x LOADER_ICON_SIZE pixels
/// size.
/// '''
STATIC mp_obj_t mod_trezorui_Display_loader(size_t n_args,
const mp_obj_t *args) {
mp_int_t progress = mp_obj_get_int(args[1]);
mp_int_t yoffset = mp_obj_get_int(args[2]);
mp_int_t fgcolor = mp_obj_get_int(args[3]);
mp_int_t bgcolor = mp_obj_get_int(args[4]);
if (n_args > 5) { // icon provided
mp_buffer_info_t icon; mp_buffer_info_t icon;
mp_get_buffer_raise(args[3], &icon, MP_BUFFER_READ); mp_get_buffer_raise(args[5], &icon, MP_BUFFER_READ);
const uint8_t *data = icon.buf; const uint8_t *data = icon.buf;
if (icon.len < 8 || memcmp(data, "TOIg", 4) != 0) { if (icon.len < 8 || memcmp(data, "TOIg", 4) != 0) {
mp_raise_ValueError("Invalid image format"); mp_raise_ValueError("Invalid image format");
} }
mp_int_t w = *(uint16_t *)(data + 4); mp_int_t w = *(uint16_t *)(data + 4);
mp_int_t h = *(uint16_t *)(data + 6); mp_int_t h = *(uint16_t *)(data + 6);
mp_int_t datalen = *(uint32_t *)(data + 8); mp_int_t datalen = *(uint32_t *)(data + 8);
if (w != LOADER_ICON_SIZE || h != LOADER_ICON_SIZE) {
mp_raise_ValueError("Invalid icon size");
}
if (datalen != icon.len - 12) { if (datalen != icon.len - 12) {
mp_raise_ValueError("Invalid size of data"); mp_raise_ValueError("Invalid size of data");
} }
mp_int_t fgcolor = mp_obj_get_int(args[4]); uint16_t iconfgcolor;
mp_int_t bgcolor = mp_obj_get_int(args[5]); if (n_args > 6) { // icon color provided
display_icon(x, y, w, h, data + 12, icon.len - 12, fgcolor, bgcolor); iconfgcolor = mp_obj_get_int(args[6]);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_icon_obj, 6, 6, mod_trezorui_Display_icon);
/// def loader(self, progress: int, yoffset: int, fgcolor: int, bgcolor: int, icon: bytes = None, iconfgcolor: int = None) -> None:
/// '''
/// Renders a rotating loader graphic.
/// Progress determines its position (0-1000), fgcolor is used as foreground color, bgcolor as background.
/// When icon and iconfgcolor are provided, an icon is drawn in the middle using the color specified in iconfgcolor.
/// Icon needs to be of exactly LOADER_ICON_SIZE x LOADER_ICON_SIZE pixels size.
/// '''
STATIC mp_obj_t mod_trezorui_Display_loader(size_t n_args, const mp_obj_t *args) {
mp_int_t progress = mp_obj_get_int(args[1]);
mp_int_t yoffset = mp_obj_get_int(args[2]);
mp_int_t fgcolor = mp_obj_get_int(args[3]);
mp_int_t bgcolor = mp_obj_get_int(args[4]);
if (n_args > 5) { // icon provided
mp_buffer_info_t icon;
mp_get_buffer_raise(args[5], &icon, MP_BUFFER_READ);
const uint8_t *data = icon.buf;
if (icon.len < 8 || memcmp(data, "TOIg", 4) != 0) {
mp_raise_ValueError("Invalid image format");
}
mp_int_t w = *(uint16_t *)(data + 4);
mp_int_t h = *(uint16_t *)(data + 6);
mp_int_t datalen = *(uint32_t *)(data + 8);
if (w != LOADER_ICON_SIZE || h != LOADER_ICON_SIZE) {
mp_raise_ValueError("Invalid icon size");
}
if (datalen != icon.len - 12) {
mp_raise_ValueError("Invalid size of data");
}
uint16_t iconfgcolor;
if (n_args > 6) { // icon color provided
iconfgcolor = mp_obj_get_int(args[6]);
} else {
iconfgcolor = ~bgcolor; // invert
}
display_loader(progress, yoffset, fgcolor, bgcolor, icon.buf, icon.len, iconfgcolor);
} else { } else {
display_loader(progress, yoffset, fgcolor, bgcolor, NULL, 0, 0); iconfgcolor = ~bgcolor; // invert
} }
return mp_const_none; display_loader(progress, yoffset, fgcolor, bgcolor, icon.buf, icon.len,
iconfgcolor);
} else {
display_loader(progress, yoffset, fgcolor, bgcolor, NULL, 0, 0);
}
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_loader_obj, 5, 7, mod_trezorui_Display_loader); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_loader_obj, 5,
7, mod_trezorui_Display_loader);
/// def print(self, text: str) -> None: /// def print(self, text: str) -> None:
/// ''' /// '''
/// Renders text using 5x8 bitmap font (using special text mode). /// Renders text using 5x8 bitmap font (using special text mode).
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_print(mp_obj_t self, mp_obj_t text) { STATIC mp_obj_t mod_trezorui_Display_print(mp_obj_t self, mp_obj_t text) {
mp_buffer_info_t buf; mp_buffer_info_t buf;
mp_get_buffer_raise(text, &buf, MP_BUFFER_READ); mp_get_buffer_raise(text, &buf, MP_BUFFER_READ);
if (buf.len > 0) { if (buf.len > 0) {
display_print(buf.buf, buf.len); display_print(buf.buf, buf.len);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj, mod_trezorui_Display_print); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_print_obj,
mod_trezorui_Display_print);
/// def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int: /// def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor:
/// int, minwidth: int=None) -> int:
/// ''' /// '''
/// Renders left-aligned text at position (x,y) where x is left position and y is baseline. /// Renders left-aligned text at position (x,y) where x is left position and
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background. /// y is baseline. Font font is used for rendering, fgcolor is used as
/// Fills at least minwidth pixels with bgcolor. /// foreground color, bgcolor as background. Fills at least minwidth pixels
/// Returns width of rendered text in pixels. /// with bgcolor. Returns width of rendered text in pixels.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_text(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]); mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]); mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text; mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ); mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]); mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]); mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0; mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start // prefill start
int w = display_text_width(text.buf, text.len, font); int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth); int barwidth = MAX(w, minwidth);
display_bar(x, y - 18, barwidth, 23, bgcolor); display_bar(x, y - 18, barwidth, 23, bgcolor);
// prefill end // prefill end
display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor); display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w); return mp_obj_new_int(w);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 8, mod_trezorui_Display_text); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_obj, 7, 8,
mod_trezorui_Display_text);
/// def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int: /// def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int,
/// ''' /// bgcolor: int, minwidth: int=None) -> int:
/// Renders text centered at position (x,y) where x is text center and y is baseline. /// '''
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background. /// Renders text centered at position (x,y) where x is text center and y is
/// Fills at least minwidth pixels with bgcolor. /// baseline. Font font is used for rendering, fgcolor is used as foreground
/// Returns width of rendered text in pixels. /// color, bgcolor as background. Fills at least minwidth pixels with
/// ''' /// bgcolor. Returns width of rendered text in pixels.
STATIC mp_obj_t mod_trezorui_Display_text_center(size_t n_args, const mp_obj_t *args) { /// '''
mp_int_t x = mp_obj_get_int(args[1]); STATIC mp_obj_t mod_trezorui_Display_text_center(size_t n_args,
mp_int_t y = mp_obj_get_int(args[2]); const mp_obj_t *args) {
mp_buffer_info_t text; mp_int_t x = mp_obj_get_int(args[1]);
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ); mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t font = mp_obj_get_int(args[4]); mp_buffer_info_t text;
mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t bgcolor = mp_obj_get_int(args[6]); mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0; mp_int_t fgcolor = mp_obj_get_int(args[5]);
// prefill start mp_int_t bgcolor = mp_obj_get_int(args[6]);
int w = display_text_width(text.buf, text.len, font); mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
int barwidth = MAX(w, minwidth); // prefill start
display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor); int w = display_text_width(text.buf, text.len, font);
// prefill end int barwidth = MAX(w, minwidth);
display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor); display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor);
return mp_obj_new_int(w); // prefill end
display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_center_obj, 7, 8, mod_trezorui_Display_text_center); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_center_obj,
7, 8,
mod_trezorui_Display_text_center);
/// def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> int: /// def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int,
/// ''' /// bgcolor: int, minwidth: int=None) -> int:
/// Renders right-aligned text at position (x,y) where x is right position and y is baseline. /// '''
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background. /// Renders right-aligned text at position (x,y) where x is right position
/// Fills at least minwidth pixels with bgcolor. /// and y is baseline. Font font is used for rendering, fgcolor is used as
/// Returns width of rendered text in pixels. /// foreground color, bgcolor as background. Fills at least minwidth pixels
/// ''' /// with bgcolor. Returns width of rendered text in pixels.
STATIC mp_obj_t mod_trezorui_Display_text_right(size_t n_args, const mp_obj_t *args) { /// '''
mp_int_t x = mp_obj_get_int(args[1]); STATIC mp_obj_t mod_trezorui_Display_text_right(size_t n_args,
mp_int_t y = mp_obj_get_int(args[2]); const mp_obj_t *args) {
mp_buffer_info_t text; mp_int_t x = mp_obj_get_int(args[1]);
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ); mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t font = mp_obj_get_int(args[4]); mp_buffer_info_t text;
mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t bgcolor = mp_obj_get_int(args[6]); mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0; mp_int_t fgcolor = mp_obj_get_int(args[5]);
// prefill start mp_int_t bgcolor = mp_obj_get_int(args[6]);
int w = display_text_width(text.buf, text.len, font); mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
int barwidth = MAX(w, minwidth); // prefill start
display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor); int w = display_text_width(text.buf, text.len, font);
// prefill end int barwidth = MAX(w, minwidth);
display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor); display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor);
return mp_obj_new_int(w); // prefill end
display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj, 7, 8, mod_trezorui_Display_text_right); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_text_right_obj,
7, 8,
mod_trezorui_Display_text_right);
/// def text_width(self, text: str, font: int) -> int: /// def text_width(self, text: str, font: int) -> int:
/// ''' /// '''
/// Returns a width of text in pixels. Font font is used for rendering. /// Returns a width of text in pixels. Font font is used for rendering.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text, mp_obj_t font) { STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text,
mp_buffer_info_t txt; mp_obj_t font) {
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ); mp_buffer_info_t txt;
mp_int_t f = mp_obj_get_int(font); mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
int w = display_text_width(txt.buf, txt.len, f); mp_int_t f = mp_obj_get_int(font);
return mp_obj_new_int(w); int w = display_text_width(txt.buf, txt.len, f);
return mp_obj_new_int(w);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj, mod_trezorui_Display_text_width); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorui_Display_text_width_obj,
mod_trezorui_Display_text_width);
/// def qrcode(self, x: int, y: int, data: bytes, scale: int) -> None: /// def qrcode(self, x: int, y: int, data: bytes, scale: int) -> None:
/// ''' /// '''
/// Renders data encoded as a QR code centered at position (x,y). /// Renders data encoded as a QR code centered at position (x,y).
/// Scale determines a zoom factor. /// Scale determines a zoom factor.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_qrcode(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_qrcode(size_t n_args,
mp_int_t x = mp_obj_get_int(args[1]); const mp_obj_t *args) {
mp_int_t y = mp_obj_get_int(args[2]); mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t scale = mp_obj_get_int(args[4]); mp_int_t y = mp_obj_get_int(args[2]);
if (scale < 1 || scale > 10) { mp_int_t scale = mp_obj_get_int(args[4]);
mp_raise_ValueError("Scale has to be between 1 and 10"); if (scale < 1 || scale > 10) {
} mp_raise_ValueError("Scale has to be between 1 and 10");
mp_buffer_info_t data; }
mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ); mp_buffer_info_t data;
if (data.len > 0) { mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ);
display_qrcode(x, y, data.buf, data.len, scale); if (data.len > 0) {
} display_qrcode(x, y, data.buf, data.len, scale);
return mp_const_none; }
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_qrcode_obj, 5, 5, mod_trezorui_Display_qrcode); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_qrcode_obj, 5,
5, mod_trezorui_Display_qrcode);
/// def orientation(self, degrees: int = None) -> int: /// def orientation(self, degrees: int = None) -> int:
/// ''' /// '''
/// Sets display orientation to 0, 90, 180 or 270 degrees. /// Sets display orientation to 0, 90, 180 or 270 degrees.
/// Everything needs to be redrawn again when this function is used. /// Everything needs to be redrawn again when this function is used.
/// Call without the degrees parameter to just perform the read of the value. /// Call without the degrees parameter to just perform the read of the
/// ''' /// value.
STATIC mp_obj_t mod_trezorui_Display_orientation(size_t n_args, const mp_obj_t *args) { /// '''
mp_int_t deg; STATIC mp_obj_t mod_trezorui_Display_orientation(size_t n_args,
if (n_args > 1) { const mp_obj_t *args) {
deg = mp_obj_get_int(args[1]); mp_int_t deg;
if (deg != 0 && deg != 90 && deg != 180 && deg != 270) { if (n_args > 1) {
mp_raise_ValueError("Value must be 0, 90, 180 or 270"); deg = mp_obj_get_int(args[1]);
} if (deg != 0 && deg != 90 && deg != 180 && deg != 270) {
deg = display_orientation(deg); mp_raise_ValueError("Value must be 0, 90, 180 or 270");
} else {
deg = display_orientation(-1);
} }
return MP_OBJ_NEW_SMALL_INT(deg); deg = display_orientation(deg);
} else {
deg = display_orientation(-1);
}
return MP_OBJ_NEW_SMALL_INT(deg);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_orientation_obj, 1, 2, mod_trezorui_Display_orientation); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_orientation_obj,
1, 2,
mod_trezorui_Display_orientation);
/// def backlight(self, val: int = None) -> int: /// def backlight(self, val: int = None) -> int:
/// ''' /// '''
/// Sets backlight intensity to the value specified in val. /// Sets backlight intensity to the value specified in val.
/// Call without the val parameter to just perform the read of the value. /// Call without the val parameter to just perform the read of the value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_backlight(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_backlight(size_t n_args,
mp_int_t val; const mp_obj_t *args) {
if (n_args > 1) { mp_int_t val;
val = mp_obj_get_int(args[1]); if (n_args > 1) {
if (val < 0 || val > 255) { val = mp_obj_get_int(args[1]);
mp_raise_ValueError("Value must be between 0 and 255"); if (val < 0 || val > 255) {
} mp_raise_ValueError("Value must be between 0 and 255");
val = display_backlight(val);
} else {
val = display_backlight(-1);
} }
return MP_OBJ_NEW_SMALL_INT(val); val = display_backlight(val);
} else {
val = display_backlight(-1);
}
return MP_OBJ_NEW_SMALL_INT(val);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_backlight_obj, 1, 2, mod_trezorui_Display_backlight); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_backlight_obj,
1, 2,
mod_trezorui_Display_backlight);
/// def offset(self, xy: Tuple[int, int] = None) -> Tuple[int, int]: /// def offset(self, xy: Tuple[int, int] = None) -> Tuple[int, int]:
/// ''' /// '''
/// Sets offset (x, y) for all subsequent drawing calls. /// Sets offset (x, y) for all subsequent drawing calls.
/// Call without the xy parameter to just perform the read of the value. /// Call without the xy parameter to just perform the read of the value.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_offset(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorui_Display_offset(size_t n_args,
int xy[2], x, y; const mp_obj_t *args) {
if (n_args > 1) { int xy[2], x, y;
size_t xy_cnt; if (n_args > 1) {
mp_obj_t *xy_obj; size_t xy_cnt;
if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple)) { mp_obj_t *xy_obj;
mp_obj_tuple_get(args[1], &xy_cnt, &xy_obj); if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple)) {
} else { mp_obj_tuple_get(args[1], &xy_cnt, &xy_obj);
mp_raise_TypeError("Tuple expected");
}
if (xy_cnt != 2) {
mp_raise_ValueError("Tuple of 2 values expected");
}
xy[0] = mp_obj_get_int(xy_obj[0]);
xy[1] = mp_obj_get_int(xy_obj[1]);
display_offset(xy, &x, &y);
} else { } else {
display_offset(0, &x, &y); mp_raise_TypeError("Tuple expected");
}
if (xy_cnt != 2) {
mp_raise_ValueError("Tuple of 2 values expected");
} }
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); xy[0] = mp_obj_get_int(xy_obj[0]);
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(x); xy[1] = mp_obj_get_int(xy_obj[1]);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(y); display_offset(xy, &x, &y);
return MP_OBJ_FROM_PTR(tuple); } else {
display_offset(0, &x, &y);
}
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(x);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(y);
return MP_OBJ_FROM_PTR(tuple);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_offset_obj, 1, 2, mod_trezorui_Display_offset); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_offset_obj, 1,
2, mod_trezorui_Display_offset);
/// def save(self, prefix: str) -> None: /// def save(self, prefix: str) -> None:
/// ''' /// '''
/// Saves current display contents to PNG file with given prefix. /// Saves current display contents to PNG file with given prefix.
/// ''' /// '''
STATIC mp_obj_t mod_trezorui_Display_save(mp_obj_t self, mp_obj_t prefix) { STATIC mp_obj_t mod_trezorui_Display_save(mp_obj_t self, mp_obj_t prefix) {
mp_buffer_info_t pfx; mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ); mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len > 0) { if (pfx.len > 0) {
display_save(pfx.buf); display_save(pfx.buf);
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj, mod_trezorui_Display_save); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj,
mod_trezorui_Display_save);
STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = { STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&mod_trezorui_Display_clear_obj) }, {MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&mod_trezorui_Display_clear_obj)},
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&mod_trezorui_Display_refresh_obj) }, {MP_ROM_QSTR(MP_QSTR_refresh),
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj) }, MP_ROM_PTR(&mod_trezorui_Display_refresh_obj)},
{ MP_ROM_QSTR(MP_QSTR_bar_radius), MP_ROM_PTR(&mod_trezorui_Display_bar_radius_obj) }, {MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj)},
{ MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&mod_trezorui_Display_image_obj) }, {MP_ROM_QSTR(MP_QSTR_bar_radius),
{ MP_ROM_QSTR(MP_QSTR_avatar), MP_ROM_PTR(&mod_trezorui_Display_avatar_obj) }, MP_ROM_PTR(&mod_trezorui_Display_bar_radius_obj)},
{ MP_ROM_QSTR(MP_QSTR_icon), MP_ROM_PTR(&mod_trezorui_Display_icon_obj) }, {MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&mod_trezorui_Display_image_obj)},
{ MP_ROM_QSTR(MP_QSTR_loader), MP_ROM_PTR(&mod_trezorui_Display_loader_obj) }, {MP_ROM_QSTR(MP_QSTR_avatar), MP_ROM_PTR(&mod_trezorui_Display_avatar_obj)},
{ MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mod_trezorui_Display_print_obj) }, {MP_ROM_QSTR(MP_QSTR_icon), MP_ROM_PTR(&mod_trezorui_Display_icon_obj)},
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&mod_trezorui_Display_text_obj) }, {MP_ROM_QSTR(MP_QSTR_loader), MP_ROM_PTR(&mod_trezorui_Display_loader_obj)},
{ MP_ROM_QSTR(MP_QSTR_text_center), MP_ROM_PTR(&mod_trezorui_Display_text_center_obj) }, {MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mod_trezorui_Display_print_obj)},
{ MP_ROM_QSTR(MP_QSTR_text_right), MP_ROM_PTR(&mod_trezorui_Display_text_right_obj) }, {MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&mod_trezorui_Display_text_obj)},
{ MP_ROM_QSTR(MP_QSTR_text_width), MP_ROM_PTR(&mod_trezorui_Display_text_width_obj) }, {MP_ROM_QSTR(MP_QSTR_text_center),
{ MP_ROM_QSTR(MP_QSTR_qrcode), MP_ROM_PTR(&mod_trezorui_Display_qrcode_obj) }, MP_ROM_PTR(&mod_trezorui_Display_text_center_obj)},
{ MP_ROM_QSTR(MP_QSTR_orientation), MP_ROM_PTR(&mod_trezorui_Display_orientation_obj) }, {MP_ROM_QSTR(MP_QSTR_text_right),
{ MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&mod_trezorui_Display_backlight_obj) }, MP_ROM_PTR(&mod_trezorui_Display_text_right_obj)},
{ MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&mod_trezorui_Display_offset_obj) }, {MP_ROM_QSTR(MP_QSTR_text_width),
{ MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&mod_trezorui_Display_save_obj) }, MP_ROM_PTR(&mod_trezorui_Display_text_width_obj)},
{ MP_ROM_QSTR(MP_QSTR_WIDTH), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESX) }, {MP_ROM_QSTR(MP_QSTR_qrcode), MP_ROM_PTR(&mod_trezorui_Display_qrcode_obj)},
{ MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESY) }, {MP_ROM_QSTR(MP_QSTR_orientation),
{ MP_ROM_QSTR(MP_QSTR_FONT_SIZE), MP_OBJ_NEW_SMALL_INT(FONT_SIZE) }, MP_ROM_PTR(&mod_trezorui_Display_orientation_obj)},
{ MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_OBJ_NEW_SMALL_INT(FONT_NORMAL) }, {MP_ROM_QSTR(MP_QSTR_backlight),
{ MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_BOLD) }, MP_ROM_PTR(&mod_trezorui_Display_backlight_obj)},
{ MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_OBJ_NEW_SMALL_INT(FONT_MONO) }, {MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&mod_trezorui_Display_offset_obj)},
{ MP_ROM_QSTR(MP_QSTR_FONT_MONO_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_MONO_BOLD) }, {MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&mod_trezorui_Display_save_obj)},
{MP_ROM_QSTR(MP_QSTR_WIDTH), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESX)},
{MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_OBJ_NEW_SMALL_INT(DISPLAY_RESY)},
{MP_ROM_QSTR(MP_QSTR_FONT_SIZE), MP_OBJ_NEW_SMALL_INT(FONT_SIZE)},
{MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_OBJ_NEW_SMALL_INT(FONT_NORMAL)},
{MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_BOLD)},
{MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_OBJ_NEW_SMALL_INT(FONT_MONO)},
{MP_ROM_QSTR(MP_QSTR_FONT_MONO_BOLD), MP_OBJ_NEW_SMALL_INT(FONT_MONO_BOLD)},
}; };
STATIC MP_DEFINE_CONST_DICT(mod_trezorui_Display_locals_dict, mod_trezorui_Display_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(mod_trezorui_Display_locals_dict,
mod_trezorui_Display_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorui_Display_type = { STATIC const mp_obj_type_t mod_trezorui_Display_type = {
{ &mp_type_type }, {&mp_type_type},
.name = MP_QSTR_Display, .name = MP_QSTR_Display,
.make_new = mod_trezorui_Display_make_new, .make_new = mod_trezorui_Display_make_new,
.locals_dict = (void*)&mod_trezorui_Display_locals_dict, .locals_dict = (void *)&mod_trezorui_Display_locals_dict,
}; };

@ -17,9 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include "py/runtime.h" #include "py/runtime.h"
@ -28,15 +28,16 @@
#include "modtrezorui-display.h" #include "modtrezorui-display.h"
STATIC const mp_rom_map_elem_t mp_module_trezorui_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_trezorui_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorui) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorui)},
{ MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&mod_trezorui_Display_type) }, {MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&mod_trezorui_Display_type)},
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorui_globals, mp_module_trezorui_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_trezorui_globals,
mp_module_trezorui_globals_table);
const mp_obj_module_t mp_module_trezorui = { const mp_obj_module_t mp_module_trezorui = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mp_module_trezorui_globals, .globals = (mp_obj_dict_t*)&mp_module_trezorui_globals,
}; };
#endif // MICROPY_PY_TREZORUI #endif // MICROPY_PY_TREZORUI

@ -36,25 +36,26 @@
/// expected to avoid any invalid memory access. /// expected to avoid any invalid memory access.
/// ''' /// '''
STATIC mp_obj_t mod_trezorutils_consteq(mp_obj_t sec, mp_obj_t pub) { STATIC mp_obj_t mod_trezorutils_consteq(mp_obj_t sec, mp_obj_t pub) {
mp_buffer_info_t secbuf; mp_buffer_info_t secbuf;
mp_get_buffer_raise(sec, &secbuf, MP_BUFFER_READ); mp_get_buffer_raise(sec, &secbuf, MP_BUFFER_READ);
mp_buffer_info_t pubbuf; mp_buffer_info_t pubbuf;
mp_get_buffer_raise(pub, &pubbuf, MP_BUFFER_READ); mp_get_buffer_raise(pub, &pubbuf, MP_BUFFER_READ);
size_t diff = secbuf.len - pubbuf.len; size_t diff = secbuf.len - pubbuf.len;
for (size_t i = 0; i < pubbuf.len; i++) { for (size_t i = 0; i < pubbuf.len; i++) {
const uint8_t *s = (uint8_t *)secbuf.buf; const uint8_t *s = (uint8_t *)secbuf.buf;
const uint8_t *p = (uint8_t *)pubbuf.buf; const uint8_t *p = (uint8_t *)pubbuf.buf;
diff |= s[i] - p[i]; diff |= s[i] - p[i];
} }
if (diff == 0) { if (diff == 0) {
return mp_const_true; return mp_const_true;
} else { } else {
return mp_const_false; return mp_const_false;
} }
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorutils_consteq_obj, mod_trezorutils_consteq); STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorutils_consteq_obj,
mod_trezorutils_consteq);
/// def memcpy(dst: bytearray, dst_ofs: int, /// def memcpy(dst: bytearray, dst_ofs: int,
/// src: bytearray, src_ofs: int, /// src: bytearray, src_ofs: int,
@ -65,42 +66,44 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorutils_consteq_obj, mod_trezorutils_co
/// copied bytes. /// copied bytes.
/// ''' /// '''
STATIC mp_obj_t mod_trezorutils_memcpy(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorutils_memcpy(size_t n_args, const mp_obj_t *args) {
mp_arg_check_num(n_args, 0, 5, 5, false); mp_arg_check_num(n_args, 0, 5, 5, false);
mp_buffer_info_t dst; mp_buffer_info_t dst;
mp_get_buffer_raise(args[0], &dst, MP_BUFFER_WRITE); mp_get_buffer_raise(args[0], &dst, MP_BUFFER_WRITE);
uint32_t dst_ofs = trezor_obj_get_uint(args[1]); uint32_t dst_ofs = trezor_obj_get_uint(args[1]);
mp_buffer_info_t src; mp_buffer_info_t src;
mp_get_buffer_raise(args[2], &src, MP_BUFFER_READ); mp_get_buffer_raise(args[2], &src, MP_BUFFER_READ);
uint32_t src_ofs = trezor_obj_get_uint(args[3]); uint32_t src_ofs = trezor_obj_get_uint(args[3]);
uint32_t n = trezor_obj_get_uint(args[4]); uint32_t n = trezor_obj_get_uint(args[4]);
size_t dst_rem = (dst_ofs < dst.len) ? dst.len - dst_ofs : 0; size_t dst_rem = (dst_ofs < dst.len) ? dst.len - dst_ofs : 0;
size_t src_rem = (src_ofs < src.len) ? src.len - src_ofs : 0; size_t src_rem = (src_ofs < src.len) ? src.len - src_ofs : 0;
size_t ncpy = MIN(n, MIN(src_rem, dst_rem)); size_t ncpy = MIN(n, MIN(src_rem, dst_rem));
memmove(((char*)dst.buf) + dst_ofs, ((const char*)src.buf) + src_ofs, ncpy); memmove(((char *)dst.buf) + dst_ofs, ((const char *)src.buf) + src_ofs, ncpy);
return mp_obj_new_int(ncpy); return mp_obj_new_int(ncpy);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_memcpy_obj, 5, 5, mod_trezorutils_memcpy); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_memcpy_obj, 5, 5,
mod_trezorutils_memcpy);
/// def halt(msg: str = None) -> None: /// def halt(msg: str = None) -> None:
/// ''' /// '''
/// Halts execution. /// Halts execution.
/// ''' /// '''
STATIC mp_obj_t mod_trezorutils_halt(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_trezorutils_halt(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t msg; mp_buffer_info_t msg;
if (n_args > 0 && mp_get_buffer(args[0], &msg, MP_BUFFER_READ)) { if (n_args > 0 && mp_get_buffer(args[0], &msg, MP_BUFFER_READ)) {
ensure(secfalse, msg.buf); ensure(secfalse, msg.buf);
} else { } else {
ensure(secfalse, "halt"); ensure(secfalse, "halt");
} }
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1, mod_trezorutils_halt); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1,
mod_trezorutils_halt);
/// def set_mode_unprivileged() -> None: /// def set_mode_unprivileged() -> None:
/// ''' /// '''
@ -108,40 +111,43 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1, mod_t
/// ''' /// '''
STATIC mp_obj_t mod_trezorutils_set_mode_unprivileged(void) { STATIC mp_obj_t mod_trezorutils_set_mode_unprivileged(void) {
#ifndef TREZOR_EMULATOR #ifndef TREZOR_EMULATOR
__asm__ volatile("msr control, %0" :: "r" (0x1)); __asm__ volatile("msr control, %0" ::"r"(0x1));
__asm__ volatile("isb"); __asm__ volatile("isb");
#endif #endif
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_set_mode_unprivileged_obj, mod_trezorutils_set_mode_unprivileged); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_set_mode_unprivileged_obj,
mod_trezorutils_set_mode_unprivileged);
#define PASTER(s) MP_QSTR_ ## s #define PASTER(s) MP_QSTR_##s
#define MP_QSTR(s) PASTER(s) #define MP_QSTR(s) PASTER(s)
STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils)},
{ MP_ROM_QSTR(MP_QSTR_consteq), MP_ROM_PTR(&mod_trezorutils_consteq_obj) }, {MP_ROM_QSTR(MP_QSTR_consteq), MP_ROM_PTR(&mod_trezorutils_consteq_obj)},
{ MP_ROM_QSTR(MP_QSTR_memcpy), MP_ROM_PTR(&mod_trezorutils_memcpy_obj) }, {MP_ROM_QSTR(MP_QSTR_memcpy), MP_ROM_PTR(&mod_trezorutils_memcpy_obj)},
{ MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&mod_trezorutils_halt_obj) }, {MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&mod_trezorutils_halt_obj)},
{ MP_ROM_QSTR(MP_QSTR_set_mode_unprivileged), MP_ROM_PTR(&mod_trezorutils_set_mode_unprivileged_obj) }, {MP_ROM_QSTR(MP_QSTR_set_mode_unprivileged),
MP_ROM_PTR(&mod_trezorutils_set_mode_unprivileged_obj)},
// various built-in constants // various built-in constants
{ MP_ROM_QSTR(MP_QSTR_GITREV), MP_ROM_QSTR(MP_QSTR(GITREV)) }, {MP_ROM_QSTR(MP_QSTR_GITREV), MP_ROM_QSTR(MP_QSTR(GITREV))},
{ MP_ROM_QSTR(MP_QSTR_VERSION_MAJOR), MP_OBJ_NEW_SMALL_INT(VERSION_MAJOR) }, {MP_ROM_QSTR(MP_QSTR_VERSION_MAJOR), MP_OBJ_NEW_SMALL_INT(VERSION_MAJOR)},
{ MP_ROM_QSTR(MP_QSTR_VERSION_MINOR), MP_OBJ_NEW_SMALL_INT(VERSION_MINOR) }, {MP_ROM_QSTR(MP_QSTR_VERSION_MINOR), MP_OBJ_NEW_SMALL_INT(VERSION_MINOR)},
{ MP_ROM_QSTR(MP_QSTR_VERSION_PATCH), MP_OBJ_NEW_SMALL_INT(VERSION_PATCH) }, {MP_ROM_QSTR(MP_QSTR_VERSION_PATCH), MP_OBJ_NEW_SMALL_INT(VERSION_PATCH)},
{ MP_ROM_QSTR(MP_QSTR_MODEL), MP_ROM_QSTR(MP_QSTR(TREZOR_MODEL)) }, {MP_ROM_QSTR(MP_QSTR_MODEL), MP_ROM_QSTR(MP_QSTR(TREZOR_MODEL))},
#ifdef TREZOR_EMULATOR #ifdef TREZOR_EMULATOR
{ MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_true }, {MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_true},
#else #else
{ MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_false }, {MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_false},
#endif #endif
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorutils_globals, mp_module_trezorutils_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_trezorutils_globals,
mp_module_trezorutils_globals_table);
const mp_obj_module_t mp_module_trezorutils = { const mp_obj_module_t mp_module_trezorutils = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&mp_module_trezorutils_globals, .globals = (mp_obj_dict_t *)&mp_module_trezorutils_globals,
}; };
#endif // MICROPY_PY_TREZORUTILS #endif // MICROPY_PY_TREZORUTILS

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "py/runtime.h"
#include "py/objint.h" #include "py/objint.h"
#include "py/runtime.h"
#ifndef __TREZOROBJ_H__ #ifndef __TREZOROBJ_H__
#define __TREZOROBJ_H__ #define __TREZOROBJ_H__
@ -30,51 +30,49 @@
// Casts int object into mp_int_t, without any conversions. Raises if object is // Casts int object into mp_int_t, without any conversions. Raises if object is
// not int or if it does not fit into mp_int_t representation. // not int or if it does not fit into mp_int_t representation.
static inline mp_int_t trezor_obj_get_int(mp_obj_t obj) { static inline mp_int_t trezor_obj_get_int(mp_obj_t obj) {
if (MP_OBJ_IS_SMALL_INT(obj)) { if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj); mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
return i; return i;
} } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { mp_int_t i = 0;
mp_int_t i = 0; mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj); if (!mpz_as_int_checked(&self->mpz, &i)) {
if (!mpz_as_int_checked(&self->mpz, &i)) { mp_raise_msg(&mp_type_OverflowError,
mp_raise_msg(&mp_type_OverflowError, "value does not fit into signed int type"); "value does not fit into signed int type");
}
return i;
}
else {
mp_raise_TypeError("value is not int");
} }
return i;
} else {
mp_raise_TypeError("value is not int");
}
} }
// Casts int object into mp_uint_t, without any conversions. Raises if object is // Casts int object into mp_uint_t, without any conversions. Raises if object is
// not int or if it does not fit into mp_uint_t representation (or is less than // not int or if it does not fit into mp_uint_t representation (or is less than
// 0). // 0).
static inline mp_uint_t trezor_obj_get_uint(mp_obj_t obj) { static inline mp_uint_t trezor_obj_get_uint(mp_obj_t obj) {
if (MP_OBJ_IS_SMALL_INT(obj)) { if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj); mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
mp_uint_t u = i; mp_uint_t u = i;
return u; return u;
} } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { mp_uint_t u = 0;
mp_uint_t u = 0; mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj); if (!mpz_as_uint_checked(&self->mpz, &u)) {
if (!mpz_as_uint_checked(&self->mpz, &u)) { mp_raise_msg(&mp_type_OverflowError,
mp_raise_msg(&mp_type_OverflowError, "value does not fit into unsigned int type"); "value does not fit into unsigned int type");
}
return u;
}
else {
mp_raise_TypeError("value is not int");
} }
return u;
} else {
mp_raise_TypeError("value is not int");
}
} }
static inline uint8_t trezor_obj_get_uint8(mp_obj_t obj) { static inline uint8_t trezor_obj_get_uint8(mp_obj_t obj) {
mp_uint_t u = trezor_obj_get_uint(obj); mp_uint_t u = trezor_obj_get_uint(obj);
if (u > 0xFF) { if (u > 0xFF) {
mp_raise_msg(&mp_type_OverflowError, "value does not fit into byte type"); mp_raise_msg(&mp_type_OverflowError, "value does not fit into byte type");
} }
return u; return u;
} }
#endif #endif

@ -19,9 +19,9 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "blake2s.h"
#include "common.h" #include "common.h"
#include "flash.h" #include "flash.h"
#include "blake2s.h"
// symbols from bootloader.bin => bootloader.o // symbols from bootloader.bin => bootloader.o
extern const uint32_t _binary_embed_firmware_bootloader_bin_start; extern const uint32_t _binary_embed_firmware_bootloader_bin_start;
@ -31,56 +31,83 @@ extern const uint32_t _binary_embed_firmware_bootloader_bin_size;
static secbool known_bootloader(const uint8_t *hash, int len) { static secbool known_bootloader(const uint8_t *hash, int len) {
if (len != 32) return secfalse; if (len != 32) return secfalse;
// bootloader-2.0.1.bin (padded with 0x00) // bootloader-2.0.1.bin (padded with 0x00)
if (0 == memcmp(hash, "\x91\x37\x46\xd0\x2d\xa7\xc4\xbe\x1d\xae\xef\xb0\x9b\x4e\x31\x88\xed\x38\x23\x5e\x0e\x31\xa7\x8c\x01\xde\x4e\xcc\xc2\xd6\x36\xb3", 32)) return sectrue; if (0 == memcmp(hash,
"\x91\x37\x46\xd0\x2d\xa7\xc4\xbe\x1d\xae\xef\xb0\x9b\x4e\x31\x88\xed\x38\x23\x5e\x0e\x31\xa7\x8c\x01\xde\x4e\xcc\xc2\xd6\x36\xb3",
32)) return sectrue;
// bootloader-2.0.1.bin (padded with 0xff) // bootloader-2.0.1.bin (padded with 0xff)
if (0 == memcmp(hash, "\x2f\xdb\xde\x94\x0a\xd8\x91\x1c\xbd\x07\xb0\xba\x06\x2c\x90\x84\x02\xec\x95\x19\xde\x52\x8d\x4b\xe9\xb9\xed\x30\x71\x91\xb4\xd3", 32)) return sectrue; if (0 == memcmp(hash,
"\x2f\xdb\xde\x94\x0a\xd8\x91\x1c\xbd\x07\xb0\xba\x06\x2c\x90\x84\x02\xec\x95\x19\xde\x52\x8d\x4b\xe9\xb9\xed\x30\x71\x91\xb4\xd3",
32)) return sectrue;
// bootloader-2.0.2.bin (padded with 0x00) // bootloader-2.0.2.bin (padded with 0x00)
if (0 == memcmp(hash, "\x2e\xf7\x47\xf8\x49\x87\x1e\xc8\xc6\x01\x35\xd6\x32\xe5\x5a\xd1\x56\x18\xf8\x64\x87\xb7\xaa\x7c\x62\x0e\xc3\x0d\x25\x69\x4e\x18", 32)) return sectrue; if (0 == memcmp(hash,
"\x2e\xf7\x47\xf8\x49\x87\x1e\xc8\xc6\x01\x35\xd6\x32\xe5\x5a\xd1\x56\x18\xf8\x64\x87\xb7\xaa\x7c\x62\x0e\xc3\x0d\x25\x69\x4e\x18",
32)) return sectrue;
// bootloader-2.0.2.bin (padded with 0xff) // bootloader-2.0.2.bin (padded with 0xff)
if (0 == memcmp(hash, "\xcc\x6b\x35\xc3\x8f\x29\x5c\xbd\x7d\x31\x69\xaf\xae\xf1\x61\x01\xef\xbe\x9f\x3b\x0a\xfd\xc5\x91\x70\x9b\xf5\xa0\xd5\xa4\xc5\xe0", 32)) return sectrue; if (0 == memcmp(hash,
"\xcc\x6b\x35\xc3\x8f\x29\x5c\xbd\x7d\x31\x69\xaf\xae\xf1\x61\x01\xef\xbe\x9f\x3b\x0a\xfd\xc5\x91\x70\x9b\xf5\xa0\xd5\xa4\xc5\xe0",
32)) return sectrue;
// bootloader-2.0.3.bin (padded with 0x00) // bootloader-2.0.3.bin (padded with 0x00)
if (0 == memcmp(hash, "\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14", 32)) return sectrue; if (0 == memcmp(hash,
"\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14",
32)) return sectrue;
// bootloader-2.0.3.bin (padded with 0xff) // bootloader-2.0.3.bin (padded with 0xff)
if (0 == memcmp(hash, "\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30", 32)) return sectrue; if (0 == memcmp(hash,
return secfalse; "\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30",
32)) return sectrue; return secfalse;
} }
*/ */
static secbool latest_bootloader(const uint8_t *hash, int len) { static secbool latest_bootloader(const uint8_t *hash, int len) {
if (len != 32) return secfalse; if (len != 32) return secfalse;
// bootloader.bin (padded with 0x00) // bootloader.bin (padded with 0x00)
if (0 == memcmp(hash, "\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14", 32)) return sectrue; if (0 ==
// bootloader.bin (padded with 0xff) memcmp(hash,
if (0 == memcmp(hash, "\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30", 32)) return sectrue; "\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53"
return secfalse; "\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14",
32))
return sectrue;
// bootloader.bin (padded with 0xff)
if (0 ==
memcmp(hash,
"\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7"
"\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30",
32))
return sectrue;
return secfalse;
} }
void check_and_replace_bootloader(void) void check_and_replace_bootloader(void) {
{ // compute current bootloader hash
// compute current bootloader hash uint8_t hash[BLAKE2S_DIGEST_LENGTH];
uint8_t hash[BLAKE2S_DIGEST_LENGTH]; const uint32_t bl_len = 128 * 1024;
const uint32_t bl_len = 128 * 1024; const void *bl_data = flash_get_address(FLASH_SECTOR_BOOTLOADER, 0, bl_len);
const void *bl_data = flash_get_address(FLASH_SECTOR_BOOTLOADER, 0, bl_len); blake2s(bl_data, bl_len, hash, BLAKE2S_DIGEST_LENGTH);
blake2s(bl_data, bl_len, hash, BLAKE2S_DIGEST_LENGTH);
// don't whitelist the valid bootloaders for now // don't whitelist the valid bootloaders for now
// ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader detected"); // ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader
// detected");
// do we have the latest bootloader? // do we have the latest bootloader?
if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) { if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) {
return; return;
} }
// replace bootloader with the latest one // replace bootloader with the latest one
const uint32_t *data = (const uint32_t *)&_binary_embed_firmware_bootloader_bin_start; const uint32_t *data =
const uint32_t len = (const uint32_t)&_binary_embed_firmware_bootloader_bin_size; (const uint32_t *)&_binary_embed_firmware_bootloader_bin_start;
ensure(flash_erase(FLASH_SECTOR_BOOTLOADER), NULL); const uint32_t len =
ensure(flash_unlock_write(), NULL); (const uint32_t)&_binary_embed_firmware_bootloader_bin_size;
for (int i = 0; i < len / sizeof(uint32_t); i++) { ensure(flash_erase(FLASH_SECTOR_BOOTLOADER), NULL);
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t), data[i]), NULL); ensure(flash_unlock_write(), NULL);
} for (int i = 0; i < len / sizeof(uint32_t); i++) {
for (int i = len / sizeof(uint32_t); i < 128 * 1024 / sizeof(uint32_t); i++) { ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t),
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t), 0x00000000), NULL); data[i]),
} NULL);
ensure(flash_lock_write(), NULL); }
for (int i = len / sizeof(uint32_t); i < 128 * 1024 / sizeof(uint32_t); i++) {
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t),
0x00000000),
NULL);
}
ensure(flash_lock_write(), NULL);
} }

@ -21,18 +21,19 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "py/nlr.h" #include "lib/utils/pyexec.h"
#include "py/compile.h" #include "py/compile.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/repl.h"
#include "py/gc.h" #include "py/gc.h"
#include "py/mperrno.h" #include "py/mperrno.h"
#include "lib/utils/pyexec.h" #include "py/nlr.h"
#include "py/repl.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "ports/stm32/gccollect.h" #include "ports/stm32/gccollect.h"
#include "ports/stm32/pendsv.h" #include "ports/stm32/pendsv.h"
#include "bl_check.h"
#include "common.h" #include "common.h"
#include "display.h" #include "display.h"
#include "flash.h" #include "flash.h"
@ -40,84 +41,82 @@
#include "rng.h" #include "rng.h"
#include "sdcard.h" #include "sdcard.h"
#include "touch.h" #include "touch.h"
#include "bl_check.h"
int main(void) int main(void) {
{ // reinitialize HAL for Trezor One
// reinitialize HAL for Trezor One
#if TREZOR_MODEL == 1 #if TREZOR_MODEL == 1
HAL_Init(); HAL_Init();
#endif #endif
collect_hw_entropy(); collect_hw_entropy();
#if TREZOR_MODEL == T #if TREZOR_MODEL == T
check_and_replace_bootloader(); check_and_replace_bootloader();
// Enable MPU // Enable MPU
mpu_config_firmware(); mpu_config_firmware();
#endif #endif
// Init peripherals // Init peripherals
pendsv_init(); pendsv_init();
#if TREZOR_MODEL == 1 #if TREZOR_MODEL == 1
display_init(); display_init();
touch_init(); touch_init();
#endif #endif
#if TREZOR_MODEL == T #if TREZOR_MODEL == T
sdcard_init(); sdcard_init();
touch_init(); touch_init();
touch_power_on(); touch_power_on();
display_clear(); display_clear();
#endif #endif
printf("CORE: Preparing stack\n"); printf("CORE: Preparing stack\n");
// Stack limit should be less than real stack size, so we have a chance // Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit. // to recover from limit hit.
mp_stack_set_top(&_estack); mp_stack_set_top(&_estack);
mp_stack_set_limit((char*)&_estack - (char*)&_heap_end - 1024); mp_stack_set_limit((char *)&_estack - (char *)&_heap_end - 1024);
// GC init // GC init
printf("CORE: Starting GC\n"); printf("CORE: Starting GC\n");
gc_init(&_heap_start, &_heap_end); gc_init(&_heap_start, &_heap_end);
// Interpreter init // Interpreter init
printf("CORE: Starting interpreter\n"); printf("CORE: Starting interpreter\n");
mp_init(); mp_init();
mp_obj_list_init(mp_sys_argv, 0); mp_obj_list_init(mp_sys_argv, 0);
mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) mp_obj_list_append(
mp_sys_path,
// Execute the main script MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
printf("CORE: Executing main script\n");
pyexec_frozen_module("main.py"); // Execute the main script
printf("CORE: Executing main script\n");
// Clean up pyexec_frozen_module("main.py");
printf("CORE: Main script finished, cleaning up\n");
mp_deinit(); // Clean up
printf("CORE: Main script finished, cleaning up\n");
return 0; mp_deinit();
return 0;
} }
// MicroPython default exception handler // MicroPython default exception handler
void __attribute__((noreturn)) nlr_jump_fail(void *val) { void __attribute__((noreturn)) nlr_jump_fail(void *val) {
ensure(secfalse, "uncaught exception"); ensure(secfalse, "uncaught exception");
} }
void PendSV_Handler(void) { void PendSV_Handler(void) { pendsv_isr_handler(); }
pendsv_isr_handler();
}
// MicroPython builtin stubs // MicroPython builtin stubs
mp_import_stat_t mp_import_stat(const char *path) { mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST; return MP_IMPORT_STAT_NO_EXIST;
} }
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

@ -27,21 +27,21 @@
#include "extmod/utime_mphal.h" #include "extmod/utime_mphal.h"
STATIC const mp_rom_map_elem_t time_module_globals_table[] = { STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime)},
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, {MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj)},
{ MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, {MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj)},
{ MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, {MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj)},
{ MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, {MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj)},
{ MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, {MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj)},
{ MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, {MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj)},
{ MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, {MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj)},
{ MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, {MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj)},
}; };
STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
const mp_obj_module_t mp_module_utime = { const mp_obj_module_t mp_module_utime = {
.base = { &mp_type_module }, .base = {&mp_type_module},
.globals = (mp_obj_dict_t*)&time_module_globals, .globals = (mp_obj_dict_t*)&time_module_globals,
}; };

@ -1,3 +1,5 @@
// clang-format off
/* /*
* This file is part of the MicroPython project, http://micropython.org/ * This file is part of the MicroPython project, http://micropython.org/
* *

@ -17,27 +17,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "common.h"
#include "py/mphal.h" #include "py/mphal.h"
#include "usb.h" #include "usb.h"
#include "common.h"
static int vcp_iface_num = -1; static int vcp_iface_num = -1;
int mp_hal_stdin_rx_chr(void) { int mp_hal_stdin_rx_chr(void) {
ensure(sectrue * (vcp_iface_num >= 0), "vcp stdio is not configured"); ensure(sectrue * (vcp_iface_num >= 0), "vcp stdio is not configured");
uint8_t c = 0; uint8_t c = 0;
int r = usb_vcp_read_blocking(vcp_iface_num, &c, 1, -1); int r = usb_vcp_read_blocking(vcp_iface_num, &c, 1, -1);
(void)r; (void)r;
return c; return c;
} }
void mp_hal_stdout_tx_strn(const char *str, size_t len) { void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (vcp_iface_num >= 0) { if (vcp_iface_num >= 0) {
int r = usb_vcp_write_blocking(vcp_iface_num, (const uint8_t *)str, len, 0); int r = usb_vcp_write_blocking(vcp_iface_num, (const uint8_t *)str, len, 0);
(void)r; (void)r;
} }
} }
void mp_hal_set_vcp_iface(int iface_num) { void mp_hal_set_vcp_iface(int iface_num) { vcp_iface_num = iface_num; }
vcp_iface_num = iface_num;
}

@ -19,8 +19,6 @@
#include "lib/utils/interrupt_char.h" #include "lib/utils/interrupt_char.h"
static inline mp_uint_t mp_hal_ticks_cpu(void) { static inline mp_uint_t mp_hal_ticks_cpu(void) { return 0; }
return 0;
}
void mp_hal_set_vcp_iface(int iface_num); void mp_hal_set_vcp_iface(int iface_num);

@ -1,3 +1,5 @@
// clang-format off
/* /*
* This file is part of the TREZOR project, https://trezor.io/ * This file is part of the TREZOR project, https://trezor.io/
* *

@ -1,9 +1,9 @@
#define VERSION_MAJOR 2 #define VERSION_MAJOR 2
#define VERSION_MINOR 1 #define VERSION_MINOR 1
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 0 #define VERSION_BUILD 0
#define FIX_VERSION_MAJOR 2 #define FIX_VERSION_MAJOR 2
#define FIX_VERSION_MINOR 1 #define FIX_VERSION_MINOR 1
#define FIX_VERSION_PATCH 0 #define FIX_VERSION_PATCH 0
#define FIX_VERSION_BUILD 0 #define FIX_VERSION_BUILD 0

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include STM32_HAL_H #include STM32_HAL_H
@ -38,393 +38,400 @@
enum { VCP_IFACE = 0x00 }; enum { VCP_IFACE = 0x00 };
static void vcp_intr(void) static void vcp_intr(void) {
{ display_clear();
display_clear(); ensure(secfalse, "vcp_intr");
ensure(secfalse, "vcp_intr");
} }
static void vcp_puts(const char *s, size_t len) static void vcp_puts(const char *s, size_t len) {
{ int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *)s, len, -1);
int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *) s, len, -1); (void)r;
(void)r;
} }
static char vcp_getchar(void) static char vcp_getchar(void) {
{ uint8_t c = 0;
uint8_t c = 0; int r = usb_vcp_read_blocking(VCP_IFACE, &c, 1, -1);
int r = usb_vcp_read_blocking(VCP_IFACE, &c, 1, -1); (void)r;
(void)r; return (char)c;
return (char)c;
} }
static void vcp_readline(char *buf, size_t len) static void vcp_readline(char *buf, size_t len) {
{ for (;;) {
for (;;) { char c = vcp_getchar();
char c = vcp_getchar(); if (c == '\r') {
if (c == '\r') { vcp_puts("\r\n", 2);
vcp_puts("\r\n", 2); break;
break; }
} if (c < 32 || c > 126) { // not printable
if (c < 32 || c > 126) { // not printable continue;
continue;
}
if (len > 1) { // leave space for \0
*buf = c;
buf++;
len--;
vcp_puts(&c, 1);
}
} }
if (len > 0) { if (len > 1) { // leave space for \0
*buf = '\0'; *buf = c;
buf++;
len--;
vcp_puts(&c, 1);
} }
}
if (len > 0) {
*buf = '\0';
}
} }
static void vcp_printf(const char *fmt, ...) static void vcp_printf(const char *fmt, ...) {
{ static char buf[128];
static char buf[128]; va_list va;
va_list va; va_start(va, fmt);
va_start(va, fmt); int r = mini_vsnprintf(buf, sizeof(buf), fmt, va);
int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); va_end(va);
va_end(va); vcp_puts(buf, r);
vcp_puts(buf, r); vcp_puts("\r\n", 2);
vcp_puts("\r\n", 2);
} }
static void usb_init_all(void) static void usb_init_all(void) {
{ enum {
enum { VCP_PACKET_LEN = 64,
VCP_PACKET_LEN = 64, VCP_BUFFER_LEN = 1024,
VCP_BUFFER_LEN = 1024, };
};
static const usb_dev_info_t dev_info = {
static const usb_dev_info_t dev_info = { .device_class = 0xEF, // Composite Device Class
.device_class = 0xEF, // Composite Device Class .device_subclass = 0x02, // Common Class
.device_subclass = 0x02, // Common Class .device_protocol = 0x01, // Interface Association Descriptor
.device_protocol = 0x01, // Interface Association Descriptor .vendor_id = 0x1209,
.vendor_id = 0x1209, .product_id = 0x53C1,
.product_id = 0x53C1, .release_num = 0x0400,
.release_num = 0x0400, .manufacturer = "SatoshiLabs",
.manufacturer = "SatoshiLabs", .product = "TREZOR",
.product = "TREZOR", .serial_number = "000000000000",
.serial_number = "000000000000", .interface = "TREZOR Interface",
.interface = "TREZOR Interface", .usb21_enabled = secfalse,
.usb21_enabled = secfalse, .usb21_landing = secfalse,
.usb21_landing = secfalse, };
};
static uint8_t tx_packet[VCP_PACKET_LEN];
static uint8_t tx_packet[VCP_PACKET_LEN]; static uint8_t tx_buffer[VCP_BUFFER_LEN];
static uint8_t tx_buffer[VCP_BUFFER_LEN]; static uint8_t rx_packet[VCP_PACKET_LEN];
static uint8_t rx_packet[VCP_PACKET_LEN]; static uint8_t rx_buffer[VCP_BUFFER_LEN];
static uint8_t rx_buffer[VCP_BUFFER_LEN];
static const usb_vcp_info_t vcp_info = {
static const usb_vcp_info_t vcp_info = { .tx_packet = tx_packet,
.tx_packet = tx_packet, .tx_buffer = tx_buffer,
.tx_buffer = tx_buffer, .rx_packet = rx_packet,
.rx_packet = rx_packet, .rx_buffer = rx_buffer,
.rx_buffer = rx_buffer, .tx_buffer_len = VCP_BUFFER_LEN,
.tx_buffer_len = VCP_BUFFER_LEN, .rx_buffer_len = VCP_BUFFER_LEN,
.rx_buffer_len = VCP_BUFFER_LEN, .rx_intr_fn = vcp_intr,
.rx_intr_fn = vcp_intr, .rx_intr_byte = 3, // Ctrl-C
.rx_intr_byte = 3, // Ctrl-C .iface_num = VCP_IFACE,
.iface_num = VCP_IFACE, .data_iface_num = 0x01,
.data_iface_num = 0x01, .ep_cmd = 0x82,
.ep_cmd = 0x82, .ep_in = 0x81,
.ep_in = 0x81, .ep_out = 0x01,
.ep_out = 0x01, .polling_interval = 10,
.polling_interval = 10, .max_packet_len = VCP_PACKET_LEN,
.max_packet_len = VCP_PACKET_LEN, };
};
usb_init(&dev_info);
usb_init(&dev_info); ensure(usb_vcp_add(&vcp_info), "usb_vcp_add");
ensure(usb_vcp_add(&vcp_info), "usb_vcp_add"); usb_start();
usb_start();
} }
static void draw_border(int width, int padding) static void draw_border(int width, int padding) {
{ const int W = width, P = padding, RX = DISPLAY_RESX, RY = DISPLAY_RESY;
const int W = width, P = padding, RX = DISPLAY_RESX, RY = DISPLAY_RESY; display_clear();
display_clear(); display_bar(P, P, RX - 2 * P, RY - 2 * P, 0xFFFF);
display_bar(P, P, RX - 2 * P, RY - 2 * P, 0xFFFF); display_bar(P + W, P + W, RX - 2 * (P + W), RY - 2 * (P + W), 0x0000);
display_bar(P + W, P + W, RX - 2 * (P + W), RY - 2 * (P + W), 0x0000); display_refresh();
display_refresh();
} }
static void test_border(void) static void test_border(void) {
{ draw_border(2, 0);
draw_border(2, 0); vcp_printf("OK");
vcp_printf("OK");
} }
static void test_display(const char *colors) static void test_display(const char *colors) {
{ display_clear();
display_clear();
size_t l = strlen(colors);
size_t l = strlen(colors); size_t w = DISPLAY_RESX / l;
size_t w = DISPLAY_RESX / l;
for (size_t i = 0; i < l; i++) {
for (size_t i = 0; i < l; i++) { uint16_t c = 0x0000; // black
uint16_t c = 0x0000; // black switch (colors[i]) {
switch (colors[i]) { case 'R':
case 'R': c = 0xF800; break; c = 0xF800;
case 'G': c = 0x07E0; break; break;
case 'B': c = 0x001F; break; case 'G':
case 'W': c = 0xFFFF; break; c = 0x07E0;
} break;
display_bar(i * w, 0, i * w + w, 240, c); case 'B':
c = 0x001F;
break;
case 'W':
c = 0xFFFF;
break;
} }
display_refresh(); display_bar(i * w, 0, i * w + w, 240, c);
vcp_printf("OK"); }
display_refresh();
vcp_printf("OK");
} }
static secbool touch_click_timeout(uint32_t *touch, uint32_t timeout_ms) static secbool touch_click_timeout(uint32_t *touch, uint32_t timeout_ms) {
{ uint32_t deadline = HAL_GetTick() + timeout_ms;
uint32_t deadline = HAL_GetTick() + timeout_ms; uint32_t r = 0;
uint32_t r = 0;
while (touch_read())
while (touch_read()); ;
while ((touch_read() & TOUCH_START) == 0) { while ((touch_read() & TOUCH_START) == 0) {
if (HAL_GetTick() > deadline) return secfalse; if (HAL_GetTick() > deadline) return secfalse;
} }
while (((r = touch_read()) & TOUCH_END) == 0) { while (((r = touch_read()) & TOUCH_END) == 0) {
if (HAL_GetTick() > deadline) return secfalse; if (HAL_GetTick() > deadline) return secfalse;
} }
while (touch_read()); while (touch_read())
;
*touch = r;
return sectrue; *touch = r;
return sectrue;
} }
static void test_touch(const char *args) static void test_touch(const char *args) {
{ int column = args[0] - '0';
int column = args[0] - '0'; int timeout = args[1] - '0';
int timeout = args[1] - '0';
display_clear();
display_clear(); switch (column) {
switch (column) { case 1:
case 1: display_bar(0, 0, 120, 120, 0xFFFF); break; display_bar(0, 0, 120, 120, 0xFFFF);
case 2: display_bar(120, 0, 120, 120, 0xFFFF); break; break;
case 3: display_bar(120, 120, 120, 120, 0xFFFF); break; case 2:
default: display_bar(0, 120, 120, 120, 0xFFFF); break; display_bar(120, 0, 120, 120, 0xFFFF);
} break;
display_refresh(); case 3:
display_bar(120, 120, 120, 120, 0xFFFF);
touch_power_on(); break;
default:
uint32_t evt = 0; display_bar(0, 120, 120, 120, 0xFFFF);
if (touch_click_timeout(&evt, timeout * 1000)) { break;
uint16_t x = touch_unpack_x(evt); }
uint16_t y = touch_unpack_y(evt); display_refresh();
vcp_printf("OK %d %d", x, y);
} else { touch_power_on();
vcp_printf("ERROR TIMEOUT");
} uint32_t evt = 0;
display_clear(); if (touch_click_timeout(&evt, timeout * 1000)) {
display_refresh(); uint16_t x = touch_unpack_x(evt);
uint16_t y = touch_unpack_y(evt);
touch_power_off(); vcp_printf("OK %d %d", x, y);
} else {
vcp_printf("ERROR TIMEOUT");
}
display_clear();
display_refresh();
touch_power_off();
} }
static void test_sensitivity(const char *args) static void test_sensitivity(const char *args) {
{ int v = atoi(args);
int v = atoi(args);
touch_power_on();
touch_power_on(); touch_sensitivity(v & 0xFF);
touch_sensitivity(v & 0xFF);
display_clear();
display_clear(); display_refresh();
display_refresh();
for (;;) {
for (;;) { uint32_t evt = touch_read();
uint32_t evt = touch_read(); if (evt & TOUCH_START || evt & TOUCH_MOVE) {
if (evt & TOUCH_START || evt & TOUCH_MOVE) { int x = touch_unpack_x(evt);
int x = touch_unpack_x(evt); int y = touch_unpack_y(evt);
int y = touch_unpack_y(evt); display_clear();
display_clear(); display_bar(x - 48, y - 48, 96, 96, 0xFFFF);
display_bar(x - 48, y - 48, 96, 96, 0xFFFF); display_refresh();
display_refresh(); } else if (evt & TOUCH_END) {
} else if (evt & TOUCH_END) { display_clear();
display_clear(); display_refresh();
display_refresh();
}
} }
}
touch_power_off(); touch_power_off();
} }
static void test_pwm(const char *args) static void test_pwm(const char *args) {
{ int v = atoi(args);
int v = atoi(args);
display_backlight(v); display_backlight(v);
display_refresh(); display_refresh();
vcp_printf("OK"); vcp_printf("OK");
} }
static void test_sd(void) static void test_sd(void) {
{
#define BLOCK_SIZE (32 * 1024) #define BLOCK_SIZE (32 * 1024)
static uint32_t buf1[BLOCK_SIZE / sizeof(uint32_t)]; static uint32_t buf1[BLOCK_SIZE / sizeof(uint32_t)];
static uint32_t buf2[BLOCK_SIZE / sizeof(uint32_t)]; static uint32_t buf2[BLOCK_SIZE / sizeof(uint32_t)];
if (sectrue != sdcard_is_present()) { if (sectrue != sdcard_is_present()) {
vcp_printf("ERROR NOCARD"); vcp_printf("ERROR NOCARD");
return; return;
}
ensure(sdcard_power_on(), NULL);
if (sectrue != sdcard_read_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
vcp_printf("ERROR sdcard_read_blocks (0)");
goto power_off;
}
for (int j = 1; j <= 2; j++) {
for (int i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) {
buf1[i] ^= 0xFFFFFFFF;
} }
if (sectrue !=
ensure(sdcard_power_on(), NULL); sdcard_write_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
if (sectrue != sdcard_read_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) { vcp_printf("ERROR sdcard_write_blocks (%d)", j);
vcp_printf("ERROR sdcard_read_blocks (0)"); goto power_off;
goto power_off;
} }
for (int j = 1; j <= 2; j++) { HAL_Delay(1000);
for (int i = 0; i < BLOCK_SIZE / sizeof(uint32_t); i++) { if (sectrue !=
buf1[i] ^= 0xFFFFFFFF; sdcard_read_blocks(buf2, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
} vcp_printf("ERROR sdcard_read_blocks (%d)", j);
if (sectrue != sdcard_write_blocks(buf1, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) { goto power_off;
vcp_printf("ERROR sdcard_write_blocks (%d)", j);
goto power_off;
}
HAL_Delay(1000);
if (sectrue != sdcard_read_blocks(buf2, 0, BLOCK_SIZE / SDCARD_BLOCK_SIZE)) {
vcp_printf("ERROR sdcard_read_blocks (%d)", j);
goto power_off;
}
if (0 != memcmp(buf1, buf2, sizeof(buf1))) {
vcp_printf("ERROR DATA MISMATCH");
goto power_off;
}
} }
vcp_printf("OK"); if (0 != memcmp(buf1, buf2, sizeof(buf1))) {
vcp_printf("ERROR DATA MISMATCH");
goto power_off;
}
}
vcp_printf("OK");
power_off: power_off:
sdcard_power_off(); sdcard_power_off();
} }
static void test_wipe(void) static void test_wipe(void) {
{ // erase start of the firmware (metadata) -> invalidate FW
// erase start of the firmware (metadata) -> invalidate FW ensure(flash_unlock_write(), NULL);
ensure(flash_unlock_write(), NULL); for (int i = 0; i < 1024 / sizeof(uint32_t); i++) {
for (int i = 0; i < 1024 / sizeof(uint32_t); i++) { ensure(flash_write_word(FLASH_SECTOR_FIRMWARE_START, i * sizeof(uint32_t),
ensure(flash_write_word(FLASH_SECTOR_FIRMWARE_START, i * sizeof(uint32_t), 0x00000000), NULL); 0x00000000),
} NULL);
ensure(flash_lock_write(), NULL); }
display_clear(); ensure(flash_lock_write(), NULL);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); display_clear();
display_refresh(); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1,
vcp_printf("OK"); FONT_BOLD, COLOR_WHITE, COLOR_BLACK);
display_refresh();
vcp_printf("OK");
} }
static void test_sbu(const char *args) static void test_sbu(const char *args) {
{ secbool sbu1 = sectrue * (args[0] == '1');
secbool sbu1 = sectrue * (args[0] == '1'); secbool sbu2 = sectrue * (args[1] == '1');
secbool sbu2 = sectrue * (args[1] == '1'); sbu_set(sbu1, sbu2);
sbu_set(sbu1, sbu2); vcp_printf("OK");
vcp_printf("OK");
} }
static void test_otp_read(void) static void test_otp_read(void) {
{ uint8_t data[32];
uint8_t data[32]; memzero(data, sizeof(data));
memzero(data, sizeof(data)); ensure(flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, data, sizeof(data)), NULL);
ensure(flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, data, sizeof(data)), NULL);
// strip trailing 0xFF
for (size_t i = 0; i < sizeof(data); i++) {
if (data[i] == 0xFF) {
data[i] = 0x00;
break;
}
}
// use (null) for empty data // strip trailing 0xFF
if (data[0] == 0x00) { for (size_t i = 0; i < sizeof(data); i++) {
vcp_printf("OK (null)"); if (data[i] == 0xFF) {
} else { data[i] = 0x00;
vcp_printf("OK %s", (const char *) data); break;
} }
}
// use (null) for empty data
if (data[0] == 0x00) {
vcp_printf("OK (null)");
} else {
vcp_printf("OK %s", (const char *)data);
}
} }
static void test_otp_write(const char *args) static void test_otp_write(const char *args) {
{ char data[32];
char data[32]; memzero(data, sizeof(data));
memzero(data, sizeof(data)); strncpy(data, args, sizeof(data) - 1);
strncpy(data, args, sizeof(data) - 1); ensure(flash_otp_write(FLASH_OTP_BLOCK_BATCH, 0, (const uint8_t *)data,
ensure(flash_otp_write(FLASH_OTP_BLOCK_BATCH, 0, (const uint8_t *) data, sizeof(data)), NULL); sizeof(data)),
ensure(flash_otp_lock(FLASH_OTP_BLOCK_BATCH), NULL); NULL);
vcp_printf("OK"); ensure(flash_otp_lock(FLASH_OTP_BLOCK_BATCH), NULL);
vcp_printf("OK");
} }
static secbool startswith(const char *s, const char *prefix) static secbool startswith(const char *s, const char *prefix) {
{ return sectrue * (0 == strncmp(s, prefix, strlen(prefix)));
return sectrue * (0 == strncmp(s, prefix, strlen(prefix)));
} }
#define BACKLIGHT_NORMAL 150 #define BACKLIGHT_NORMAL 150
int main(void) int main(void) {
{ display_orientation(0);
display_orientation(0); sdcard_init();
sdcard_init(); touch_init();
touch_init(); sbu_init();
sbu_init(); usb_init_all();
usb_init_all();
display_clear();
display_clear(); draw_border(1, 3);
draw_border(1, 3);
char dom[32];
// format: TREZOR2-YYMMDD
if (sectrue == flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, (uint8_t *)dom, 32) && 0 == memcmp(dom, "TREZOR2-", 8) && dom[31] == 0) {
display_qrcode(DISPLAY_RESX / 2, DISPLAY_RESY / 2, dom, strlen(dom), 4);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 30, dom + 8, -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK);
}
display_fade(0, BACKLIGHT_NORMAL, 1000); char dom[32];
// format: TREZOR2-YYMMDD
if (sectrue == flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, (uint8_t *)dom, 32) &&
0 == memcmp(dom, "TREZOR2-", 8) && dom[31] == 0) {
display_qrcode(DISPLAY_RESX / 2, DISPLAY_RESY / 2, dom, strlen(dom), 4);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 30, dom + 8, -1,
FONT_BOLD, COLOR_WHITE, COLOR_BLACK);
}
char line[128]; display_fade(0, BACKLIGHT_NORMAL, 1000);
for (;;) { char line[128];
vcp_readline(line, sizeof(line));
if (startswith(line, "PING")) { for (;;) {
vcp_printf("OK"); vcp_readline(line, sizeof(line));
} else if (startswith(line, "BORDER")) { if (startswith(line, "PING")) {
test_border(); vcp_printf("OK");
} else if (startswith(line, "DISP ")) { } else if (startswith(line, "BORDER")) {
test_display(line + 5); test_border();
} else if (startswith(line, "TOUCH ")) { } else if (startswith(line, "DISP ")) {
test_touch(line + 6); test_display(line + 5);
} else if (startswith(line, "SENS ")) { } else if (startswith(line, "TOUCH ")) {
test_sensitivity(line + 5); test_touch(line + 6);
} else if (startswith(line, "PWM ")) { } else if (startswith(line, "SENS ")) {
test_pwm(line + 4); test_sensitivity(line + 5);
} else if (startswith(line, "SD")) { } else if (startswith(line, "PWM ")) {
test_sd(); test_pwm(line + 4);
} else if (startswith(line, "SBU ")) { } else if (startswith(line, "SD")) {
test_sbu(line + 4); test_sd();
} else if (startswith(line, "OTP READ")) { } else if (startswith(line, "SBU ")) {
test_otp_read(); test_sbu(line + 4);
} else if (startswith(line, "OTP WRITE ")) { } else if (startswith(line, "OTP READ")) {
test_otp_write(line + 10); test_otp_read();
} else if (startswith(line, "WIPE")) { } else if (startswith(line, "OTP WRITE ")) {
test_wipe(); test_otp_write(line + 10);
} else { } else if (startswith(line, "WIPE")) {
vcp_printf("UNKNOWN"); test_wipe();
}
} else {
vcp_printf("UNKNOWN");
} }
}
return 0; return 0;
} }

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include STM32_HAL_H #include STM32_HAL_H
@ -33,77 +33,74 @@
#include "secbool.h" #include "secbool.h"
#include "touch.h" #include "touch.h"
static void progress_callback(int pos, int len) static void progress_callback(int pos, int len) { display_printf("."); }
{
display_printf(".");
}
static void flash_from_sdcard(uint8_t sector, uint32_t source, uint32_t length) static void flash_from_sdcard(uint8_t sector, uint32_t source,
{ uint32_t length) {
static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
ensure( ensure(sectrue * (source % SDCARD_BLOCK_SIZE == 0),
sectrue * (source % SDCARD_BLOCK_SIZE == 0), "source not a multiple of block size");
"source not a multiple of block size"); ensure(sectrue * (length % SDCARD_BLOCK_SIZE == 0),
ensure( "length not a multiple of block size");
sectrue * (length % SDCARD_BLOCK_SIZE == 0),
"length not a multiple of block size");
for (uint32_t i = 0; i < length / SDCARD_BLOCK_SIZE; i++) { for (uint32_t i = 0; i < length / SDCARD_BLOCK_SIZE; i++) {
display_printf("read %d\n", (unsigned int)(i + source / SDCARD_BLOCK_SIZE)); display_printf("read %d\n", (unsigned int)(i + source / SDCARD_BLOCK_SIZE));
ensure( ensure(sdcard_read_blocks(buf, i + source / SDCARD_BLOCK_SIZE, 1),
sdcard_read_blocks(buf, i + source / SDCARD_BLOCK_SIZE, 1), "sdcard_read_blocks");
"sdcard_read_blocks");
for (uint32_t j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { for (uint32_t j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) {
ensure(flash_write_word(sector, i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]), NULL); ensure(flash_write_word(
} sector, i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]),
NULL);
} }
}
} }
int main(void) int main(void) {
{ sdcard_init();
sdcard_init(); touch_init();
touch_init();
display_orientation(0); display_orientation(0);
display_clear(); display_clear();
display_backlight(255); display_backlight(255);
ensure( ensure(sdcard_is_present(), "sdcard_is_present");
sdcard_is_present(),
"sdcard_is_present");
display_printf("updating boardloader + bootloader\n"); display_printf("updating boardloader + bootloader\n");
static const uint8_t sectors[] = { static const uint8_t sectors[] = {
FLASH_SECTOR_BOARDLOADER_START, FLASH_SECTOR_BOARDLOADER_START,
1, 1,
FLASH_SECTOR_BOARDLOADER_END, FLASH_SECTOR_BOARDLOADER_END,
FLASH_SECTOR_BOOTLOADER, FLASH_SECTOR_BOOTLOADER,
}; };
display_printf("erasing sectors"); display_printf("erasing sectors");
ensure(flash_erase_sectors(sectors, sizeof(sectors), progress_callback), "flash_erase_sectors"); ensure(flash_erase_sectors(sectors, sizeof(sectors), progress_callback),
display_printf("\n"); "flash_erase_sectors");
display_printf("erased\n"); display_printf("\n");
display_printf("erased\n");
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
ensure(sdcard_power_on(), NULL); ensure(sdcard_power_on(), NULL);
#define BOARDLOADER_CHUNK_SIZE (16 * 1024) #define BOARDLOADER_CHUNK_SIZE (16 * 1024)
#define BOARDLOADER_TOTAL_SIZE (3 * BOARDLOADER_CHUNK_SIZE) #define BOARDLOADER_TOTAL_SIZE (3 * BOARDLOADER_CHUNK_SIZE)
#define BOOTLOADER_TOTAL_SIZE (128 * 1024) #define BOOTLOADER_TOTAL_SIZE (128 * 1024)
flash_from_sdcard(FLASH_SECTOR_BOARDLOADER_START, 0 * BOARDLOADER_CHUNK_SIZE, BOARDLOADER_CHUNK_SIZE); flash_from_sdcard(FLASH_SECTOR_BOARDLOADER_START, 0 * BOARDLOADER_CHUNK_SIZE,
flash_from_sdcard(1, 1 * BOARDLOADER_CHUNK_SIZE, BOARDLOADER_CHUNK_SIZE); BOARDLOADER_CHUNK_SIZE);
flash_from_sdcard(FLASH_SECTOR_BOARDLOADER_END, 2 * BOARDLOADER_CHUNK_SIZE, BOARDLOADER_CHUNK_SIZE); flash_from_sdcard(1, 1 * BOARDLOADER_CHUNK_SIZE, BOARDLOADER_CHUNK_SIZE);
flash_from_sdcard(FLASH_SECTOR_BOOTLOADER, BOARDLOADER_TOTAL_SIZE, BOOTLOADER_TOTAL_SIZE); flash_from_sdcard(FLASH_SECTOR_BOARDLOADER_END, 2 * BOARDLOADER_CHUNK_SIZE,
BOARDLOADER_CHUNK_SIZE);
flash_from_sdcard(FLASH_SECTOR_BOOTLOADER, BOARDLOADER_TOTAL_SIZE,
BOOTLOADER_TOTAL_SIZE);
display_printf("done\n"); display_printf("done\n");
sdcard_power_off(); sdcard_power_off();
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return 0; return 0;
} }

@ -1,9 +1,9 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 1 #define VERSION_MINOR 1
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 0 #define VERSION_BUILD 0
#define FIX_VERSION_MAJOR 0 #define FIX_VERSION_MAJOR 0
#define FIX_VERSION_MINOR 1 #define FIX_VERSION_MINOR 1
#define FIX_VERSION_PATCH 0 #define FIX_VERSION_PATCH 0
#define FIX_VERSION_BUILD 0 #define FIX_VERSION_BUILD 0

@ -23,9 +23,9 @@
#include "common.h" #include "common.h"
#include "display.h" #include "display.h"
#include "rng.h"
#include "rand.h"
#include "flash.h" #include "flash.h"
#include "rand.h"
#include "rng.h"
#include "stm32f4xx_ll_utils.h" #include "stm32f4xx_ll_utils.h"
@ -34,144 +34,154 @@ extern void shutdown(void);
#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) #define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00)
void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func) { void __attribute__((noreturn))
display_orientation(0); __fatal_error(const char *expr, const char *msg, const char *file, int line,
display_backlight(255); const char *func) {
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_orientation(0);
display_printf("\nFATAL ERROR:\n"); display_backlight(255);
if (expr) { display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
display_printf("expr: %s\n", expr); display_printf("\nFATAL ERROR:\n");
} if (expr) {
if (msg) { display_printf("expr: %s\n", expr);
display_printf("msg : %s\n", msg); }
} if (msg) {
if (file) { display_printf("msg : %s\n", msg);
display_printf("file: %s:%d\n", file, line); }
} if (file) {
if (func) { display_printf("file: %s:%d\n", file, line);
display_printf("func: %s\n", func); }
} if (func) {
display_printf("func: %s\n", func);
}
#ifdef GITREV #ifdef GITREV
display_printf("rev : %s\n", XSTR(GITREV)); display_printf("rev : %s\n", XSTR(GITREV));
#endif #endif
display_printf("\nPlease contact TREZOR support.\n"); display_printf("\nPlease contact TREZOR support.\n");
shutdown(); shutdown();
for (;;); for (;;)
;
} }
void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) void __attribute__((noreturn))
{ error_shutdown(const char *line1, const char *line2, const char *line3,
display_orientation(0); const char *line4) {
display_orientation(0);
#ifdef TREZOR_FONT_NORMAL_ENABLE #ifdef TREZOR_FONT_NORMAL_ENABLE
display_clear(); display_clear();
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR); display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR);
int y = 32; int y = 32;
if (line1) { if (line1) {
display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
if (line2) {
display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
if (line3) {
display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
if (line4) {
display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
y += 32; y += 32;
display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); }
if (line2) {
display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
if (line3) {
display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
if (line4) {
display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
y += 32;
}
y += 32;
display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE,
COLOR_FATAL_ERROR);
#else #else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
if (line1) { if (line1) {
display_printf("%s\n", line1); display_printf("%s\n", line1);
} }
if (line2) { if (line2) {
display_printf("%s\n", line2); display_printf("%s\n", line2);
} }
if (line3) { if (line3) {
display_printf("%s\n", line3); display_printf("%s\n", line3);
} }
if (line4) { if (line4) {
display_printf("%s\n", line4); display_printf("%s\n", line4);
} }
display_printf("\nPlease unplug the device.\n"); display_printf("\nPlease unplug the device.\n");
#endif #endif
display_backlight(255); display_backlight(255);
shutdown(); shutdown();
for (;;); for (;;)
;
} }
#ifndef NDEBUG #ifndef NDEBUG
void __assert_func(const char *file, int line, const char *func, const char *expr) { void __assert_func(const char *file, int line, const char *func,
__fatal_error(expr, "assert failed", file, line, func); const char *expr) {
__fatal_error(expr, "assert failed", file, line, func);
} }
#endif #endif
void hal_delay(uint32_t ms) void hal_delay(uint32_t ms) { HAL_Delay(ms); }
{
HAL_Delay(ms);
}
void delay_random(void) void delay_random(void) {
{ int wait = rng_get() & 0xff;
int wait = rng_get() & 0xff; volatile int i = 0;
volatile int i = 0; volatile int j = wait;
volatile int j = wait; while (i < wait) {
while (i < wait) { if (i + j != wait) {
if (i + j != wait) { shutdown();
shutdown();
}
++i;
--j;
}
// Double-check loop completion.
if (i != wait || j != 0) {
shutdown();
} }
++i;
--j;
}
// Double-check loop completion.
if (i != wait || j != 0) {
shutdown();
}
} }
// reference RM0090 section 35.12.1 Figure 413 // reference RM0090 section 35.12.1 Figure 413
#define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U) #define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U)
#define USB_OTG_HS_DATA_FIFO_SIZE (4096U) #define USB_OTG_HS_DATA_FIFO_SIZE (4096U)
void clear_otg_hs_memory(void) void clear_otg_hs_memory(void) {
{ // use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet
// use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); // enable USB_OTG_HS peripheral clock so
__HAL_RCC_USB_OTG_HS_CLK_ENABLE(); // enable USB_OTG_HS peripheral clock so that the peripheral memory is accessible // that the peripheral memory is
memset_reg((volatile void *) USB_OTG_HS_DATA_FIFO_RAM, (volatile void *) (USB_OTG_HS_DATA_FIFO_RAM + USB_OTG_HS_DATA_FIFO_SIZE), 0); // accessible
__HAL_RCC_USB_OTG_HS_CLK_DISABLE(); // disable USB OTG_HS peripheral clock as the peripheral is not needed right now memset_reg(
(volatile void *)USB_OTG_HS_DATA_FIFO_RAM,
(volatile void *)(USB_OTG_HS_DATA_FIFO_RAM + USB_OTG_HS_DATA_FIFO_SIZE),
0);
__HAL_RCC_USB_OTG_HS_CLK_DISABLE(); // disable USB OTG_HS peripheral clock as
// the peripheral is not needed right now
} }
uint32_t __stack_chk_guard = 0; uint32_t __stack_chk_guard = 0;
void __attribute__((noreturn)) __stack_chk_fail(void) void __attribute__((noreturn)) __stack_chk_fail(void) {
{ ensure(secfalse, "Stack smashing detected");
ensure(secfalse, "Stack smashing detected");
} }
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
void collect_hw_entropy(void) void collect_hw_entropy(void) {
{ // collect entropy from UUID
// collect entropy from UUID uint32_t w = LL_GetUID_Word0();
uint32_t w = LL_GetUID_Word0(); memcpy(HW_ENTROPY_DATA, &w, 4);
memcpy(HW_ENTROPY_DATA, &w, 4); w = LL_GetUID_Word1();
w = LL_GetUID_Word1(); memcpy(HW_ENTROPY_DATA + 4, &w, 4);
memcpy(HW_ENTROPY_DATA + 4, &w, 4); w = LL_GetUID_Word2();
w = LL_GetUID_Word2(); memcpy(HW_ENTROPY_DATA + 8, &w, 4);
memcpy(HW_ENTROPY_DATA + 8, &w, 4);
// set entropy in the OTP randomness block
// set entropy in the OTP randomness block if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { uint8_t entropy[FLASH_OTP_BLOCK_SIZE];
uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; random_buffer(entropy, FLASH_OTP_BLOCK_SIZE);
random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy,
ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE), NULL); FLASH_OTP_BLOCK_SIZE),
ensure(flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS), NULL); NULL);
} ensure(flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS), NULL);
// collect entropy from OTP randomness block }
ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, FLASH_OTP_BLOCK_SIZE), NULL); // collect entropy from OTP randomness block
ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12,
FLASH_OTP_BLOCK_SIZE),
NULL);
} }

@ -27,19 +27,41 @@
#define STR(s) #s #define STR(s) #s
#ifndef MIN_8bits #ifndef MIN_8bits
#define MIN_8bits(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? (_a & 0xFF) : (_b & 0xFF); }) #define MIN_8bits(a, b) \
({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a < _b ? (_a & 0xFF) : (_b & 0xFF); \
})
#endif #endif
#ifndef MIN #ifndef MIN
#define MIN(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; \
})
#endif #endif
#ifndef MAX #ifndef MAX
#define MAX(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; \
})
#endif #endif
void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn))
void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); __fatal_error(const char *expr, const char *msg, const char *file, int line,
const char *func);
void __attribute__((noreturn))
error_shutdown(const char *line1, const char *line2, const char *line3,
const char *line4);
#define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) #define ensure(expr, msg) \
(((expr) == sectrue) \
? (void)0 \
: __fatal_error(#expr, msg, __FILE__, __LINE__, __func__))
void hal_delay(uint32_t ms); void hal_delay(uint32_t ms);

@ -27,34 +27,34 @@
// see docs/memory.md for more information // see docs/memory.md for more information
static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = {
[ 0] = 0x08000000, // - 0x08003FFF | 16 KiB [0] = 0x08000000, // - 0x08003FFF | 16 KiB
[ 1] = 0x08004000, // - 0x08007FFF | 16 KiB [1] = 0x08004000, // - 0x08007FFF | 16 KiB
[ 2] = 0x08008000, // - 0x0800BFFF | 16 KiB [2] = 0x08008000, // - 0x0800BFFF | 16 KiB
[ 3] = 0x0800C000, // - 0x0800FFFF | 16 KiB [3] = 0x0800C000, // - 0x0800FFFF | 16 KiB
[ 4] = 0x08010000, // - 0x0801FFFF | 64 KiB [4] = 0x08010000, // - 0x0801FFFF | 64 KiB
[ 5] = 0x08020000, // - 0x0803FFFF | 128 KiB [5] = 0x08020000, // - 0x0803FFFF | 128 KiB
[ 6] = 0x08040000, // - 0x0805FFFF | 128 KiB [6] = 0x08040000, // - 0x0805FFFF | 128 KiB
[ 7] = 0x08060000, // - 0x0807FFFF | 128 KiB [7] = 0x08060000, // - 0x0807FFFF | 128 KiB
[ 8] = 0x08080000, // - 0x0809FFFF | 128 KiB [8] = 0x08080000, // - 0x0809FFFF | 128 KiB
[ 9] = 0x080A0000, // - 0x080BFFFF | 128 KiB [9] = 0x080A0000, // - 0x080BFFFF | 128 KiB
[10] = 0x080C0000, // - 0x080DFFFF | 128 KiB [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB
[11] = 0x080E0000, // - 0x080FFFFF | 128 KiB [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB
[12] = 0x08100000, // - 0x08103FFF | 16 KiB [12] = 0x08100000, // - 0x08103FFF | 16 KiB
[13] = 0x08104000, // - 0x08107FFF | 16 KiB [13] = 0x08104000, // - 0x08107FFF | 16 KiB
[14] = 0x08108000, // - 0x0810BFFF | 16 KiB [14] = 0x08108000, // - 0x0810BFFF | 16 KiB
[15] = 0x0810C000, // - 0x0810FFFF | 16 KiB [15] = 0x0810C000, // - 0x0810FFFF | 16 KiB
[16] = 0x08110000, // - 0x0811FFFF | 64 KiB [16] = 0x08110000, // - 0x0811FFFF | 64 KiB
[17] = 0x08120000, // - 0x0813FFFF | 128 KiB [17] = 0x08120000, // - 0x0813FFFF | 128 KiB
[18] = 0x08140000, // - 0x0815FFFF | 128 KiB [18] = 0x08140000, // - 0x0815FFFF | 128 KiB
[19] = 0x08160000, // - 0x0817FFFF | 128 KiB [19] = 0x08160000, // - 0x0817FFFF | 128 KiB
[20] = 0x08180000, // - 0x0819FFFF | 128 KiB [20] = 0x08180000, // - 0x0819FFFF | 128 KiB
[21] = 0x081A0000, // - 0x081BFFFF | 128 KiB [21] = 0x081A0000, // - 0x081BFFFF | 128 KiB
[22] = 0x081C0000, // - 0x081DFFFF | 128 KiB [22] = 0x081C0000, // - 0x081DFFFF | 128 KiB
[23] = 0x081E0000, // - 0x081FFFFF | 128 KiB [23] = 0x081E0000, // - 0x081FFFFF | 128 KiB
[24] = 0x08200000, // last element - not a valid sector [24] = 0x08200000, // last element - not a valid sector
}; };
const uint8_t FIRMWARE_SECTORS [FIRMWARE_SECTORS_COUNT] = { const uint8_t FIRMWARE_SECTORS[FIRMWARE_SECTORS_COUNT] = {
FLASH_SECTOR_FIRMWARE_START, FLASH_SECTOR_FIRMWARE_START,
7, 7,
8, 8,
@ -75,147 +75,146 @@ const uint8_t STORAGE_SECTORS[STORAGE_SECTORS_COUNT] = {
FLASH_SECTOR_STORAGE_2, FLASH_SECTOR_STORAGE_2,
}; };
void flash_init(void) void flash_init(void) {}
{
}
secbool flash_unlock_write(void) secbool flash_unlock_write(void) {
{ HAL_FLASH_Unlock();
HAL_FLASH_Unlock(); FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags return sectrue;
return sectrue;
} }
secbool flash_lock_write(void) secbool flash_lock_write(void) {
{ HAL_FLASH_Lock();
HAL_FLASH_Lock(); return sectrue;
return sectrue;
} }
const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) {
{ if (sector >= FLASH_SECTOR_COUNT) {
if (sector >= FLASH_SECTOR_COUNT) { return NULL;
return NULL; }
} const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset;
const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset; const uint32_t next = FLASH_SECTOR_TABLE[sector + 1];
const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; if (addr + size > next) {
if (addr + size > next) { return NULL;
return NULL; }
} return (const void *)addr;
return (const void *)addr;
} }
secbool flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(int pos, int len)) secbool flash_erase_sectors(const uint8_t *sectors, int len,
{ void (*progress)(int pos, int len)) {
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
FLASH_EraseInitTypeDef EraseInitStruct; FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.NbSectors = 1; EraseInitStruct.NbSectors = 1;
if (progress) { if (progress) {
progress(0, len); progress(0, len);
} }
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
EraseInitStruct.Sector = sectors[i]; EraseInitStruct.Sector = sectors[i];
uint32_t SectorError; uint32_t SectorError;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return secfalse; return secfalse;
} }
// check whether the sector was really deleted (contains only 0xFF) // check whether the sector was really deleted (contains only 0xFF)
const uint32_t addr_start = FLASH_SECTOR_TABLE[sectors[i]], addr_end = FLASH_SECTOR_TABLE[sectors[i] + 1]; const uint32_t addr_start = FLASH_SECTOR_TABLE[sectors[i]],
for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { addr_end = FLASH_SECTOR_TABLE[sectors[i] + 1];
if (*((const uint32_t *)addr) != 0xFFFFFFFF) { for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
ensure(flash_lock_write(), NULL); if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
return secfalse; ensure(flash_lock_write(), NULL);
}
}
if (progress) {
progress(i + 1, len);
}
}
ensure(flash_lock_write(), NULL);
return sectrue;
}
secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data)
{
uint32_t address = (uint32_t)flash_get_address(sector, offset, 1);
if (address == 0) {
return secfalse; return secfalse;
}
} }
if (data != (data & *((const uint8_t *)address))) { if (progress) {
return secfalse; progress(i + 1, len);
}
if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data)) {
return secfalse;
}
if (data != *((const uint8_t *)address)) {
return secfalse;
} }
return sectrue; }
ensure(flash_lock_write(), NULL);
return sectrue;
} }
secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) {
{ uint32_t address = (uint32_t)flash_get_address(sector, offset, 1);
uint32_t address = (uint32_t)flash_get_address(sector, offset, 4); if (address == 0) {
if (address == 0) { return secfalse;
return secfalse; }
} if (data != (data & *((const uint8_t *)address))) {
if (offset % sizeof(uint32_t)) { // we write only at 4-byte boundary return secfalse;
return secfalse; }
} if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data)) {
if (data != (data & *((const uint32_t *)address))) { return secfalse;
return secfalse; }
} if (data != *((const uint8_t *)address)) {
if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data)) { return secfalse;
return secfalse; }
} return sectrue;
if (data != *((const uint32_t *)address)) {
return secfalse;
}
return sectrue;
} }
#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) {
uint32_t address = (uint32_t)flash_get_address(sector, offset, 4);
if (address == 0) {
return secfalse;
}
if (offset % sizeof(uint32_t)) { // we write only at 4-byte boundary
return secfalse;
}
if (data != (data & *((const uint32_t *)address))) {
return secfalse;
}
if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data)) {
return secfalse;
}
if (data != *((const uint32_t *)address)) {
return secfalse;
}
return sectrue;
}
secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen) #define FLASH_OTP_LOCK_BASE 0x1FFF7A00U
{
if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
return secfalse; uint8_t datalen) {
} if (block >= FLASH_OTP_NUM_BLOCKS ||
for (uint8_t i = 0; i < datalen; i++) { offset + datalen > FLASH_OTP_BLOCK_SIZE) {
data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); return secfalse;
} }
return sectrue; for (uint8_t i = 0; i < datalen; i++) {
data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
offset + i);
}
return sectrue;
} }
secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen) secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
{ uint8_t datalen) {
if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { if (block >= FLASH_OTP_NUM_BLOCKS ||
return secfalse; offset + datalen > FLASH_OTP_BLOCK_SIZE) {
} return secfalse;
ensure(flash_unlock_write(), NULL); }
for (uint8_t i = 0; i < datalen; i++) { ensure(flash_unlock_write(), NULL);
uint32_t address = FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; for (uint8_t i = 0; i < datalen; i++) {
ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data[i])), NULL); uint32_t address =
} FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
ensure(flash_lock_write(), NULL); ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
return sectrue; address, data[i])),
NULL);
}
ensure(flash_lock_write(), NULL);
return sectrue;
} }
secbool flash_otp_lock(uint8_t block) secbool flash_otp_lock(uint8_t block) {
{ if (block >= FLASH_OTP_NUM_BLOCKS) {
if (block >= FLASH_OTP_NUM_BLOCKS) { return secfalse;
return secfalse; }
} ensure(flash_unlock_write(), NULL);
ensure(flash_unlock_write(), NULL); HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, FLASH_OTP_LOCK_BASE + block, 0x00); FLASH_OTP_LOCK_BASE + block, 0x00);
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return sectrue * (ret == HAL_OK); return sectrue * (ret == HAL_OK);
} }
secbool flash_otp_is_locked(uint8_t block) secbool flash_otp_is_locked(uint8_t block) {
{ return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block));
return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block));
} }

@ -28,51 +28,54 @@
#define FLASH_SECTOR_COUNT 24 #define FLASH_SECTOR_COUNT 24
#define FLASH_SECTOR_BOARDLOADER_START 0 #define FLASH_SECTOR_BOARDLOADER_START 0
// 1 // 1
#define FLASH_SECTOR_BOARDLOADER_END 2 #define FLASH_SECTOR_BOARDLOADER_END 2
// 3 // 3
#define FLASH_SECTOR_STORAGE_1 4 #define FLASH_SECTOR_STORAGE_1 4
#define FLASH_SECTOR_BOOTLOADER 5 #define FLASH_SECTOR_BOOTLOADER 5
#define FLASH_SECTOR_FIRMWARE_START 6 #define FLASH_SECTOR_FIRMWARE_START 6
// 7 // 7
// 8 // 8
// 9 // 9
// 10 // 10
#define FLASH_SECTOR_FIRMWARE_END 11 #define FLASH_SECTOR_FIRMWARE_END 11
#define FLASH_SECTOR_UNUSED_START 12 #define FLASH_SECTOR_UNUSED_START 12
// 13 // 13
// 14 // 14
#define FLASH_SECTOR_UNUSED_END 15 #define FLASH_SECTOR_UNUSED_END 15
#define FLASH_SECTOR_STORAGE_2 16 #define FLASH_SECTOR_STORAGE_2 16
#define FLASH_SECTOR_FIRMWARE_EXTRA_START 17 #define FLASH_SECTOR_FIRMWARE_EXTRA_START 17
// 18 // 18
// 19 // 19
// 20 // 20
// 21 // 21
// 22 // 22
#define FLASH_SECTOR_FIRMWARE_EXTRA_END 23 #define FLASH_SECTOR_FIRMWARE_EXTRA_END 23
#define BOOTLOADER_SECTORS_COUNT (1) #define BOOTLOADER_SECTORS_COUNT (1)
#define STORAGE_SECTORS_COUNT (2) #define STORAGE_SECTORS_COUNT (2)
#define FIRMWARE_SECTORS_COUNT (6 + 7) #define FIRMWARE_SECTORS_COUNT (6 + 7)
extern const uint8_t STORAGE_SECTORS[STORAGE_SECTORS_COUNT]; extern const uint8_t STORAGE_SECTORS[STORAGE_SECTORS_COUNT];
extern const uint8_t FIRMWARE_SECTORS[FIRMWARE_SECTORS_COUNT]; extern const uint8_t FIRMWARE_SECTORS[FIRMWARE_SECTORS_COUNT];
// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) // note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427)
// (reference RM0090 section 3.7.5)
#ifndef STM32F427xx #ifndef STM32F427xx
#define FLASH_SR_RDERR 0 #define FLASH_SR_RDERR 0
#endif #endif
#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) #define FLASH_STATUS_ALL_FLAGS \
(FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \
FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP)
void flash_init(void); void flash_init(void);
@ -81,23 +84,28 @@ secbool __wur flash_lock_write(void);
const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size); const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size);
secbool __wur flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(int pos, int len)); secbool __wur flash_erase_sectors(const uint8_t *sectors, int len,
static inline secbool flash_erase(uint8_t sector) { return flash_erase_sectors(&sector, 1, NULL); } void (*progress)(int pos, int len));
static inline secbool flash_erase(uint8_t sector) {
return flash_erase_sectors(&sector, 1, NULL);
}
secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data);
secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data);
#define FLASH_OTP_NUM_BLOCKS 16 #define FLASH_OTP_NUM_BLOCKS 16
#define FLASH_OTP_BLOCK_SIZE 32 #define FLASH_OTP_BLOCK_SIZE 32
// OTP blocks allocation // OTP blocks allocation
#define FLASH_OTP_BLOCK_BATCH 0 #define FLASH_OTP_BLOCK_BATCH 0
#define FLASH_OTP_BLOCK_BOOTLOADER_VERSION 1 #define FLASH_OTP_BLOCK_BOOTLOADER_VERSION 1
#define FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK 2 #define FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK 2
#define FLASH_OTP_BLOCK_RANDOMNESS 3 #define FLASH_OTP_BLOCK_RANDOMNESS 3
secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen); secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
secbool __wur flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen); uint8_t datalen);
secbool __wur flash_otp_write(uint8_t block, uint8_t offset,
const uint8_t *data, uint8_t datalen);
secbool __wur flash_otp_lock(uint8_t block); secbool __wur flash_otp_lock(uint8_t block);
secbool __wur flash_otp_is_locked(uint8_t block); secbool __wur flash_otp_is_locked(uint8_t block);
#endif // TREZORHAL_FLASH_H #endif // TREZORHAL_FLASH_H

@ -26,180 +26,199 @@
#include "flash.h" #include "flash.h"
#include "image.h" #include "image.h"
static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n, const uint8_t * const *pub, uint8_t sigmask, ed25519_public_key res) static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n,
{ const uint8_t *const *pub, uint8_t sigmask,
if (0 == sig_m || 0 == sig_n) return secfalse; ed25519_public_key res) {
if (sig_m > sig_n) return secfalse; if (0 == sig_m || 0 == sig_n) return secfalse;
if (sig_m > sig_n) return secfalse;
// discard bits higher than sig_n
sigmask &= ((1 << sig_n) - 1); // discard bits higher than sig_n
sigmask &= ((1 << sig_n) - 1);
// remove if number of set bits in sigmask is not equal to sig_m
if (__builtin_popcount(sigmask) != sig_m) return secfalse; // remove if number of set bits in sigmask is not equal to sig_m
if (__builtin_popcount(sigmask) != sig_m) return secfalse;
ed25519_public_key keys[sig_m];
int j = 0; ed25519_public_key keys[sig_m];
for (int i = 0; i < sig_n; i++) { int j = 0;
if ((1 << i) & sigmask) { for (int i = 0; i < sig_n; i++) {
memcpy(keys[j], pub[i], 32); if ((1 << i) & sigmask) {
j++; memcpy(keys[j], pub[i], 32);
} j++;
} }
}
return sectrue * (0 == ed25519_cosi_combine_publickeys(res, keys, sig_m)); return sectrue * (0 == ed25519_cosi_combine_publickeys(res, keys, sig_m));
} }
secbool load_image_header(const uint8_t * const data, const uint32_t magic, const uint32_t maxsize, uint8_t key_m, uint8_t key_n, const uint8_t * const *keys, image_header * const hdr) secbool load_image_header(const uint8_t *const data, const uint32_t magic,
{ const uint32_t maxsize, uint8_t key_m, uint8_t key_n,
memcpy(&hdr->magic, data, 4); const uint8_t *const *keys, image_header *const hdr) {
if (hdr->magic != magic) return secfalse; memcpy(&hdr->magic, data, 4);
if (hdr->magic != magic) return secfalse;
memcpy(&hdr->hdrlen, data + 4, 4); memcpy(&hdr->hdrlen, data + 4, 4);
if (hdr->hdrlen != IMAGE_HEADER_SIZE) return secfalse; if (hdr->hdrlen != IMAGE_HEADER_SIZE) return secfalse;
memcpy(&hdr->expiry, data + 8, 4); memcpy(&hdr->expiry, data + 8, 4);
// TODO: expiry mechanism needs to be ironed out before production or those // TODO: expiry mechanism needs to be ironed out before production or those
// devices won't accept expiring bootloaders (due to boardloader write protection). // devices won't accept expiring bootloaders (due to boardloader write
if (hdr->expiry != 0) return secfalse; // protection).
if (hdr->expiry != 0) return secfalse;
memcpy(&hdr->codelen, data + 12, 4); memcpy(&hdr->codelen, data + 12, 4);
if (hdr->codelen > (maxsize - hdr->hdrlen)) return secfalse; if (hdr->codelen > (maxsize - hdr->hdrlen)) return secfalse;
if ((hdr->hdrlen + hdr->codelen) < 4 * 1024) return secfalse; if ((hdr->hdrlen + hdr->codelen) < 4 * 1024) return secfalse;
if ((hdr->hdrlen + hdr->codelen) % 512 != 0) return secfalse; if ((hdr->hdrlen + hdr->codelen) % 512 != 0) return secfalse;
memcpy(&hdr->version, data + 16, 4); memcpy(&hdr->version, data + 16, 4);
memcpy(&hdr->fix_version, data + 20, 4); memcpy(&hdr->fix_version, data + 20, 4);
memcpy(hdr->hashes, data + 32, 512); memcpy(hdr->hashes, data + 32, 512);
memcpy(&hdr->sigmask, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE, 1); memcpy(&hdr->sigmask, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE, 1);
memcpy(hdr->sig, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE + 1, IMAGE_SIG_SIZE - 1); memcpy(hdr->sig, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE + 1,
IMAGE_SIG_SIZE - 1);
// check header signature // check header signature
BLAKE2S_CTX ctx; BLAKE2S_CTX ctx;
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
blake2s_Update(&ctx, data, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE); blake2s_Update(&ctx, data, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE);
for (int i = 0; i < IMAGE_SIG_SIZE; i++) { for (int i = 0; i < IMAGE_SIG_SIZE; i++) {
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
} }
blake2s_Final(&ctx, hdr->fingerprint, BLAKE2S_DIGEST_LENGTH); blake2s_Final(&ctx, hdr->fingerprint, BLAKE2S_DIGEST_LENGTH);
ed25519_public_key pub; ed25519_public_key pub;
if (sectrue != compute_pubkey(key_m, key_n, keys, hdr->sigmask, pub)) return secfalse; if (sectrue != compute_pubkey(key_m, key_n, keys, hdr->sigmask, pub))
return secfalse;
return sectrue * (0 == ed25519_sign_open(hdr->fingerprint, BLAKE2S_DIGEST_LENGTH, pub, *(const ed25519_signature *)hdr->sig)); return sectrue *
(0 == ed25519_sign_open(hdr->fingerprint, BLAKE2S_DIGEST_LENGTH, pub,
*(const ed25519_signature *)hdr->sig));
} }
secbool load_vendor_header(const uint8_t * const data, uint8_t key_m, uint8_t key_n, const uint8_t * const *keys, vendor_header * const vhdr) secbool load_vendor_header(const uint8_t *const data, uint8_t key_m,
{ uint8_t key_n, const uint8_t *const *keys,
memcpy(&vhdr->magic, data, 4); vendor_header *const vhdr) {
if (vhdr->magic != 0x565A5254) return secfalse; // TRZV memcpy(&vhdr->magic, data, 4);
if (vhdr->magic != 0x565A5254) return secfalse; // TRZV
memcpy(&vhdr->hdrlen, data + 4, 4); memcpy(&vhdr->hdrlen, data + 4, 4);
if (vhdr->hdrlen > 64 * 1024) return secfalse; if (vhdr->hdrlen > 64 * 1024) return secfalse;
memcpy(&vhdr->expiry, data + 8, 4); memcpy(&vhdr->expiry, data + 8, 4);
if (vhdr->expiry != 0) return secfalse; if (vhdr->expiry != 0) return secfalse;
memcpy(&vhdr->version, data + 12, 2); memcpy(&vhdr->version, data + 12, 2);
memcpy(&vhdr->vsig_m, data + 14, 1); memcpy(&vhdr->vsig_m, data + 14, 1);
memcpy(&vhdr->vsig_n, data + 15, 1); memcpy(&vhdr->vsig_n, data + 15, 1);
memcpy(&vhdr->vtrust, data + 16, 2); memcpy(&vhdr->vtrust, data + 16, 2);
if (vhdr->vsig_n > MAX_VENDOR_PUBLIC_KEYS) { if (vhdr->vsig_n > MAX_VENDOR_PUBLIC_KEYS) {
return secfalse; return secfalse;
} }
for (int i = 0; i < vhdr->vsig_n; i++) { for (int i = 0; i < vhdr->vsig_n; i++) {
vhdr->vpub[i] = data + 32 + i * 32; vhdr->vpub[i] = data + 32 + i * 32;
} }
for (int i = vhdr->vsig_n; i < MAX_VENDOR_PUBLIC_KEYS; i++) { for (int i = vhdr->vsig_n; i < MAX_VENDOR_PUBLIC_KEYS; i++) {
vhdr->vpub[i] = 0; vhdr->vpub[i] = 0;
} }
memcpy(&vhdr->vstr_len, data + 32 + vhdr->vsig_n * 32, 1); memcpy(&vhdr->vstr_len, data + 32 + vhdr->vsig_n * 32, 1);
vhdr->vstr = (const char *)(data + 32 + vhdr->vsig_n * 32 + 1); vhdr->vstr = (const char *)(data + 32 + vhdr->vsig_n * 32 + 1);
vhdr->vimg = data + 32 + vhdr->vsig_n * 32 + 1 + vhdr->vstr_len; vhdr->vimg = data + 32 + vhdr->vsig_n * 32 + 1 + vhdr->vstr_len;
// align to 4 bytes // align to 4 bytes
vhdr->vimg += (-(uintptr_t)vhdr->vimg) & 3; vhdr->vimg += (-(uintptr_t)vhdr->vimg) & 3;
memcpy(&vhdr->sigmask, data + vhdr->hdrlen - IMAGE_SIG_SIZE, 1); memcpy(&vhdr->sigmask, data + vhdr->hdrlen - IMAGE_SIG_SIZE, 1);
memcpy(vhdr->sig, data + vhdr->hdrlen - IMAGE_SIG_SIZE + 1, IMAGE_SIG_SIZE - 1); memcpy(vhdr->sig, data + vhdr->hdrlen - IMAGE_SIG_SIZE + 1,
IMAGE_SIG_SIZE - 1);
// check header signature // check header signature
uint8_t hash[BLAKE2S_DIGEST_LENGTH]; uint8_t hash[BLAKE2S_DIGEST_LENGTH];
BLAKE2S_CTX ctx; BLAKE2S_CTX ctx;
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
blake2s_Update(&ctx, data, vhdr->hdrlen - IMAGE_SIG_SIZE); blake2s_Update(&ctx, data, vhdr->hdrlen - IMAGE_SIG_SIZE);
for (int i = 0; i < IMAGE_SIG_SIZE; i++) { for (int i = 0; i < IMAGE_SIG_SIZE; i++) {
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
} }
blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH);
ed25519_public_key pub; ed25519_public_key pub;
if (sectrue != compute_pubkey(key_m, key_n, keys, vhdr->sigmask, pub)) return secfalse; if (sectrue != compute_pubkey(key_m, key_n, keys, vhdr->sigmask, pub))
return secfalse;
return sectrue * (0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, pub, *(const ed25519_signature *)vhdr->sig)); return sectrue *
(0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, pub,
*(const ed25519_signature *)vhdr->sig));
} }
void vendor_keys_hash(const vendor_header * const vhdr, uint8_t *hash) void vendor_keys_hash(const vendor_header *const vhdr, uint8_t *hash) {
{ BLAKE2S_CTX ctx;
BLAKE2S_CTX ctx; blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); blake2s_Update(&ctx, &(vhdr->vsig_m), sizeof(vhdr->vsig_m));
blake2s_Update(&ctx, &(vhdr->vsig_m), sizeof(vhdr->vsig_m)); blake2s_Update(&ctx, &(vhdr->vsig_n), sizeof(vhdr->vsig_n));
blake2s_Update(&ctx, &(vhdr->vsig_n), sizeof(vhdr->vsig_n)); for (int i = 0; i < MAX_VENDOR_PUBLIC_KEYS; i++) {
for (int i = 0; i < MAX_VENDOR_PUBLIC_KEYS; i++) { if (vhdr->vpub[i] != 0) {
if (vhdr->vpub[i] != 0) { blake2s_Update(&ctx, vhdr->vpub[i], 32);
blake2s_Update(&ctx, vhdr->vpub[i], 32); } else {
} else { blake2s_Update(
blake2s_Update(&ctx, "\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); &ctx,
} "\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);
} }
blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); }
blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH);
} }
secbool check_single_hash(const uint8_t * const hash, const uint8_t * const data, int len) secbool check_single_hash(const uint8_t *const hash, const uint8_t *const data,
{ int len) {
uint8_t h[BLAKE2S_DIGEST_LENGTH]; uint8_t h[BLAKE2S_DIGEST_LENGTH];
blake2s(data, len, h, BLAKE2S_DIGEST_LENGTH); blake2s(data, len, h, BLAKE2S_DIGEST_LENGTH);
return sectrue * (0 == memcmp(h, hash, BLAKE2S_DIGEST_LENGTH)); return sectrue * (0 == memcmp(h, hash, BLAKE2S_DIGEST_LENGTH));
} }
secbool check_image_contents(const image_header * const hdr, uint32_t firstskip, const uint8_t *sectors, int blocks) secbool check_image_contents(const image_header *const hdr, uint32_t firstskip,
{ const uint8_t *sectors, int blocks) {
if (0 == sectors || blocks < 1) { if (0 == sectors || blocks < 1) {
return secfalse; return secfalse;
}
const void *data =
flash_get_address(sectors[0], firstskip, IMAGE_CHUNK_SIZE - firstskip);
if (!data) {
return secfalse;
}
int remaining = hdr->codelen;
if (sectrue !=
check_single_hash(hdr->hashes, data,
MIN(remaining, IMAGE_CHUNK_SIZE - firstskip))) {
return secfalse;
}
int block = 1;
remaining -= IMAGE_CHUNK_SIZE - firstskip;
while (remaining > 0) {
if (block >= blocks) {
return secfalse;
} }
const void *data = flash_get_address(sectors[0], firstskip, IMAGE_CHUNK_SIZE - firstskip); data = flash_get_address(sectors[block], 0, IMAGE_CHUNK_SIZE);
if (!data) { if (!data) {
return secfalse; return secfalse;
}
int remaining = hdr->codelen;
if (sectrue != check_single_hash(hdr->hashes, data, MIN(remaining, IMAGE_CHUNK_SIZE - firstskip))) {
return secfalse;
} }
int block = 1; if (sectrue != check_single_hash(hdr->hashes + block * 32, data,
remaining -= IMAGE_CHUNK_SIZE - firstskip; MIN(remaining, IMAGE_CHUNK_SIZE))) {
while (remaining > 0) { return secfalse;
if (block >= blocks) {
return secfalse;
}
data = flash_get_address(sectors[block], 0, IMAGE_CHUNK_SIZE);
if (!data) {
return secfalse;
}
if (sectrue != check_single_hash(hdr->hashes + block * 32, data, MIN(remaining, IMAGE_CHUNK_SIZE))) {
return secfalse;
}
block++;
remaining -= IMAGE_CHUNK_SIZE;
} }
return sectrue; block++;
remaining -= IMAGE_CHUNK_SIZE;
}
return sectrue;
} }

@ -23,68 +23,76 @@
#include <stdint.h> #include <stdint.h>
#include "secbool.h" #include "secbool.h"
#define BOARDLOADER_START 0x08000000 #define BOARDLOADER_START 0x08000000
#define BOOTLOADER_START 0x08020000 #define BOOTLOADER_START 0x08020000
#define FIRMWARE_START 0x08040000 #define FIRMWARE_START 0x08040000
#define IMAGE_HEADER_SIZE 0x400 #define IMAGE_HEADER_SIZE 0x400
#define IMAGE_SIG_SIZE 65 #define IMAGE_SIG_SIZE 65
#define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_CHUNK_SIZE (128 * 1024)
#define BOOTLOADER_IMAGE_MAGIC 0x425A5254 // TRZB #define BOOTLOADER_IMAGE_MAGIC 0x425A5254 // TRZB
#define BOOTLOADER_IMAGE_MAXSIZE (BOOTLOADER_SECTORS_COUNT * IMAGE_CHUNK_SIZE) #define BOOTLOADER_IMAGE_MAXSIZE (BOOTLOADER_SECTORS_COUNT * IMAGE_CHUNK_SIZE)
#define FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF #define FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF
#define FIRMWARE_IMAGE_MAXSIZE (FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE) #define FIRMWARE_IMAGE_MAXSIZE (FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE)
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint32_t hdrlen; uint32_t hdrlen;
uint32_t expiry; uint32_t expiry;
uint32_t codelen; uint32_t codelen;
uint32_t version; uint32_t version;
uint32_t fix_version; uint32_t fix_version;
// uint8_t reserved[8]; // uint8_t reserved[8];
uint8_t hashes[512]; uint8_t hashes[512];
// uint8_t reserved[415]; // uint8_t reserved[415];
uint8_t sigmask; uint8_t sigmask;
uint8_t sig[64]; uint8_t sig[64];
uint8_t fingerprint[32]; uint8_t fingerprint[32];
} image_header; } image_header;
#define MAX_VENDOR_PUBLIC_KEYS 8 #define MAX_VENDOR_PUBLIC_KEYS 8
#define VTRUST_WAIT 0x000F #define VTRUST_WAIT 0x000F
#define VTRUST_RED 0x0010 #define VTRUST_RED 0x0010
#define VTRUST_CLICK 0x0020 #define VTRUST_CLICK 0x0020
#define VTRUST_STRING 0x0040 #define VTRUST_STRING 0x0040
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING) #define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint32_t hdrlen; uint32_t hdrlen;
uint32_t expiry; uint32_t expiry;
uint16_t version; uint16_t version;
uint8_t vsig_m; uint8_t vsig_m;
uint8_t vsig_n; uint8_t vsig_n;
uint16_t vtrust; uint16_t vtrust;
// uint8_t reserved[14]; // uint8_t reserved[14];
const uint8_t *vpub[MAX_VENDOR_PUBLIC_KEYS]; const uint8_t *vpub[MAX_VENDOR_PUBLIC_KEYS];
uint8_t vstr_len; uint8_t vstr_len;
const char *vstr; const char *vstr;
const uint8_t *vimg; const uint8_t *vimg;
uint8_t sigmask; uint8_t sigmask;
uint8_t sig[64]; uint8_t sig[64];
} vendor_header; } vendor_header;
secbool __wur load_image_header(const uint8_t * const data, const uint32_t magic, const uint32_t maxsize, uint8_t key_m, uint8_t key_n, const uint8_t * const *keys, image_header * const hdr); secbool __wur load_image_header(const uint8_t *const data, const uint32_t magic,
const uint32_t maxsize, uint8_t key_m,
uint8_t key_n, const uint8_t *const *keys,
image_header *const hdr);
secbool __wur load_vendor_header(const uint8_t * const data, uint8_t key_m, uint8_t key_n, const uint8_t * const *keys, vendor_header * const vhdr); secbool __wur load_vendor_header(const uint8_t *const data, uint8_t key_m,
uint8_t key_n, const uint8_t *const *keys,
vendor_header *const vhdr);
void vendor_keys_hash(const vendor_header * const vhdr, uint8_t *hash); void vendor_keys_hash(const vendor_header *const vhdr, uint8_t *hash);
secbool __wur check_single_hash(const uint8_t * const hash, const uint8_t * const data, int len); secbool __wur check_single_hash(const uint8_t *const hash,
const uint8_t *const data, int len);
secbool __wur check_image_contents(const image_header * const hdr, uint32_t firstskip, const uint8_t *sectors, int blocks); secbool __wur check_image_contents(const image_header *const hdr,
uint32_t firstskip, const uint8_t *sectors,
int blocks);
#endif #endif

@ -19,151 +19,165 @@
#include STM32_HAL_H #include STM32_HAL_H
#include "flash.h"
#include "lowlevel.h" #include "lowlevel.h"
#include "flash.h"
#pragma GCC optimize("no-stack-protector") // applies to all functions in this file #pragma GCC optimize( \
"no-stack-protector") // applies to all functions in this file
#if PRODUCTION #if PRODUCTION
#define WANT_RDP_LEVEL (OB_RDP_LEVEL_2) #define WANT_RDP_LEVEL (OB_RDP_LEVEL_2)
#define WANT_WRP_SECTORS (OB_WRP_SECTOR_0 | OB_WRP_SECTOR_1 | OB_WRP_SECTOR_2) #define WANT_WRP_SECTORS (OB_WRP_SECTOR_0 | OB_WRP_SECTOR_1 | OB_WRP_SECTOR_2)
#else #else
#define WANT_RDP_LEVEL (OB_RDP_LEVEL_0) #define WANT_RDP_LEVEL (OB_RDP_LEVEL_0)
#define WANT_WRP_SECTORS (0) #define WANT_WRP_SECTORS (0)
#endif #endif
// BOR LEVEL 3: Reset level threshold is around 2.5 V // BOR LEVEL 3: Reset level threshold is around 2.5 V
#define WANT_BOR_LEVEL (OB_BOR_LEVEL3) #define WANT_BOR_LEVEL (OB_BOR_LEVEL3)
// reference RM0090 section 3.9.10; SPRMOD is 0 meaning PCROP disabled.; DB1M is 0 because we use 2MB dual-bank; BFB2 is 0 allowing boot from flash; // reference RM0090 section 3.9.10; SPRMOD is 0 meaning PCROP disabled.; DB1M is
#define FLASH_OPTCR_VALUE ( (((~WANT_WRP_SECTORS) << FLASH_OPTCR_nWRP_Pos) & FLASH_OPTCR_nWRP_Msk) | \ // 0 because we use 2MB dual-bank; BFB2 is 0 allowing boot from flash;
(WANT_RDP_LEVEL << FLASH_OPTCR_RDP_Pos) | FLASH_OPTCR_nRST_STDBY | FLASH_OPTCR_nRST_STOP | FLASH_OPTCR_WDG_SW | WANT_BOR_LEVEL ) #define FLASH_OPTCR_VALUE \
((((~WANT_WRP_SECTORS) << FLASH_OPTCR_nWRP_Pos) & FLASH_OPTCR_nWRP_Msk) | \
(WANT_RDP_LEVEL << FLASH_OPTCR_RDP_Pos) | FLASH_OPTCR_nRST_STDBY | \
FLASH_OPTCR_nRST_STOP | FLASH_OPTCR_WDG_SW | WANT_BOR_LEVEL)
// reference RM0090 section 3.7.1 table 16 // reference RM0090 section 3.7.1 table 16
#define OPTION_BYTES_RDP_USER_VALUE ((uint16_t) ((WANT_RDP_LEVEL << FLASH_OPTCR_RDP_Pos) | FLASH_OPTCR_nRST_STDBY | FLASH_OPTCR_nRST_STOP | FLASH_OPTCR_WDG_SW | WANT_BOR_LEVEL)) #define OPTION_BYTES_RDP_USER_VALUE \
#define OPTION_BYTES_BANK1_WRP_VALUE ((uint16_t) ((~WANT_WRP_SECTORS) & 0xFFFU)) ((uint16_t)((WANT_RDP_LEVEL << FLASH_OPTCR_RDP_Pos) | \
#define OPTION_BYTES_BANK2_WRP_VALUE ((uint16_t) 0xFFFU) FLASH_OPTCR_nRST_STDBY | FLASH_OPTCR_nRST_STOP | \
FLASH_OPTCR_WDG_SW | WANT_BOR_LEVEL))
// reference RM0090 section 3.7.1 table 16. use 16 bit pointers because the top 48 bits are all reserved. #define OPTION_BYTES_BANK1_WRP_VALUE ((uint16_t)((~WANT_WRP_SECTORS) & 0xFFFU))
#define OPTION_BYTES_RDP_USER (*(volatile uint16_t * const) 0x1FFFC000U) #define OPTION_BYTES_BANK2_WRP_VALUE ((uint16_t)0xFFFU)
#define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t * const) 0x1FFFC008U)
#define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t * const) 0x1FFEC008U) // reference RM0090 section 3.7.1 table 16. use 16 bit pointers because the top
// 48 bits are all reserved.
uint32_t flash_wait_and_clear_status_flags(void) #define OPTION_BYTES_RDP_USER (*(volatile uint16_t* const)0x1FFFC000U)
{ #define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t* const)0x1FFFC008U)
while(FLASH->SR & FLASH_SR_BSY); // wait for all previous flash operations to complete #define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t* const)0x1FFEC008U)
const uint32_t result = FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags uint32_t flash_wait_and_clear_status_flags(void) {
return result; while (FLASH->SR & FLASH_SR_BSY)
; // wait for all previous flash operations to complete
const uint32_t result =
FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags
FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags
return result;
} }
secbool flash_check_option_bytes(void) secbool flash_check_option_bytes(void) {
{ flash_wait_and_clear_status_flags();
flash_wait_and_clear_status_flags(); // check values stored in flash interface registers
// check values stored in flash interface registers if ((FLASH->OPTCR & ~3) !=
if ((FLASH->OPTCR & ~3) != FLASH_OPTCR_VALUE) { // ignore bits 0 and 1 because they are control bits FLASH_OPTCR_VALUE) { // ignore bits 0 and 1 because they are control bits
return secfalse; return secfalse;
} }
if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) { if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) {
return secfalse; return secfalse;
} }
// check values stored in flash memory // check values stored in flash memory
if ((OPTION_BYTES_RDP_USER & ~3) != OPTION_BYTES_RDP_USER_VALUE) { // bits 0 and 1 are unused if ((OPTION_BYTES_RDP_USER & ~3) !=
return secfalse; OPTION_BYTES_RDP_USER_VALUE) { // bits 0 and 1 are unused
} return secfalse;
if ((OPTION_BYTES_BANK1_WRP & 0xCFFFU) != OPTION_BYTES_BANK1_WRP_VALUE) { // bits 12 and 13 are unused }
return secfalse; if ((OPTION_BYTES_BANK1_WRP & 0xCFFFU) !=
} OPTION_BYTES_BANK1_WRP_VALUE) { // bits 12 and 13 are unused
if ((OPTION_BYTES_BANK2_WRP & 0xFFFU) != OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused return secfalse;
return secfalse; }
} if ((OPTION_BYTES_BANK2_WRP & 0xFFFU) !=
return sectrue; OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused
return secfalse;
}
return sectrue;
} }
void flash_lock_option_bytes(void) void flash_lock_option_bytes(void) {
{ FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; // lock the option bytes
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; // lock the option bytes
} }
void flash_unlock_option_bytes(void) void flash_unlock_option_bytes(void) {
{ if ((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) == 0) {
if ((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) == 0) { return; // already unlocked
return; // already unlocked }
} // reference RM0090 section 3.7.2
// reference RM0090 section 3.7.2 // write the special sequence to unlock
// write the special sequence to unlock FLASH->OPTKEYR = FLASH_OPT_KEY1;
FLASH->OPTKEYR = FLASH_OPT_KEY1; FLASH->OPTKEYR = FLASH_OPT_KEY2;
FLASH->OPTKEYR = FLASH_OPT_KEY2; while (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK)
while (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK); // wait until the flash option control register is unlocked ; // wait until the flash option control register is unlocked
} }
uint32_t flash_set_option_bytes(void) uint32_t flash_set_option_bytes(void) {
{ // reference RM0090 section 3.7.2
// reference RM0090 section 3.7.2 flash_wait_and_clear_status_flags();
flash_wait_and_clear_status_flags(); flash_unlock_option_bytes();
flash_unlock_option_bytes(); flash_wait_and_clear_status_flags();
flash_wait_and_clear_status_flags(); FLASH->OPTCR1 =
FLASH->OPTCR1 = FLASH_OPTCR1_nWRP; // no write protection on any sectors in bank 2 FLASH_OPTCR1_nWRP; // no write protection on any sectors in bank 2
FLASH->OPTCR = FLASH_OPTCR_VALUE; // WARNING: dev board safe unless you compile for PRODUCTION or change this value!!! FLASH->OPTCR =
FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; // begin committing changes to flash FLASH_OPTCR_VALUE; // WARNING: dev board safe unless you compile for
const uint32_t result = flash_wait_and_clear_status_flags(); // wait until changes are committed // PRODUCTION or change this value!!!
flash_lock_option_bytes(); FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; // begin committing changes to flash
return result; const uint32_t result =
flash_wait_and_clear_status_flags(); // wait until changes are committed
flash_lock_option_bytes();
return result;
} }
secbool flash_configure_option_bytes(void) secbool flash_configure_option_bytes(void) {
{ if (sectrue == flash_check_option_bytes()) {
if (sectrue == flash_check_option_bytes()) { return sectrue; // we DID NOT have to change the option bytes
return sectrue; // we DID NOT have to change the option bytes }
}
do { do {
flash_set_option_bytes(); flash_set_option_bytes();
} while(sectrue != flash_check_option_bytes()); } while (sectrue != flash_check_option_bytes());
return secfalse; // notify that we DID have to change the option bytes return secfalse; // notify that we DID have to change the option bytes
} }
void periph_init(void) void periph_init(void) {
{ // STM32F4xx HAL library initialization:
// STM32F4xx HAL library initialization: // - configure the Flash prefetch, instruction and data caches
// - configure the Flash prefetch, instruction and data caches // - configure the Systick to generate an interrupt each 1 msec
// - configure the Systick to generate an interrupt each 1 msec // - set NVIC Group Priority to 4
// - set NVIC Group Priority to 4 // - global MSP (MCU Support Package) initialization
// - global MSP (MCU Support Package) initialization HAL_Init();
HAL_Init();
// Enable GPIO clocks
// Enable GPIO clocks __HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
// enable the PVD (programmable voltage detector).
// enable the PVD (programmable voltage detector). // select the "2.7V" threshold (level 5).
// select the "2.7V" threshold (level 5). // this detector will be active regardless of the
// this detector will be active regardless of the // flash option byte BOR setting.
// flash option byte BOR setting. __HAL_RCC_PWR_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE(); PWR_PVDTypeDef pvd_config;
PWR_PVDTypeDef pvd_config; pvd_config.PVDLevel = PWR_PVDLEVEL_5;
pvd_config.PVDLevel = PWR_PVDLEVEL_5; pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING; HAL_PWR_ConfigPVD(&pvd_config);
HAL_PWR_ConfigPVD(&pvd_config); HAL_PWR_EnablePVD();
HAL_PWR_EnablePVD(); NVIC_EnableIRQ(PVD_IRQn);
NVIC_EnableIRQ(PVD_IRQn);
} }
secbool reset_flags_check(void) secbool reset_flags_check(void) {
{
#if PRODUCTION #if PRODUCTION
// this is effective enough that it makes development painful, so only use it for production. // this is effective enough that it makes development painful, so only use it
// check the reset flags to assure that we arrive here due to a regular full power-on event, // for production. check the reset flags to assure that we arrive here due to
// and not as a result of a lesser reset. // a regular full power-on event, and not as a result of a lesser reset.
if ((RCC->CSR & (RCC_CSR_LPWRRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_IWDGRSTF | RCC_CSR_SFTRSTF | RCC_CSR_PORRSTF | RCC_CSR_PINRSTF | RCC_CSR_BORRSTF)) != (RCC_CSR_PORRSTF | RCC_CSR_PINRSTF | RCC_CSR_BORRSTF)) { if ((RCC->CSR & (RCC_CSR_LPWRRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_IWDGRSTF |
return secfalse; RCC_CSR_SFTRSTF | RCC_CSR_PORRSTF | RCC_CSR_PINRSTF |
} RCC_CSR_BORRSTF)) !=
(RCC_CSR_PORRSTF | RCC_CSR_PINRSTF | RCC_CSR_BORRSTF)) {
return secfalse;
}
#endif #endif
RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags
return sectrue; return sectrue;
} }

@ -31,4 +31,4 @@ secbool flash_configure_option_bytes(void);
void periph_init(void); void periph_init(void);
secbool reset_flags_check(void); secbool reset_flags_check(void);
#endif // __TREZORHAL_LOWLEVEL_H__ #endif // __TREZORHAL_LOWLEVEL_H__

@ -1,3 +1,5 @@
// clang-format off
/* /*
* The Minimal snprintf() implementation * The Minimal snprintf() implementation
* *

@ -1,3 +1,5 @@
// clang-format off
/* /*
* The Minimal snprintf() implementation * The Minimal snprintf() implementation
* *

@ -21,126 +21,151 @@
#include "stm32f4xx_ll_cortex.h" #include "stm32f4xx_ll_cortex.h"
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html
#define MPU_RASR_ATTR_FLASH (MPU_RASR_C_Msk) #define MPU_RASR_ATTR_FLASH (MPU_RASR_C_Msk)
#define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk) #define MPU_RASR_ATTR_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_Msk)
#define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk) #define MPU_RASR_ATTR_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk)
#define MPU_SUBREGION_DISABLE(X) ((X) << MPU_RASR_SRD_Pos) #define MPU_SUBREGION_DISABLE(X) ((X) << MPU_RASR_SRD_Pos)
void mpu_config_off(void) void mpu_config_off(void) {
{ // Disable MPU
// Disable MPU HAL_MPU_Disable();
HAL_MPU_Disable();
} }
void mpu_config_bootloader(void) void mpu_config_bootloader(void) {
{ // Disable MPU
// Disable MPU HAL_MPU_Disable();
HAL_MPU_Disable();
// Note: later entries overwrite previous ones
// Note: later entries overwrite previous ones
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) MPU->RNR = MPU_REGION_NUMBER0;
MPU->RNR = MPU_REGION_NUMBER0; MPU->RBAR = 0;
MPU->RBAR = 0; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS; LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS;
// Flash (0x0800C000 - 0x0800FFFF, 16 KiB, no access) // Flash (0x0800C000 - 0x0800FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER1; MPU->RNR = MPU_REGION_NUMBER1;
MPU->RBAR = FLASH_BASE + 0xC000; MPU->RBAR = FLASH_BASE + 0xC000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS;
// Flash (0x0810C000 - 0x0810FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER2; // Flash (0x0810C000 - 0x0810FFFF, 16 KiB, no access)
MPU->RBAR = FLASH_BASE + 0x10C000; MPU->RNR = MPU_REGION_NUMBER2;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS; MPU->RBAR = FLASH_BASE + 0x10C000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, read-write, execute never) LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS;
MPU->RNR = MPU_REGION_NUMBER3;
MPU->RBAR = SRAM_BASE; // SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end,
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); // read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER3;
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) MPU->RBAR = SRAM_BASE;
// External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
MPU->RNR = MPU_REGION_NUMBER4; LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS |
MPU->RBAR = PERIPH_BASE; MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0);
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk;
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never)
// External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER4;
MPU->RBAR = PERIPH_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH |
LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk;
#ifdef STM32F427xx #ifdef STM32F427xx
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER5; MPU->RNR = MPU_REGION_NUMBER5;
MPU->RBAR = CCMDATARAM_BASE; MPU->RBAR = CCMDATARAM_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk;
#elif STM32F405xx #elif STM32F405xx
// no CCMRAM // no CCMRAM
#else #else
#error Unsupported MCU #error Unsupported MCU
#endif #endif
// Enable MPU // Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
} }
void mpu_config_firmware(void) {
void mpu_config_firmware(void) // Disable MPU
{ HAL_MPU_Disable();
// Disable MPU
HAL_MPU_Disable(); // Note: later entries overwrite previous ones
// Note: later entries overwrite previous ones /*
// Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never)
/* MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0;
// Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never) MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0; LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | MPU_RASR_XN_Msk;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO | MPU_RASR_XN_Msk; */
*/
// Bootloader (0x08020000 - 0x0803FFFF, 64 KiB, read-only)
// Bootloader (0x08020000 - 0x0803FFFF, 64 KiB, read-only) MPU->RNR = MPU_REGION_NUMBER0;
MPU->RNR = MPU_REGION_NUMBER0; MPU->RBAR = FLASH_BASE + 0x20000;
MPU->RBAR = FLASH_BASE + 0x20000; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO; LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO;
// Storage#1 (0x08010000 - 0x0801FFFF, 64 KiB, read-write, execute never) // Storage#1 (0x08010000 - 0x0801FFFF, 64 KiB, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER1; MPU->RNR = MPU_REGION_NUMBER1;
MPU->RBAR = FLASH_BASE + 0x10000; MPU->RBAR = FLASH_BASE + 0x10000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
// Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never) LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
MPU->RNR = MPU_REGION_NUMBER2; MPU_RASR_XN_Msk;
MPU->RBAR = FLASH_BASE + 0x110000; // Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never)
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk; MPU->RNR = MPU_REGION_NUMBER2;
MPU->RBAR = FLASH_BASE + 0x110000;
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at start = 768 KiB, read-only) MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
MPU->RNR = MPU_REGION_NUMBER3; LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
MPU->RBAR = FLASH_BASE; MPU_RASR_XN_Msk;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO | MPU_SUBREGION_DISABLE(0x03);
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
// Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8 at start = 896 KiB, read-only) // start = 768 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER4; MPU->RNR = MPU_REGION_NUMBER3;
MPU->RBAR = FLASH_BASE + 0x100000; MPU->RBAR = FLASH_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO | MPU_SUBREGION_DISABLE(0x01); MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO |
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, read-write, execute never) MPU_SUBREGION_DISABLE(0x03);
MPU->RNR = MPU_REGION_NUMBER5;
MPU->RBAR = SRAM_BASE; // Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0); // at start = 896 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER4;
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) MPU->RBAR = FLASH_BASE + 0x100000;
// External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never) MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
MPU->RNR = MPU_REGION_NUMBER6; LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_PRIV_RO_URO |
MPU->RBAR = PERIPH_BASE; MPU_SUBREGION_DISABLE(0x01);
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH | LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk;
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end,
// read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER5;
MPU->RBAR = SRAM_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0);
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never)
// External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER6;
MPU->RBAR = PERIPH_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH |
LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk;
#ifdef STM32F427xx #ifdef STM32F427xx
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never) // CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER7; MPU->RNR = MPU_REGION_NUMBER7;
MPU->RBAR = CCMDATARAM_BASE; MPU->RBAR = CCMDATARAM_BASE;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk; MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk;
#elif STM32F405xx #elif STM32F405xx
// no CCMRAM // no CCMRAM
#else #else
#error Unsupported MCU #error Unsupported MCU
#endif #endif
// Enable MPU // Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
} }

@ -21,36 +21,38 @@
#include "rng.h" #include "rng.h"
#pragma GCC optimize("no-stack-protector") // applies to all functions in this file #pragma GCC optimize( \
"no-stack-protector") // applies to all functions in this file
void rng_init(void) void rng_init(void) {
{ // enable TRNG peripheral clock
// enable TRNG peripheral clock // use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet
// use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet // "Delay after an RCC peripheral clock enabling"
// "Delay after an RCC peripheral clock enabling" __HAL_RCC_RNG_CLK_ENABLE();
__HAL_RCC_RNG_CLK_ENABLE(); RNG->CR = RNG_CR_RNGEN; // enable TRNG
RNG->CR = RNG_CR_RNGEN; // enable TRNG
} }
uint32_t rng_read(const uint32_t previous, const uint32_t compare_previous) uint32_t rng_read(const uint32_t previous, const uint32_t compare_previous) {
{ uint32_t temp = previous;
uint32_t temp = previous; do {
do { while ((RNG->SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) != RNG_SR_DRDY)
while ((RNG->SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) != RNG_SR_DRDY); // wait until TRNG is ready ; // wait until TRNG is ready
temp = RNG->DR; // read the data from the TRNG temp = RNG->DR; // read the data from the TRNG
} while (compare_previous && (temp == previous)); // RM0090 section 24.3.1 FIPS continuous random number generator test } while (compare_previous &&
return temp; (temp == previous)); // RM0090 section 24.3.1 FIPS continuous random
// number generator test
return temp;
} }
uint32_t rng_get(void) uint32_t rng_get(void) {
{ // reason for keeping history: RM0090 section 24.3.1 FIPS continuous random
// reason for keeping history: RM0090 section 24.3.1 FIPS continuous random number generator test // number generator test
static uint32_t previous = 0, current = 0; static uint32_t previous = 0, current = 0;
if (previous == current) { if (previous == current) {
previous = rng_read(previous, 0); previous = rng_read(previous, 0);
} else { } else {
previous = current; previous = current;
} }
current = rng_read(previous, 1); current = rng_read(previous, 1);
return current; return current;
} }

@ -22,20 +22,22 @@
#include "sbu.h" #include "sbu.h"
void sbu_init(void) { void sbu_init(void) {
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
// SBU1/PA2 SBU2/PA3 // SBU1/PA2 SBU2/PA3
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3; GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
} }
void sbu_set(secbool sbu1, secbool sbu2) { void sbu_set(secbool sbu1, secbool sbu2) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, sbu1 == sectrue ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2,
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, sbu2 == sectrue ? GPIO_PIN_SET : GPIO_PIN_RESET); sbu1 == sectrue ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,
sbu2 == sectrue ? GPIO_PIN_SET : GPIO_PIN_RESET);
} }

@ -52,198 +52,202 @@
static SD_HandleTypeDef sd_handle; static SD_HandleTypeDef sd_handle;
static inline void sdcard_default_pin_state(void) { static inline void sdcard_default_pin_state(void) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // SD_ON/PC0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // SD_ON/PC0
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); // SD_DAT0/PC8 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); // SD_DAT0/PC8
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); // SD_DAT1/PC9 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); // SD_DAT1/PC9
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SD_DAT2/PC10 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SD_DAT2/PC10
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // SD_DAT3/PC11 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // SD_DAT3/PC11
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); // SD_CLK/PC12 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); // SD_CLK/PC12
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // SD_CMD/PD2 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // SD_CMD/PD2
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
// configure the SD card circuitry on/off pin // configure the SD card circuitry on/off pin
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_0; GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
// configure SD GPIO // configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; GPIO_InitStructure.Pin =
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStructure.Pin = GPIO_PIN_2; HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// configure the SD card detect pin
GPIO_InitStructure.Mode = GPIO_MODE_INPUT; // configure the SD card detect pin
GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Pin = GPIO_PIN_13; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_13;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
} }
static inline void sdcard_active_pin_state(void) { static inline void sdcard_active_pin_state(void) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // SD_ON/PC0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // SD_ON/PC0
HAL_Delay(10); // we need to wait until the circuit fully kicks-in HAL_Delay(10); // we need to wait until the circuit fully kicks-in
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
// configure SD GPIO // configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_SDIO; GPIO_InitStructure.Alternate = GPIO_AF12_SDIO;
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; GPIO_InitStructure.Pin =
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStructure.Pin = GPIO_PIN_2; HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
} }
void sdcard_init(void) { void sdcard_init(void) { sdcard_default_pin_state(); }
sdcard_default_pin_state();
}
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
// enable SDIO clock // enable SDIO clock
__HAL_RCC_SDIO_CLK_ENABLE(); __HAL_RCC_SDIO_CLK_ENABLE();
// GPIO have already been initialised by sdcard_init // GPIO have already been initialised by sdcard_init
} }
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { __HAL_RCC_SDIO_CLK_DISABLE(); }
__HAL_RCC_SDIO_CLK_DISABLE();
}
secbool sdcard_power_on(void) { secbool sdcard_power_on(void) {
if (sectrue != sdcard_is_present()) { if (sectrue != sdcard_is_present()) {
return secfalse; return secfalse;
} }
if (sd_handle.Instance) { if (sd_handle.Instance) {
return sectrue; return sectrue;
}
// turn on SD card circuitry
sdcard_active_pin_state();
HAL_Delay(50);
// SD device interface configuration
sd_handle.Instance = SDIO;
sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE;
sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B;
sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;
// init the SD interface, with retry if it's not ready yet
for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) {
if (retry == 0) {
goto error;
} }
// turn on SD card circuitry
sdcard_active_pin_state();
HAL_Delay(50); HAL_Delay(50);
}
// SD device interface configuration // configure the SD bus width for wide operation
sd_handle.Instance = SDIO; if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; HAL_SD_DeInit(&sd_handle);
sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; goto error;
sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; }
sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B;
sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;
// init the SD interface, with retry if it's not ready yet
for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) {
if (retry == 0) {
goto error;
}
HAL_Delay(50);
}
// configure the SD bus width for wide operation return sectrue;
if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
HAL_SD_DeInit(&sd_handle);
goto error;
}
return sectrue;
error: error:
sdcard_power_off(); sdcard_power_off();
return secfalse; return secfalse;
} }
void sdcard_power_off(void) { void sdcard_power_off(void) {
if (sd_handle.Instance) { if (sd_handle.Instance) {
HAL_SD_DeInit(&sd_handle); HAL_SD_DeInit(&sd_handle);
sd_handle.Instance = NULL; sd_handle.Instance = NULL;
} }
// turn off SD card circuitry // turn off SD card circuitry
HAL_Delay(50); HAL_Delay(50);
sdcard_default_pin_state(); sdcard_default_pin_state();
HAL_Delay(100); HAL_Delay(100);
} }
secbool sdcard_is_present(void) { secbool sdcard_is_present(void) {
return sectrue * (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)); return sectrue * (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13));
} }
uint64_t sdcard_get_capacity_in_bytes(void) { uint64_t sdcard_get_capacity_in_bytes(void) {
if (sd_handle.Instance == NULL) { if (sd_handle.Instance == NULL) {
return 0; return 0;
} }
HAL_SD_CardInfoTypeDef cardinfo; HAL_SD_CardInfoTypeDef cardinfo;
HAL_SD_GetCardInfo(&sd_handle, &cardinfo); HAL_SD_GetCardInfo(&sd_handle, &cardinfo);
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
} }
static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) { static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd,
// Wait for HAL driver to be ready (eg for DMA to finish) uint32_t timeout) {
uint32_t start = HAL_GetTick(); // Wait for HAL driver to be ready (eg for DMA to finish)
while (sd->State == HAL_SD_STATE_BUSY) { uint32_t start = HAL_GetTick();
if (HAL_GetTick() - start >= timeout) { while (sd->State == HAL_SD_STATE_BUSY) {
return HAL_TIMEOUT; if (HAL_GetTick() - start >= timeout) {
} return HAL_TIMEOUT;
} }
// Wait for SD card to complete the operation }
for (;;) { // Wait for SD card to complete the operation
HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd); for (;;) {
if (state == HAL_SD_CARD_TRANSFER) { HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
return HAL_OK; if (state == HAL_SD_CARD_TRANSFER) {
} return HAL_OK;
if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING || state == HAL_SD_CARD_PROGRAMMING)) {
return HAL_ERROR;
}
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
} }
return HAL_OK; if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING ||
state == HAL_SD_CARD_PROGRAMMING)) {
return HAL_ERROR;
}
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
}
return HAL_OK;
} }
secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, uint32_t num_blocks) { secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
// check that SD card is initialised uint32_t num_blocks) {
if (sd_handle.Instance == NULL) { // check that SD card is initialised
return secfalse; if (sd_handle.Instance == NULL) {
} return secfalse;
}
// check that dest pointer is aligned on a 4-byte boundary // check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) { if (((uint32_t)dest & 3) != 0) {
return secfalse; return secfalse;
} }
HAL_StatusTypeDef err = HAL_OK; HAL_StatusTypeDef err = HAL_OK;
err = HAL_SD_ReadBlocks(&sd_handle, (uint8_t *)dest, block_num, num_blocks, 60000); err = HAL_SD_ReadBlocks(&sd_handle, (uint8_t *)dest, block_num, num_blocks,
if (err == HAL_OK) { 60000);
err = sdcard_wait_finished(&sd_handle, 60000); if (err == HAL_OK) {
} err = sdcard_wait_finished(&sd_handle, 60000);
}
return sectrue * (err == HAL_OK); return sectrue * (err == HAL_OK);
} }
secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, uint32_t num_blocks) { secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
// check that SD card is initialised uint32_t num_blocks) {
if (sd_handle.Instance == NULL) { // check that SD card is initialised
return secfalse; if (sd_handle.Instance == NULL) {
} return secfalse;
}
// check that src pointer is aligned on a 4-byte boundary // check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) { if (((uint32_t)src & 3) != 0) {
return secfalse; return secfalse;
} }
HAL_StatusTypeDef err = HAL_OK; HAL_StatusTypeDef err = HAL_OK;
err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t *)src, block_num, num_blocks, 60000); err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t *)src, block_num, num_blocks,
if (err == HAL_OK) { 60000);
err = sdcard_wait_finished(&sd_handle, 60000); if (err == HAL_OK) {
} err = sdcard_wait_finished(&sd_handle, 60000);
}
return sectrue * (err == HAL_OK); return sectrue * (err == HAL_OK);
} }

@ -56,7 +56,9 @@ secbool __wur sdcard_power_on(void);
void sdcard_power_off(void); void sdcard_power_off(void);
secbool __wur sdcard_is_present(void); secbool __wur sdcard_is_present(void);
uint64_t sdcard_get_capacity_in_bytes(void); uint64_t sdcard_get_capacity_in_bytes(void);
secbool __wur sdcard_read_blocks(uint32_t *dest, uint32_t block_num, uint32_t num_blocks); secbool __wur sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
secbool __wur sdcard_write_blocks(const uint32_t *src, uint32_t block_num, uint32_t num_blocks); uint32_t num_blocks);
secbool __wur sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
uint32_t num_blocks);
#endif #endif

@ -23,11 +23,11 @@
#include <stdint.h> #include <stdint.h>
typedef uint32_t secbool; typedef uint32_t secbool;
#define sectrue 0xAAAAAAAAU #define sectrue 0xAAAAAAAAU
#define secfalse 0x00000000U #define secfalse 0x00000000U
#ifndef __wur #ifndef __wur
#define __wur __attribute__ ((warn_unused_result)) #define __wur __attribute__((warn_unused_result))
#endif #endif
#endif #endif

@ -21,7 +21,8 @@
#include "rng.h" #include "rng.h"
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
#ifdef STM32F427xx #ifdef STM32F427xx
@ -34,56 +35,69 @@ const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
uint32_t SystemCoreClock = CORE_CLOCK_MHZ * 1000000U; uint32_t SystemCoreClock = CORE_CLOCK_MHZ * 1000000U;
#pragma GCC optimize("no-stack-protector") // applies to all functions in this file #pragma GCC optimize( \
"no-stack-protector") // applies to all functions in this file
void SystemInit(void) void SystemInit(void) {
{ // set flash wait states for an increasing HCLK frequency -- reference RM0090
// set flash wait states for an increasing HCLK frequency -- reference RM0090 section 3.5.1 // section 3.5.1
FLASH->ACR = FLASH_ACR_LATENCY_5WS; FLASH->ACR = FLASH_ACR_LATENCY_5WS;
// wait until the new wait state config takes effect -- per section 3.5.1 guidance // wait until the new wait state config takes effect -- per section 3.5.1
while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS); // guidance
// configure main PLL; assumes HSE is 8 MHz; this should evaluate to 0x27402a04 -- reference RM0090 section 7.3.2 while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS)
RCC->PLLCFGR = (RCC_PLLCFGR_RST_VALUE & ~RCC_PLLCFGR_PLLQ & ~RCC_PLLCFGR_PLLSRC & ~RCC_PLLCFGR_PLLP & ~RCC_PLLCFGR_PLLN & ~RCC_PLLCFGR_PLLM) ;
| (7U << RCC_PLLCFGR_PLLQ_Pos) // Q = 7 // configure main PLL; assumes HSE is 8 MHz; this should evaluate to
| RCC_PLLCFGR_PLLSRC_HSE // PLLSRC = HSE // 0x27402a04 -- reference RM0090 section 7.3.2
| (0U << RCC_PLLCFGR_PLLP_Pos) // P = 2 (two bits, 00 means PLLP = 2) RCC->PLLCFGR =
| (CORE_CLOCK_MHZ << RCC_PLLCFGR_PLLN_Pos) // N = CORE_CLOCK_MHZ (RCC_PLLCFGR_RST_VALUE & ~RCC_PLLCFGR_PLLQ & ~RCC_PLLCFGR_PLLSRC &
| (4U << RCC_PLLCFGR_PLLM_Pos); // M = 4 ~RCC_PLLCFGR_PLLP & ~RCC_PLLCFGR_PLLN & ~RCC_PLLCFGR_PLLM) |
// enable spread spectrum clock for main PLL (7U << RCC_PLLCFGR_PLLQ_Pos) // Q = 7
RCC->SSCGR = RCC_SSCGR_SSCGEN | (44 << RCC_SSCGR_INCSTEP_Pos) | (250 << RCC_SSCGR_MODPER_Pos); | RCC_PLLCFGR_PLLSRC_HSE // PLLSRC = HSE
// enable clock security system, HSE clock, and main PLL | (0U << RCC_PLLCFGR_PLLP_Pos) // P = 2 (two bits, 00 means PLLP = 2)
RCC->CR |= RCC_CR_CSSON | RCC_CR_HSEON | RCC_CR_PLLON; | (CORE_CLOCK_MHZ << RCC_PLLCFGR_PLLN_Pos) // N = CORE_CLOCK_MHZ
// wait until PLL and HSE ready | (4U << RCC_PLLCFGR_PLLM_Pos); // M = 4
while((RCC->CR & (RCC_CR_PLLRDY | RCC_CR_HSERDY)) != (RCC_CR_PLLRDY | RCC_CR_HSERDY)); // enable spread spectrum clock for main PLL
// APB2=2, APB1=4, AHB=1, system clock = main PLL RCC->SSCGR = RCC_SSCGR_SSCGEN | (44 << RCC_SSCGR_INCSTEP_Pos) |
const uint32_t cfgr = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLL; (250 << RCC_SSCGR_MODPER_Pos);
RCC->CFGR = cfgr; // enable clock security system, HSE clock, and main PLL
// wait until PLL is system clock and also verify that the pre-scalers were set RCC->CR |= RCC_CR_CSSON | RCC_CR_HSEON | RCC_CR_PLLON;
while(RCC->CFGR != (RCC_CFGR_SWS_PLL | cfgr)); // wait until PLL and HSE ready
// turn off the HSI as it is now unused (it will be turned on again automatically if a clock security failure occurs) while ((RCC->CR & (RCC_CR_PLLRDY | RCC_CR_HSERDY)) !=
RCC->CR &= ~RCC_CR_HSION; (RCC_CR_PLLRDY | RCC_CR_HSERDY))
// wait until ths HSI is off ;
while((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION); // APB2=2, APB1=4, AHB=1, system clock = main PLL
// init the TRNG peripheral const uint32_t cfgr = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 |
rng_init(); RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLL;
// set CP10 and CP11 to enable full access to the fpu coprocessor; ARMv7-M Architecture Reference Manual section B3.2.20 RCC->CFGR = cfgr;
SCB->CPACR |= ((3U << 22) | (3U << 20)); // wait until PLL is system clock and also verify that the pre-scalers were
// set
while (RCC->CFGR != (RCC_CFGR_SWS_PLL | cfgr))
;
// turn off the HSI as it is now unused (it will be turned on again
// automatically if a clock security failure occurs)
RCC->CR &= ~RCC_CR_HSION;
// wait until ths HSI is off
while ((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION)
;
// init the TRNG peripheral
rng_init();
// set CP10 and CP11 to enable full access to the fpu coprocessor; ARMv7-M
// Architecture Reference Manual section B3.2.20
SCB->CPACR |= ((3U << 22) | (3U << 20));
} }
extern volatile uint32_t uwTick; extern volatile uint32_t uwTick;
void SysTick_Handler(void) void SysTick_Handler(void) {
{ // this is a millisecond tick counter that wraps after approximately
// this is a millisecond tick counter that wraps after approximately // 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000)) uwTick++;
uwTick++;
} }
// from util.s // from util.s
extern void shutdown(void); extern void shutdown(void);
void PVD_IRQHandler(void) void PVD_IRQHandler(void) {
{ TIM1->CCR1 = 0; // turn off display backlight
TIM1->CCR1 = 0; // turn off display backlight shutdown();
shutdown();
} }

@ -1,3 +1,5 @@
// clang-format off
/** /**
****************************************************************************** ******************************************************************************
* @file stm32f4xx_hal_conf.h * @file stm32f4xx_hal_conf.h

@ -1,3 +1,5 @@
// clang-format off
/* /*
* This file is part of the TREZOR project, https://trezor.io/ * This file is part of the TREZOR project, https://trezor.io/
* *

@ -28,17 +28,20 @@
#error Unknown TREZOR Model #error Unknown TREZOR Model
#endif #endif
uint32_t touch_click(void) uint32_t touch_click(void) {
{ uint32_t r = 0;
uint32_t r = 0; // flush touch events if any
// flush touch events if any while (touch_read()) {
while (touch_read()) { } }
// wait for TOUCH_START // wait for TOUCH_START
while ((touch_read() & TOUCH_START) == 0) { } while ((touch_read() & TOUCH_START) == 0) {
// wait for TOUCH_END }
while (((r = touch_read()) & TOUCH_END) == 0) { } // wait for TOUCH_END
// flush touch events if any while (((r = touch_read()) & TOUCH_END) == 0) {
while (touch_read()) { } }
// return last touch coordinate // flush touch events if any
return r; while (touch_read()) {
}
// return last touch coordinate
return r;
} }

@ -22,9 +22,9 @@
#include <stdint.h> #include <stdint.h>
#define TOUCH_START (1U << 24) #define TOUCH_START (1U << 24)
#define TOUCH_MOVE (1U << 25) #define TOUCH_MOVE (1U << 25)
#define TOUCH_END (1U << 26) #define TOUCH_END (1U << 26)
void touch_init(void); void touch_init(void);
void touch_power_on(void); void touch_power_on(void);
@ -33,8 +33,14 @@ void touch_sensitivity(uint8_t value);
uint32_t touch_read(void); uint32_t touch_read(void);
uint32_t touch_click(void); uint32_t touch_click(void);
uint32_t touch_is_detected(void); uint32_t touch_is_detected(void);
static inline uint16_t touch_unpack_x(uint32_t evt) { return (evt >> 12) & 0xFFF; } static inline uint16_t touch_unpack_x(uint32_t evt) {
static inline uint16_t touch_unpack_y(uint32_t evt) { return (evt >> 0) & 0xFFF; } return (evt >> 12) & 0xFFF;
static inline uint32_t touch_pack_xy(uint16_t x, uint16_t y) { return ((x & 0xFFF) << 12) | (y & 0xFFF); } }
static inline uint16_t touch_unpack_y(uint32_t evt) {
return (evt >> 0) & 0xFFF;
}
static inline uint32_t touch_pack_xy(uint16_t x, uint16_t y) {
return ((x & 0xFFF) << 12) | (y & 0xFFF);
}
#endif #endif

@ -1,55 +1,54 @@
#define BTN_PIN_LEFT GPIO_PIN_5 #define BTN_PIN_LEFT GPIO_PIN_5
#define BTN_PIN_RIGHT GPIO_PIN_2 #define BTN_PIN_RIGHT GPIO_PIN_2
#define DISPLAY_RESX 128 #define DISPLAY_RESX 128
#define DISPLAY_RESY 64 #define DISPLAY_RESY 64
#define BTN_LEFT_COORDS touch_pack_xy(0, DISPLAY_RESY - 1) #define BTN_LEFT_COORDS touch_pack_xy(0, DISPLAY_RESY - 1)
#define BTN_RIGHT_COORDS touch_pack_xy(DISPLAY_RESX - 1, DISPLAY_RESY - 1) #define BTN_RIGHT_COORDS touch_pack_xy(DISPLAY_RESX - 1, DISPLAY_RESY - 1)
void touch_init(void) { void touch_init(void) {
__HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input // PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = BTN_PIN_LEFT | BTN_PIN_RIGHT; GPIO_InitStructure.Pin = BTN_PIN_LEFT | BTN_PIN_RIGHT;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
} }
void touch_power_on(void) { } void touch_power_on(void) {}
void touch_power_off(void) { } void touch_power_off(void) {}
void touch_sensitivity(uint8_t value) { (void)value; } void touch_sensitivity(uint8_t value) { (void)value; }
uint32_t touch_read(void) uint32_t touch_read(void) {
{ static char last_left = 0, last_right = 0;
static char last_left = 0, last_right = 0; char left = (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_LEFT));
char left = (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_LEFT)); char right = (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_RIGHT));
char right = (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_RIGHT)); if (last_left != left) {
if (last_left != left) { last_left = left;
last_left = left; if (left) {
if (left) { return TOUCH_START | BTN_LEFT_COORDS;
return TOUCH_START | BTN_LEFT_COORDS; } else {
} else { return TOUCH_END | BTN_LEFT_COORDS;
return TOUCH_END | BTN_LEFT_COORDS;
}
} }
if (last_right != right) { }
last_right = right; if (last_right != right) {
if (right) { last_right = right;
return TOUCH_START | BTN_RIGHT_COORDS; if (right) {
} else { return TOUCH_START | BTN_RIGHT_COORDS;
return TOUCH_END | BTN_RIGHT_COORDS; } else {
} return TOUCH_END | BTN_RIGHT_COORDS;
} }
return 0; }
return 0;
} }
uint32_t touch_is_detected(void) uint32_t touch_is_detected(void) {
{ return (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_LEFT)) ||
return (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_LEFT)) || (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_RIGHT)); (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, BTN_PIN_RIGHT));
} }

@ -3,13 +3,14 @@
#include "common.h" #include "common.h"
#include "secbool.h" #include "secbool.h"
#define TOUCH_ADDRESS (0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit #define TOUCH_ADDRESS \
#define TOUCH_PACKET_SIZE 7U (0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit
#define EVENT_PRESS_DOWN 0x00U #define TOUCH_PACKET_SIZE 7U
#define EVENT_CONTACT 0x80U #define EVENT_PRESS_DOWN 0x00U
#define EVENT_LIFT_UP 0x40U #define EVENT_CONTACT 0x80U
#define EVENT_NO_EVENT 0xC0U #define EVENT_LIFT_UP 0x40U
#define GESTURE_NO_GESTURE 0x00U #define EVENT_NO_EVENT 0xC0U
#define GESTURE_NO_GESTURE 0x00U
#define X_POS_MSB (touch_data[3] & 0x0FU) #define X_POS_MSB (touch_data[3] & 0x0FU)
#define X_POS_LSB (touch_data[4]) #define X_POS_LSB (touch_data[4])
#define Y_POS_MSB (touch_data[5] & 0x0FU) #define Y_POS_MSB (touch_data[5] & 0x0FU)
@ -18,180 +19,202 @@
static I2C_HandleTypeDef i2c_handle; static I2C_HandleTypeDef i2c_handle;
static void touch_default_pin_state(void) { static void touch_default_pin_state(void) {
// set power off and other pins as per section 3.5 of FT6236 datasheet // set power off and other pins as per section 3.5 of FT6236 datasheet
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); // CTP_ON/PB10 (active low) i.e.- CTPM power off when set/high/log 1 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10,
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); // CTP_I2C_SCL/PB6 GPIO_PIN_SET); // CTP_ON/PB10 (active low) i.e.- CTPM power
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // CTP_I2C_SDA/PB7 // off when set/high/log 1
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET); // CTP_INT/PC4 normally an input, but drive low as an output while powered off HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); // CTP_I2C_SCL/PB6
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET); // CTP_REST/PC5 (active low) i.e.- CTPM held in reset until released HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // CTP_I2C_SDA/PB7
HAL_GPIO_WritePin(
// set above pins to OUTPUT / NOPULL GPIOC, GPIO_PIN_4,
GPIO_InitTypeDef GPIO_InitStructure; GPIO_PIN_RESET); // CTP_INT/PC4 normally an input, but drive low as an
// output while powered off
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5,
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_PIN_RESET); // CTP_REST/PC5 (active low) i.e.- CTPM
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; // held in reset until released
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_6 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); // set above pins to OUTPUT / NOPULL
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5; GPIO_InitTypeDef GPIO_InitStructure;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
// in-case power was on, or CTPM was active make sure to wait long enough GPIO_InitStructure.Pull = GPIO_NOPULL;
// for these changes to take effect. a reset needs to be low for GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
// a minimum of 5ms. also wait for power circuitry to stabilize (if it changed). GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_6 | GPIO_PIN_7;
HAL_Delay(100); // 100ms (being conservative) HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
// in-case power was on, or CTPM was active make sure to wait long enough
// for these changes to take effect. a reset needs to be low for
// a minimum of 5ms. also wait for power circuitry to stabilize (if it
// changed).
HAL_Delay(100); // 100ms (being conservative)
} }
static void touch_active_pin_state(void) { static void touch_active_pin_state(void) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); // CTP_ON/PB10 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); // CTP_ON/PB10
HAL_Delay(10); // we need to wait until the circuit fully kicks-in HAL_Delay(10); // we need to wait until the circuit fully kicks-in
GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
// configure CTP I2C SCL and SDA GPIO lines (PB6 & PB7) // configure CTP I2C SCL and SDA GPIO lines (PB6 & PB7)
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; // I2C is a KHz bus and low speed is still good into the low MHz GPIO_InitStructure.Speed =
GPIO_InitStructure.Alternate = GPIO_AF4_I2C1; GPIO_SPEED_FREQ_LOW; // I2C is a KHz bus and low speed is still good into
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7; // the low MHz
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.Alternate = GPIO_AF4_I2C1;
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP; // PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pin = GPIO_PIN_4; GPIO_InitStructure.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // release CTPM reset HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
HAL_Delay(310); // "Time of starting to report point after resetting" min is 300ms, giving an extra 10ms
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // release CTPM reset
HAL_Delay(310); // "Time of starting to report point after resetting" min is
// 300ms, giving an extra 10ms
} }
void touch_init(void) { void touch_init(void) { touch_default_pin_state(); }
touch_default_pin_state();
}
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) { void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) {
// enable I2C clock // enable I2C clock
__HAL_RCC_I2C1_CLK_ENABLE(); __HAL_RCC_I2C1_CLK_ENABLE();
// GPIO have already been initialised by touch_init // GPIO have already been initialised by touch_init
} }
void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) { void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) {
__HAL_RCC_I2C1_CLK_DISABLE(); __HAL_RCC_I2C1_CLK_DISABLE();
} }
void touch_power_on(void) { void touch_power_on(void) {
if (i2c_handle.Instance) { if (i2c_handle.Instance) {
return; return;
} }
// turn on CTP circuitry // turn on CTP circuitry
touch_active_pin_state(); touch_active_pin_state();
HAL_Delay(50); HAL_Delay(50);
// I2C device interface configuration // I2C device interface configuration
i2c_handle.Instance = I2C1; i2c_handle.Instance = I2C1;
i2c_handle.Init.ClockSpeed = 400000; i2c_handle.Init.ClockSpeed = 400000;
i2c_handle.Init.DutyCycle = I2C_DUTYCYCLE_16_9; i2c_handle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
i2c_handle.Init.OwnAddress1 = 0xFE; // master i2c_handle.Init.OwnAddress1 = 0xFE; // master
i2c_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; i2c_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
i2c_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; i2c_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
i2c_handle.Init.OwnAddress2 = 0; i2c_handle.Init.OwnAddress2 = 0;
i2c_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; i2c_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_OK != HAL_I2C_Init(&i2c_handle)) { if (HAL_OK != HAL_I2C_Init(&i2c_handle)) {
ensure(secfalse, NULL); ensure(secfalse, NULL);
return; return;
} }
// set register 0xA4 G_MODE to interrupt polling mode (0x00). basically, CTPM keeps this input line (to PC4) low while a finger is on the screen. // set register 0xA4 G_MODE to interrupt polling mode (0x00). basically, CTPM
uint8_t touch_panel_config[] = {0xA4, 0x00}; // keeps this input line (to PC4) low while a finger is on the screen.
ensure(sectrue * (HAL_OK == HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, touch_panel_config, sizeof(touch_panel_config), 10)), NULL); uint8_t touch_panel_config[] = {0xA4, 0x00};
ensure(
touch_sensitivity(0x06); sectrue * (HAL_OK == HAL_I2C_Master_Transmit(
&i2c_handle, TOUCH_ADDRESS, touch_panel_config,
sizeof(touch_panel_config), 10)),
NULL);
touch_sensitivity(0x06);
} }
void touch_power_off(void) { void touch_power_off(void) {
if (i2c_handle.Instance) { if (i2c_handle.Instance) {
HAL_I2C_DeInit(&i2c_handle); HAL_I2C_DeInit(&i2c_handle);
i2c_handle.Instance = NULL; i2c_handle.Instance = NULL;
} }
// turn off CTP circuitry // turn off CTP circuitry
HAL_Delay(50); HAL_Delay(50);
touch_default_pin_state(); touch_default_pin_state();
} }
void touch_sensitivity(uint8_t value) { void touch_sensitivity(uint8_t value) {
// set panel threshold (TH_GROUP) - default value is 0x12 // set panel threshold (TH_GROUP) - default value is 0x12
uint8_t touch_panel_threshold[] = {0x80, value}; uint8_t touch_panel_threshold[] = {0x80, value};
ensure(sectrue * (HAL_OK == HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, touch_panel_threshold, sizeof(touch_panel_threshold), 10)), NULL); ensure(sectrue *
(HAL_OK == HAL_I2C_Master_Transmit(
&i2c_handle, TOUCH_ADDRESS, touch_panel_threshold,
sizeof(touch_panel_threshold), 10)),
NULL);
} }
uint32_t touch_is_detected(void) uint32_t touch_is_detected(void) {
{ // check the interrupt line coming in from the CTPM.
// check the interrupt line coming in from the CTPM. // the line goes low when a touch event is actively detected.
// the line goes low when a touch event is actively detected. // reference section 1.2 of "Application Note for FT6x06 CTPM".
// reference section 1.2 of "Application Note for FT6x06 CTPM". // we configure the touch controller to use "interrupt polling mode".
// we configure the touch controller to use "interrupt polling mode". return GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
return GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
} }
uint32_t touch_read(void) uint32_t touch_read(void) {
{ static uint8_t touch_data[TOUCH_PACKET_SIZE],
static uint8_t touch_data[TOUCH_PACKET_SIZE], previous_touch_data[TOUCH_PACKET_SIZE]; previous_touch_data[TOUCH_PACKET_SIZE];
static uint32_t xy; static uint32_t xy;
static int touching; static int touching;
int last_packet = 0; int last_packet = 0;
if (!touch_is_detected()) { if (!touch_is_detected()) {
// only poll when the touch interrupt is active. // only poll when the touch interrupt is active.
// when it's inactive, we might need to read one last data packet to get to // when it's inactive, we might need to read one last data packet to get to
// the TOUCH_END event, which clears the `touching` flag. // the TOUCH_END event, which clears the `touching` flag.
if (touching) { if (touching) {
last_packet = 1; last_packet = 1;
} else {
return 0;
}
}
uint8_t outgoing[] = {0x00}; // start reading from address 0x00
if (HAL_OK != HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, outgoing, sizeof(outgoing), 1)) {
return 0;
}
if (HAL_OK != HAL_I2C_Master_Receive(&i2c_handle, TOUCH_ADDRESS, touch_data, TOUCH_PACKET_SIZE, 1)) {
return 0; // read failure
}
if (0 == memcmp(previous_touch_data, touch_data, TOUCH_PACKET_SIZE)) {
return 0; // polled and got the same event again
} else { } else {
memcpy(previous_touch_data, touch_data, TOUCH_PACKET_SIZE); return 0;
} }
}
const uint32_t number_of_touch_points = touch_data[2] & 0x0F; // valid values are 0, 1, 2 (invalid 0xF before first touch) (tested with FT6206) uint8_t outgoing[] = {0x00}; // start reading from address 0x00
const uint32_t event_flag = touch_data[3] & 0xC0; if (HAL_OK != HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, outgoing,
if (touch_data[1] == GESTURE_NO_GESTURE) { sizeof(outgoing), 1)) {
xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB, (Y_POS_MSB << 8) | Y_POS_LSB); return 0;
if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) { }
touching = 1;
return TOUCH_START | xy; if (HAL_OK != HAL_I2C_Master_Receive(&i2c_handle, TOUCH_ADDRESS, touch_data,
} else if ((number_of_touch_points == 1) && (event_flag == EVENT_CONTACT)) { TOUCH_PACKET_SIZE, 1)) {
return TOUCH_MOVE | xy; return 0; // read failure
} else if ((number_of_touch_points == 0) && (event_flag == EVENT_LIFT_UP)) { }
touching = 0;
return TOUCH_END | xy; if (0 == memcmp(previous_touch_data, touch_data, TOUCH_PACKET_SIZE)) {
} return 0; // polled and got the same event again
} else {
memcpy(previous_touch_data, touch_data, TOUCH_PACKET_SIZE);
}
const uint32_t number_of_touch_points =
touch_data[2] & 0x0F; // valid values are 0, 1, 2 (invalid 0xF before
// first touch) (tested with FT6206)
const uint32_t event_flag = touch_data[3] & 0xC0;
if (touch_data[1] == GESTURE_NO_GESTURE) {
xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB,
(Y_POS_MSB << 8) | Y_POS_LSB);
if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) {
touching = 1;
return TOUCH_START | xy;
} else if ((number_of_touch_points == 1) && (event_flag == EVENT_CONTACT)) {
return TOUCH_MOVE | xy;
} else if ((number_of_touch_points == 0) && (event_flag == EVENT_LIFT_UP)) {
touching = 0;
return TOUCH_END | xy;
} }
}
if (last_packet) { if (last_packet) {
// interrupt line is inactive, we didn't read valid touch data, and as far as // interrupt line is inactive, we didn't read valid touch data, and as far
// we know, we never sent a TOUCH_END event. // as we know, we never sent a TOUCH_END event.
touching = 0; touching = 0;
return TOUCH_END | xy; return TOUCH_END | xy;
} }
return 0; return 0;
} }

@ -19,35 +19,41 @@
#include STM32_HAL_H #include STM32_HAL_H
#include "common.h"
#include "usb.h" #include "usb.h"
#include "common.h"
#include "usbd_core.h" #include "usbd_core.h"
#define USB_MAX_CONFIG_DESC_SIZE 256 #define USB_MAX_CONFIG_DESC_SIZE 256
#define USB_MAX_STR_SIZE 62 #define USB_MAX_STR_SIZE 62
#define USB_MAX_STR_DESC_SIZE (USB_MAX_STR_SIZE * 2 + 2) #define USB_MAX_STR_DESC_SIZE (USB_MAX_STR_SIZE * 2 + 2)
#if defined(USE_USB_FS) #if defined(USE_USB_FS)
#define USB_PHY_ID USB_PHY_FS_ID #define USB_PHY_ID USB_PHY_FS_ID
#elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) #elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS)
#define USB_PHY_ID USB_PHY_HS_ID #define USB_PHY_ID USB_PHY_HS_ID
#else #else
#error Unable to determine proper USB_PHY_ID to use #error Unable to determine proper USB_PHY_ID to use
#endif #endif
#define USB_WINUSB_VENDOR_CODE '!' // arbitrary, but must be equivalent to the last character in extra string #define USB_WINUSB_VENDOR_CODE \
#define USB_WINUSB_EXTRA_STRING 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, USB_WINUSB_VENDOR_CODE , 0x00 // MSFT100! '!' // arbitrary, but must be equivalent to the last character in extra
#define USB_WINUSB_EXTRA_STRING_INDEX 0xEE // string
#define USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 #define USB_WINUSB_EXTRA_STRING \
#define USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, \
USB_WINUSB_VENDOR_CODE, 0x00 // MSFT100!
#define USB_WINUSB_EXTRA_STRING_INDEX 0xEE
#define USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04
#define USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05
#define UNCONST(X) ((uint8_t *)(X)) #define UNCONST(X) ((uint8_t *)(X))
static usb_device_descriptor_t usb_dev_desc; static usb_device_descriptor_t usb_dev_desc;
// Config descriptor // Config descriptor
static uint8_t usb_config_buf[USB_MAX_CONFIG_DESC_SIZE] __attribute__((aligned(4))); static uint8_t usb_config_buf[USB_MAX_CONFIG_DESC_SIZE]
static usb_config_descriptor_t *usb_config_desc = (usb_config_descriptor_t *)(usb_config_buf); __attribute__((aligned(4)));
static usb_config_descriptor_t *usb_config_desc =
(usb_config_descriptor_t *)(usb_config_buf);
static usb_interface_descriptor_t *usb_next_iface_desc; static usb_interface_descriptor_t *usb_next_iface_desc;
// String descriptor // String descriptor
@ -64,114 +70,127 @@ static secbool usb21_enabled = secfalse;
static secbool usb21_landing = secfalse; static secbool usb21_landing = secfalse;
static secbool __wur check_desc_str(const char *s) { static secbool __wur check_desc_str(const char *s) {
if (NULL == s) return secfalse; if (NULL == s) return secfalse;
if (strlen(s) > USB_MAX_STR_SIZE) return secfalse; if (strlen(s) > USB_MAX_STR_SIZE) return secfalse;
return sectrue; return sectrue;
} }
void usb_init(const usb_dev_info_t *dev_info) { void usb_init(const usb_dev_info_t *dev_info) {
// enable/disable USB 2.1 features
// enable/disable USB 2.1 features usb21_enabled = dev_info->usb21_enabled;
usb21_enabled = dev_info->usb21_enabled; usb21_landing = dev_info->usb21_landing;
usb21_landing = dev_info->usb21_landing;
// Device descriptor
// Device descriptor usb_dev_desc.bLength = sizeof(usb_device_descriptor_t);
usb_dev_desc.bLength = sizeof(usb_device_descriptor_t); usb_dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE;
usb_dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE; usb_dev_desc.bcdUSB =
usb_dev_desc.bcdUSB = (sectrue == usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0 (sectrue == usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0
usb_dev_desc.bDeviceClass = dev_info->device_class; usb_dev_desc.bDeviceClass = dev_info->device_class;
usb_dev_desc.bDeviceSubClass = dev_info->device_subclass; usb_dev_desc.bDeviceSubClass = dev_info->device_subclass;
usb_dev_desc.bDeviceProtocol = dev_info->device_protocol; usb_dev_desc.bDeviceProtocol = dev_info->device_protocol;
usb_dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE; usb_dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE;
usb_dev_desc.idVendor = dev_info->vendor_id; usb_dev_desc.idVendor = dev_info->vendor_id;
usb_dev_desc.idProduct = dev_info->product_id; usb_dev_desc.idProduct = dev_info->product_id;
usb_dev_desc.bcdDevice = dev_info->release_num; usb_dev_desc.bcdDevice = dev_info->release_num;
usb_dev_desc.iManufacturer = USBD_IDX_MFC_STR; // Index of manufacturer string usb_dev_desc.iManufacturer =
usb_dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string USBD_IDX_MFC_STR; // Index of manufacturer string
usb_dev_desc.iSerialNumber = USBD_IDX_SERIAL_STR; // Index of serial number string usb_dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string
usb_dev_desc.bNumConfigurations = 1; usb_dev_desc.iSerialNumber =
USBD_IDX_SERIAL_STR; // Index of serial number string
// String table usb_dev_desc.bNumConfigurations = 1;
ensure(check_desc_str(dev_info->manufacturer), NULL);
ensure(check_desc_str(dev_info->product), NULL); // String table
ensure(check_desc_str(dev_info->serial_number), NULL); ensure(check_desc_str(dev_info->manufacturer), NULL);
ensure(check_desc_str(dev_info->interface), NULL); ensure(check_desc_str(dev_info->product), NULL);
ensure(check_desc_str(dev_info->serial_number), NULL);
usb_str_table.manufacturer = dev_info->manufacturer; ensure(check_desc_str(dev_info->interface), NULL);
usb_str_table.product = dev_info->product;
usb_str_table.serial_number = dev_info->serial_number; usb_str_table.manufacturer = dev_info->manufacturer;
usb_str_table.interface = dev_info->interface; usb_str_table.product = dev_info->product;
usb_str_table.serial_number = dev_info->serial_number;
// Configuration descriptor usb_str_table.interface = dev_info->interface;
usb_config_desc->bLength = sizeof(usb_config_descriptor_t);
usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION; // Configuration descriptor
usb_config_desc->wTotalLength = sizeof(usb_config_descriptor_t); // will be updated later via usb_desc_add_iface() usb_config_desc->bLength = sizeof(usb_config_descriptor_t);
usb_config_desc->bNumInterfaces = 0; // will be updated later via usb_desc_add_iface() usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION;
usb_config_desc->bConfigurationValue = 0x01; usb_config_desc->wTotalLength =
usb_config_desc->iConfiguration = 0; sizeof(usb_config_descriptor_t); // will be updated later via
usb_config_desc->bmAttributes = 0x80; // 0x80 = bus powered; 0xC0 = self powered // usb_desc_add_iface()
usb_config_desc->bMaxPower = 0x32; // Maximum Power Consumption in 2mA units usb_config_desc->bNumInterfaces =
0; // will be updated later via usb_desc_add_iface()
// Pointer to interface descriptor data usb_config_desc->bConfigurationValue = 0x01;
usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength); usb_config_desc->iConfiguration = 0;
usb_config_desc->bmAttributes =
ensure(sectrue * (USBD_OK == USBD_Init(&usb_dev_handle, (USBD_DescriptorsTypeDef*)&usb_descriptors, USB_PHY_ID)), NULL); 0x80; // 0x80 = bus powered; 0xC0 = self powered
ensure(sectrue * (USBD_OK == USBD_RegisterClass(&usb_dev_handle, (USBD_ClassTypeDef*)&usb_class)), NULL); usb_config_desc->bMaxPower = 0x32; // Maximum Power Consumption in 2mA units
// Pointer to interface descriptor data
usb_next_iface_desc =
(usb_interface_descriptor_t *)(usb_config_buf +
usb_config_desc->wTotalLength);
ensure(sectrue *
(USBD_OK == USBD_Init(&usb_dev_handle,
(USBD_DescriptorsTypeDef *)&usb_descriptors,
USB_PHY_ID)),
NULL);
ensure(sectrue *
(USBD_OK == USBD_RegisterClass(&usb_dev_handle,
(USBD_ClassTypeDef *)&usb_class)),
NULL);
} }
void usb_deinit(void) { void usb_deinit(void) {
USBD_DeInit(&usb_dev_handle); USBD_DeInit(&usb_dev_handle);
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
usb_ifaces[i].type = USB_IFACE_TYPE_DISABLED; usb_ifaces[i].type = USB_IFACE_TYPE_DISABLED;
} }
} }
void usb_start(void) { void usb_start(void) { USBD_Start(&usb_dev_handle); }
USBD_Start(&usb_dev_handle);
}
void usb_stop(void) { void usb_stop(void) { USBD_Stop(&usb_dev_handle); }
USBD_Stop(&usb_dev_handle);
}
/* /*
* Utility functions for USB interfaces * Utility functions for USB interfaces
*/ */
static usb_iface_t *usb_get_iface(uint8_t iface_num) { static usb_iface_t *usb_get_iface(uint8_t iface_num) {
if (iface_num < USBD_MAX_NUM_INTERFACES) { if (iface_num < USBD_MAX_NUM_INTERFACES) {
return &usb_ifaces[iface_num]; return &usb_ifaces[iface_num];
} else { } else {
return NULL; // Invalid interface number return NULL; // Invalid interface number
} }
} }
static void *usb_desc_alloc_iface(size_t desc_len) { static void *usb_desc_alloc_iface(size_t desc_len) {
if (usb_config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) { if (usb_config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) {
return usb_next_iface_desc; return usb_next_iface_desc;
} else { } else {
return NULL; // Not enough space in the descriptor return NULL; // Not enough space in the descriptor
} }
} }
static void usb_desc_add_iface(size_t desc_len) { static void usb_desc_add_iface(size_t desc_len) {
usb_config_desc->bNumInterfaces++; usb_config_desc->bNumInterfaces++;
usb_config_desc->wTotalLength += desc_len; usb_config_desc->wTotalLength += desc_len;
usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength); usb_next_iface_desc =
(usb_interface_descriptor_t *)(usb_config_buf +
usb_config_desc->wTotalLength);
} }
static uint8_t usb_ep_set_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) { static uint8_t usb_ep_set_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) {
PCD_HandleTypeDef *hpcd = dev->pData; PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
return USBD_OK; return USBD_OK;
} }
static uint8_t usb_ep_clear_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) { static uint8_t usb_ep_clear_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) {
PCD_HandleTypeDef *hpcd = dev->pData; PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
return USBD_OK; return USBD_OK;
} }
/* /*
@ -186,84 +205,93 @@ static uint8_t usb_ep_clear_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) {
* USB configuration (device & string descriptors) * USB configuration (device & string descriptors)
*/ */
static uint8_t *usb_get_dev_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_dev_descriptor(USBD_SpeedTypeDef speed,
*length = sizeof(usb_dev_desc); uint16_t *length) {
return (uint8_t *)(&usb_dev_desc); *length = sizeof(usb_dev_desc);
return (uint8_t *)(&usb_dev_desc);
} }
static uint8_t *usb_get_langid_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_langid_str_descriptor(USBD_SpeedTypeDef speed,
static const usb_langid_descriptor_t usb_langid_str_desc = { uint16_t *length) {
.bLength = USB_LEN_LANGID_STR_DESC, static const usb_langid_descriptor_t usb_langid_str_desc = {
.bDescriptorType = USB_DESC_TYPE_STRING, .bLength = USB_LEN_LANGID_STR_DESC,
.wData = USB_LANGID_ENGLISH_US, .bDescriptorType = USB_DESC_TYPE_STRING,
}; .wData = USB_LANGID_ENGLISH_US,
*length = sizeof(usb_langid_str_desc); };
return UNCONST(&usb_langid_str_desc); *length = sizeof(usb_langid_str_desc);
return UNCONST(&usb_langid_str_desc);
} }
static uint8_t *usb_get_manufacturer_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_manufacturer_str_descriptor(USBD_SpeedTypeDef speed,
USBD_GetString((uint8_t *)usb_str_table.manufacturer, usb_str_buf, length); uint16_t *length) {
return usb_str_buf; USBD_GetString((uint8_t *)usb_str_table.manufacturer, usb_str_buf, length);
return usb_str_buf;
} }
static uint8_t *usb_get_product_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_product_str_descriptor(USBD_SpeedTypeDef speed,
USBD_GetString((uint8_t *)usb_str_table.product, usb_str_buf, length); uint16_t *length) {
return usb_str_buf; USBD_GetString((uint8_t *)usb_str_table.product, usb_str_buf, length);
return usb_str_buf;
} }
static uint8_t *usb_get_serial_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_serial_str_descriptor(USBD_SpeedTypeDef speed,
USBD_GetString((uint8_t *)usb_str_table.serial_number, usb_str_buf, length); uint16_t *length) {
return usb_str_buf; USBD_GetString((uint8_t *)usb_str_table.serial_number, usb_str_buf, length);
return usb_str_buf;
} }
static uint8_t *usb_get_configuration_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_configuration_str_descriptor(USBD_SpeedTypeDef speed,
USBD_GetString((uint8_t *)"", usb_str_buf, length); uint16_t *length) {
return usb_str_buf; USBD_GetString((uint8_t *)"", usb_str_buf, length);
return usb_str_buf;
} }
static uint8_t *usb_get_interface_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_interface_str_descriptor(USBD_SpeedTypeDef speed,
USBD_GetString((uint8_t *)usb_str_table.interface, usb_str_buf, length); uint16_t *length) {
return usb_str_buf; USBD_GetString((uint8_t *)usb_str_table.interface, usb_str_buf, length);
return usb_str_buf;
} }
static uint8_t *usb_get_bos_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { static uint8_t *usb_get_bos_descriptor(USBD_SpeedTypeDef speed,
if (sectrue == usb21_enabled) { uint16_t *length) {
static uint8_t bos[] = { if (sectrue == usb21_enabled) {
// usb_bos_descriptor { static uint8_t bos[] = {
0x05, // uint8_t bLength // usb_bos_descriptor {
USB_DESC_TYPE_BOS, // uint8_t bDescriptorType 0x05, // uint8_t bLength
0x1d, 0x0, // uint16_t wTotalLength USB_DESC_TYPE_BOS, // uint8_t bDescriptorType
0x01, // uint8_t bNumDeviceCaps 0x1d, 0x0, // uint16_t wTotalLength
// } 0x01, // uint8_t bNumDeviceCaps
// usb_device_capability_descriptor { // }
0x18, // uint8_t bLength // usb_device_capability_descriptor {
USB_DESC_TYPE_DEVICE_CAPABILITY, // uint8_t bDescriptorType 0x18, // uint8_t bLength
USB_DEVICE_CAPABILITY_PLATFORM, // uint8_t bDevCapabilityType USB_DESC_TYPE_DEVICE_CAPABILITY, // uint8_t bDescriptorType
0x00, // uint8_t bReserved USB_DEVICE_CAPABILITY_PLATFORM, // uint8_t bDevCapabilityType
0x38, 0xb6, 0x08, 0x34, 0xa9, 0x09, 0xa0, 0x47, 0x8b, 0xfd, 0xa0, 0x76, 0x88, 0x15, 0xb6, 0x65, // uint128_t platformCompatibilityUUID 0x00, // uint8_t bReserved
0x00, 0x01, // uint16_t bcdVersion 0x38, 0xb6, 0x08, 0x34, 0xa9, 0x09, 0xa0, 0x47, 0x8b, 0xfd, 0xa0, 0x76,
USB_WEBUSB_VENDOR_CODE, // uint8_t bVendorCode 0x88, 0x15, 0xb6, 0x65, // uint128_t platformCompatibilityUUID
USB_WEBUSB_LANDING_PAGE, // uint8_t iLandingPage 0x00, 0x01, // uint16_t bcdVersion
// } USB_WEBUSB_VENDOR_CODE, // uint8_t bVendorCode
}; USB_WEBUSB_LANDING_PAGE, // uint8_t iLandingPage
bos[28] = (sectrue == usb21_landing) ? USB_WEBUSB_LANDING_PAGE : 0; // }
*length = sizeof(bos); };
return UNCONST(bos); bos[28] = (sectrue == usb21_landing) ? USB_WEBUSB_LANDING_PAGE : 0;
} else { *length = sizeof(bos);
*length = 0; return UNCONST(bos);
return NULL; } else {
} *length = 0;
return NULL;
}
} }
static const USBD_DescriptorsTypeDef usb_descriptors = { static const USBD_DescriptorsTypeDef usb_descriptors = {
.GetDeviceDescriptor = usb_get_dev_descriptor, .GetDeviceDescriptor = usb_get_dev_descriptor,
.GetLangIDStrDescriptor = usb_get_langid_str_descriptor, .GetLangIDStrDescriptor = usb_get_langid_str_descriptor,
.GetManufacturerStrDescriptor = usb_get_manufacturer_str_descriptor, .GetManufacturerStrDescriptor = usb_get_manufacturer_str_descriptor,
.GetProductStrDescriptor = usb_get_product_str_descriptor, .GetProductStrDescriptor = usb_get_product_str_descriptor,
.GetSerialStrDescriptor = usb_get_serial_str_descriptor, .GetSerialStrDescriptor = usb_get_serial_str_descriptor,
.GetConfigurationStrDescriptor = usb_get_configuration_str_descriptor, .GetConfigurationStrDescriptor = usb_get_configuration_str_descriptor,
.GetInterfaceStrDescriptor = usb_get_interface_str_descriptor, .GetInterfaceStrDescriptor = usb_get_interface_str_descriptor,
.GetBOSDescriptor = usb_get_bos_descriptor, .GetBOSDescriptor = usb_get_bos_descriptor,
}; };
/* /*
@ -271,233 +299,267 @@ static const USBD_DescriptorsTypeDef usb_descriptors = {
*/ */
static uint8_t usb_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { static uint8_t usb_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) {
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) { switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID: case USB_IFACE_TYPE_HID:
usb_hid_class_init(dev, &usb_ifaces[i].hid, cfg_idx); usb_hid_class_init(dev, &usb_ifaces[i].hid, cfg_idx);
break; break;
case USB_IFACE_TYPE_VCP: case USB_IFACE_TYPE_VCP:
usb_vcp_class_init(dev, &usb_ifaces[i].vcp, cfg_idx); usb_vcp_class_init(dev, &usb_ifaces[i].vcp, cfg_idx);
break; break;
case USB_IFACE_TYPE_WEBUSB: case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_init(dev, &usb_ifaces[i].webusb, cfg_idx); usb_webusb_class_init(dev, &usb_ifaces[i].webusb, cfg_idx);
break; break;
default: default:
break; break;
}
} }
return USBD_OK; }
return USBD_OK;
} }
static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) {
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) { switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID: case USB_IFACE_TYPE_HID:
usb_hid_class_deinit(dev, &usb_ifaces[i].hid, cfg_idx); usb_hid_class_deinit(dev, &usb_ifaces[i].hid, cfg_idx);
break; break;
case USB_IFACE_TYPE_VCP: case USB_IFACE_TYPE_VCP:
usb_vcp_class_deinit(dev, &usb_ifaces[i].vcp, cfg_idx); usb_vcp_class_deinit(dev, &usb_ifaces[i].vcp, cfg_idx);
break; break;
case USB_IFACE_TYPE_WEBUSB: case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_deinit(dev, &usb_ifaces[i].webusb, cfg_idx); usb_webusb_class_deinit(dev, &usb_ifaces[i].webusb, cfg_idx);
break; break;
default: default:
break; break;
}
} }
return USBD_OK; }
return USBD_OK;
} }
#define USB_WEBUSB_REQ_GET_URL 0x02 #define USB_WEBUSB_REQ_GET_URL 0x02
#define USB_WEBUSB_DESCRIPTOR_TYPE_URL 0x03 #define USB_WEBUSB_DESCRIPTOR_TYPE_URL 0x03
#define USB_WEBUSB_URL_SCHEME_HTTP 0 #define USB_WEBUSB_URL_SCHEME_HTTP 0
#define USB_WEBUSB_URL_SCHEME_HTTPS 1 #define USB_WEBUSB_URL_SCHEME_HTTPS 1
static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_SetupReqTypedef *req) { static uint8_t usb_class_setup(USBD_HandleTypeDef *dev,
delay_random(); USBD_SetupReqTypedef *req) {
if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) && delay_random();
((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) && if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) &&
((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_VENDOR)) { ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) &&
return USBD_OK; ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_VENDOR)) {
} return USBD_OK;
}
if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_VENDOR) {
if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) { if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_VENDOR) {
if (sectrue == usb21_enabled && req->bRequest == USB_WEBUSB_VENDOR_CODE) { if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) {
if (req->wIndex == USB_WEBUSB_REQ_GET_URL && req->wValue == USB_WEBUSB_LANDING_PAGE) { if (sectrue == usb21_enabled && req->bRequest == USB_WEBUSB_VENDOR_CODE) {
static const char webusb_url[] = { if (req->wIndex == USB_WEBUSB_REQ_GET_URL &&
3 + 15, // uint8_t bLength req->wValue == USB_WEBUSB_LANDING_PAGE) {
USB_WEBUSB_DESCRIPTOR_TYPE_URL, // uint8_t bDescriptorType static const char webusb_url[] = {
USB_WEBUSB_URL_SCHEME_HTTPS, // uint8_t bScheme 3 + 15, // uint8_t bLength
't', 'r', 'e', 'z', 'o', 'r', '.', 'i', 'o', '/', 's', 't', 'a', 'r', 't', // char URL[] USB_WEBUSB_DESCRIPTOR_TYPE_URL, // uint8_t bDescriptorType
}; USB_WEBUSB_URL_SCHEME_HTTPS, // uint8_t bScheme
USBD_CtlSendData(dev, UNCONST(webusb_url), MIN_8bits(req->wLength, sizeof(webusb_url))); 't',
return USBD_OK; 'r',
} else { 'e',
USBD_CtlError(dev, req); 'z',
return USBD_FAIL; 'o',
} 'r',
} '.',
else 'i',
if (sectrue == usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) { 'o',
if (req->wIndex == USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR) { '/',
static const uint8_t winusb_wcid[] = { 's',
// header 't',
0x28, 0x00, 0x00, 0x00, // dwLength 'a',
0x00, 0x01, // bcdVersion 'r',
0x04, 0x00, // wIndex 't', // char URL[]
0x01, // bNumSections };
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved USBD_CtlSendData(dev, UNCONST(webusb_url),
// functions MIN_8bits(req->wLength, sizeof(webusb_url)));
0x00, // bInterfaceNumber - HACK: we present only interface 0 as WinUSB return USBD_OK;
0x01, // reserved } else {
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatibleId USBD_CtlError(dev, req);
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompatibleId return USBD_FAIL;
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
};
USBD_CtlSendData(dev, UNCONST(winusb_wcid), MIN_8bits(req->wLength, sizeof(winusb_wcid)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
}
}
}
if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE) {
if (sectrue == usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) {
if (req->wIndex == USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR &&
(req->wValue & 0xFF) == 0) { // reply only if interface is 0
static const uint8_t winusb_guid[] = {
// header
0x92, 0x00, 0x00, 0x00, // dwLength
0x00, 0x01, // bcdVersion
0x05, 0x00, // wIndex
0x01, 0x00, // wNumFeatures
// features
0x88, 0x00, 0x00, 0x00, // dwLength
0x07, 0x00, 0x00, 0x00, // dwPropertyDataType
0x2A, 0x00, // wNameLength
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, // .name
0x50, 0x00, 0x00, 0x00, // dwPropertyDataLength
'{', 0x00, 'c', 0x00, '6', 0x00, 'c', 0x00, '3', 0x00, '7', 0x00, '4', 0x00, 'a', 0x00, '6', 0x00, '-', 0x00, '2', 0x00, '2', 0x00, '8', 0x00, '5', 0x00, '-', 0x00, '4', 0x00, 'c', 0x00, 'b', 0x00, '8', 0x00, '-', 0x00, 'a', 0x00, 'b', 0x00, '4', 0x00, '3', 0x00, '-', 0x00, '1', 0x00, '7', 0x00, '6', 0x00, '4', 0x00, '7', 0x00, 'c', 0x00, 'e', 0x00, 'a', 0x00, '5', 0x00, '0', 0x00, '3', 0x00, 'd', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00, // propertyData
};
USBD_CtlSendData(dev, UNCONST(winusb_guid), MIN_8bits(req->wLength, sizeof(winusb_guid)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
}
}
} }
} else } else if (sectrue == usb21_enabled &&
if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE) { req->bRequest == USB_WINUSB_VENDOR_CODE) {
if (req->wIndex >= USBD_MAX_NUM_INTERFACES) { if (req->wIndex ==
USBD_CtlError(dev, req); USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR) {
return USBD_FAIL; static const uint8_t winusb_wcid[] = {
// header
0x28, 0x00, 0x00, 0x00, // dwLength
0x00, 0x01, // bcdVersion
0x04, 0x00, // wIndex
0x01, // bNumSections
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
// functions
0x00, // bInterfaceNumber - HACK: we present only interface 0 as
// WinUSB
0x01, // reserved
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatibleId
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, // subCompatibleId
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
};
USBD_CtlSendData(dev, UNCONST(winusb_wcid),
MIN_8bits(req->wLength, sizeof(winusb_wcid)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
} }
switch (usb_ifaces[req->wIndex].type) { }
case USB_IFACE_TYPE_HID: }
return usb_hid_class_setup(dev, &usb_ifaces[req->wIndex].hid, req); if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) ==
case USB_IFACE_TYPE_VCP: USB_REQ_RECIPIENT_INTERFACE) {
return usb_vcp_class_setup(dev, &usb_ifaces[req->wIndex].vcp, req); if (sectrue == usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) {
case USB_IFACE_TYPE_WEBUSB: if (req->wIndex ==
return usb_webusb_class_setup(dev, &usb_ifaces[req->wIndex].webusb, req); USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR &&
default: (req->wValue & 0xFF) == 0) { // reply only if interface is 0
USBD_CtlError(dev, req); static const uint8_t winusb_guid[] = {
return USBD_FAIL; // header
0x92, 0x00, 0x00, 0x00, // dwLength
0x00, 0x01, // bcdVersion
0x05, 0x00, // wIndex
0x01, 0x00, // wNumFeatures
// features
0x88, 0x00, 0x00, 0x00, // dwLength
0x07, 0x00, 0x00, 0x00, // dwPropertyDataType
0x2A, 0x00, // wNameLength
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00,
'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00,
'D', 0x00, 's', 0x00, 0x00, 0x00, // .name
0x50, 0x00, 0x00, 0x00, // dwPropertyDataLength
'{', 0x00, 'c', 0x00, '6', 0x00, 'c', 0x00, '3', 0x00, '7', 0x00,
'4', 0x00, 'a', 0x00, '6', 0x00, '-', 0x00, '2', 0x00, '2', 0x00,
'8', 0x00, '5', 0x00, '-', 0x00, '4', 0x00, 'c', 0x00, 'b', 0x00,
'8', 0x00, '-', 0x00, 'a', 0x00, 'b', 0x00, '4', 0x00, '3', 0x00,
'-', 0x00, '1', 0x00, '7', 0x00, '6', 0x00, '4', 0x00, '7', 0x00,
'c', 0x00, 'e', 0x00, 'a', 0x00, '5', 0x00, '0', 0x00, '3', 0x00,
'd', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00, // propertyData
};
USBD_CtlSendData(dev, UNCONST(winusb_guid),
MIN_8bits(req->wLength, sizeof(winusb_guid)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
} }
}
} }
return USBD_OK; } else if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_INTERFACE) {
if (req->wIndex >= USBD_MAX_NUM_INTERFACES) {
USBD_CtlError(dev, req);
return USBD_FAIL;
}
switch (usb_ifaces[req->wIndex].type) {
case USB_IFACE_TYPE_HID:
return usb_hid_class_setup(dev, &usb_ifaces[req->wIndex].hid, req);
case USB_IFACE_TYPE_VCP:
return usb_vcp_class_setup(dev, &usb_ifaces[req->wIndex].vcp, req);
case USB_IFACE_TYPE_WEBUSB:
return usb_webusb_class_setup(dev, &usb_ifaces[req->wIndex].webusb,
req);
default:
USBD_CtlError(dev, req);
return USBD_FAIL;
}
}
return USBD_OK;
} }
static uint8_t usb_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { static uint8_t usb_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) {
delay_random(); delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) { switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID: case USB_IFACE_TYPE_HID:
usb_hid_class_data_in(dev, &usb_ifaces[i].hid, ep_num); usb_hid_class_data_in(dev, &usb_ifaces[i].hid, ep_num);
break; break;
case USB_IFACE_TYPE_VCP: case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_in(dev, &usb_ifaces[i].vcp, ep_num); usb_vcp_class_data_in(dev, &usb_ifaces[i].vcp, ep_num);
break; break;
case USB_IFACE_TYPE_WEBUSB: case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_in(dev, &usb_ifaces[i].webusb, ep_num); usb_webusb_class_data_in(dev, &usb_ifaces[i].webusb, ep_num);
break; break;
default: default:
break; break;
}
} }
return USBD_OK; }
return USBD_OK;
} }
static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) {
delay_random(); delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) { switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID: case USB_IFACE_TYPE_HID:
usb_hid_class_data_out(dev, &usb_ifaces[i].hid, ep_num); usb_hid_class_data_out(dev, &usb_ifaces[i].hid, ep_num);
break; break;
case USB_IFACE_TYPE_VCP: case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_out(dev, &usb_ifaces[i].vcp, ep_num); usb_vcp_class_data_out(dev, &usb_ifaces[i].vcp, ep_num);
break; break;
case USB_IFACE_TYPE_WEBUSB: case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_out(dev, &usb_ifaces[i].webusb, ep_num); usb_webusb_class_data_out(dev, &usb_ifaces[i].webusb, ep_num);
break; break;
default: default:
break; break;
}
} }
return USBD_OK; }
return USBD_OK;
} }
static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) { static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) {
delay_random(); delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) { switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_VCP: case USB_IFACE_TYPE_VCP:
usb_vcp_class_sof(dev, &usb_ifaces[i].vcp); usb_vcp_class_sof(dev, &usb_ifaces[i].vcp);
break; break;
default: default:
break; break;
}
} }
return USBD_OK; }
return USBD_OK;
} }
static uint8_t *usb_class_get_cfg_desc(uint16_t *length) { static uint8_t *usb_class_get_cfg_desc(uint16_t *length) {
*length = usb_config_desc->wTotalLength; *length = usb_config_desc->wTotalLength;
return usb_config_buf; return usb_config_buf;
} }
static uint8_t *usb_class_get_usrstr_desc(USBD_HandleTypeDef *dev, uint8_t index, uint16_t *length) { static uint8_t *usb_class_get_usrstr_desc(USBD_HandleTypeDef *dev,
if (sectrue == usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) { uint8_t index, uint16_t *length) {
static const uint8_t winusb_string_descriptor[] = { if (sectrue == usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) {
0x12, // bLength static const uint8_t winusb_string_descriptor[] = {
USB_DESC_TYPE_STRING, // bDescriptorType 0x12, // bLength
USB_WINUSB_EXTRA_STRING // wData USB_DESC_TYPE_STRING, // bDescriptorType
}; USB_WINUSB_EXTRA_STRING // wData
*length = sizeof(winusb_string_descriptor); };
return UNCONST(winusb_string_descriptor); *length = sizeof(winusb_string_descriptor);
} else { return UNCONST(winusb_string_descriptor);
*length = 0; } else {
return NULL; *length = 0;
} return NULL;
}
} }
static const USBD_ClassTypeDef usb_class = { static const USBD_ClassTypeDef usb_class = {
.Init = usb_class_init, .Init = usb_class_init,
.DeInit = usb_class_deinit, .DeInit = usb_class_deinit,
.Setup = usb_class_setup, .Setup = usb_class_setup,
.EP0_TxSent = NULL, .EP0_TxSent = NULL,
.EP0_RxReady = NULL, .EP0_RxReady = NULL,
.DataIn = usb_class_data_in, .DataIn = usb_class_data_in,
.DataOut = usb_class_data_out, .DataOut = usb_class_data_out,
.SOF = usb_class_sof, .SOF = usb_class_sof,
.IsoINIncomplete = NULL, .IsoINIncomplete = NULL,
.IsoOUTIncomplete = NULL, .IsoOUTIncomplete = NULL,
.GetHSConfigDescriptor = usb_class_get_cfg_desc, .GetHSConfigDescriptor = usb_class_get_cfg_desc,
.GetFSConfigDescriptor = usb_class_get_cfg_desc, .GetFSConfigDescriptor = usb_class_get_cfg_desc,
.GetOtherSpeedConfigDescriptor = usb_class_get_cfg_desc, .GetOtherSpeedConfigDescriptor = usb_class_get_cfg_desc,
.GetDeviceQualifierDescriptor = NULL, .GetDeviceQualifierDescriptor = NULL,
.GetUsrStrDescriptor = usb_class_get_usrstr_desc, .GetUsrStrDescriptor = usb_class_get_usrstr_desc,
}; };

@ -23,107 +23,107 @@
#include <stdint.h> #include <stdint.h>
#include "secbool.h" #include "secbool.h"
#define USB_EP_DIR_MASK 0x80 #define USB_EP_DIR_MASK 0x80
#define USB_EP_DIR_OUT 0x00 #define USB_EP_DIR_OUT 0x00
#define USB_EP_DIR_IN 0x80 #define USB_EP_DIR_IN 0x80
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t bcdUSB; uint16_t bcdUSB;
uint8_t bDeviceClass; uint8_t bDeviceClass;
uint8_t bDeviceSubClass; uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol; uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0; uint8_t bMaxPacketSize0;
uint16_t idVendor; uint16_t idVendor;
uint16_t idProduct; uint16_t idProduct;
uint16_t bcdDevice; uint16_t bcdDevice;
uint8_t iManufacturer; uint8_t iManufacturer;
uint8_t iProduct; uint8_t iProduct;
uint8_t iSerialNumber; uint8_t iSerialNumber;
uint8_t bNumConfigurations; uint8_t bNumConfigurations;
} usb_device_descriptor_t; } usb_device_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t wData; uint16_t wData;
} usb_langid_descriptor_t; } usb_langid_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t wTotalLength; uint16_t wTotalLength;
uint8_t bNumInterfaces; uint8_t bNumInterfaces;
uint8_t bConfigurationValue; uint8_t bConfigurationValue;
uint8_t iConfiguration; uint8_t iConfiguration;
uint8_t bmAttributes; uint8_t bmAttributes;
uint8_t bMaxPower; uint8_t bMaxPower;
} usb_config_descriptor_t; } usb_config_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bInterfaceNumber; uint8_t bInterfaceNumber;
uint8_t bAlternateSetting; uint8_t bAlternateSetting;
uint8_t bNumEndpoints; uint8_t bNumEndpoints;
uint8_t bInterfaceClass; uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass; uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol; uint8_t bInterfaceProtocol;
uint8_t iInterface; uint8_t iInterface;
} usb_interface_descriptor_t; } usb_interface_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bFirstInterface; uint8_t bFirstInterface;
uint8_t bInterfaceCount; uint8_t bInterfaceCount;
uint8_t bFunctionClass; uint8_t bFunctionClass;
uint8_t bFunctionSubClass; uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol; uint8_t bFunctionProtocol;
uint8_t iFunction; uint8_t iFunction;
} usb_interface_assoc_descriptor_t; } usb_interface_assoc_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bEndpointAddress; uint8_t bEndpointAddress;
uint8_t bmAttributes; uint8_t bmAttributes;
uint16_t wMaxPacketSize; uint16_t wMaxPacketSize;
uint8_t bInterval; uint8_t bInterval;
} usb_endpoint_descriptor_t; } usb_endpoint_descriptor_t;
typedef enum { typedef enum {
USB_LANGID_ENGLISH_US = 0x409, USB_LANGID_ENGLISH_US = 0x409,
} usb_language_id_t; } usb_language_id_t;
typedef struct { typedef struct {
const char *manufacturer; const char *manufacturer;
const char *product; const char *product;
const char *serial_number; const char *serial_number;
const char *interface; const char *interface;
} usb_dev_string_table_t; } usb_dev_string_table_t;
typedef struct { typedef struct {
uint8_t device_class; uint8_t device_class;
uint8_t device_subclass; uint8_t device_subclass;
uint8_t device_protocol; uint8_t device_protocol;
uint16_t vendor_id; uint16_t vendor_id;
uint16_t product_id; uint16_t product_id;
uint16_t release_num; uint16_t release_num;
const char *manufacturer; const char *manufacturer;
const char *product; const char *product;
const char *serial_number; const char *serial_number;
const char *interface; const char *interface;
secbool usb21_enabled; secbool usb21_enabled;
secbool usb21_landing; secbool usb21_landing;
} usb_dev_info_t; } usb_dev_info_t;
typedef enum { typedef enum {
USB_IFACE_TYPE_DISABLED = 0, USB_IFACE_TYPE_DISABLED = 0,
USB_IFACE_TYPE_VCP = 1, USB_IFACE_TYPE_VCP = 1,
USB_IFACE_TYPE_HID = 2, USB_IFACE_TYPE_HID = 2,
USB_IFACE_TYPE_WEBUSB = 3, USB_IFACE_TYPE_WEBUSB = 3,
} usb_iface_type_t; } usb_iface_type_t;
#include "usb_hid-defs.h" #include "usb_hid-defs.h"
@ -131,12 +131,12 @@ typedef enum {
#include "usb_webusb-defs.h" #include "usb_webusb-defs.h"
typedef struct { typedef struct {
union { union {
usb_hid_state_t hid; usb_hid_state_t hid;
usb_vcp_state_t vcp; usb_vcp_state_t vcp;
usb_webusb_state_t webusb; usb_webusb_state_t webusb;
}; };
usb_iface_type_t type; usb_iface_type_t type;
} usb_iface_t; } usb_iface_t;
void usb_init(const usb_dev_info_t *dev_info); void usb_init(const usb_dev_info_t *dev_info);

@ -18,36 +18,36 @@
*/ */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t bcdHID; uint16_t bcdHID;
uint8_t bCountryCode; uint8_t bCountryCode;
uint8_t bNumDescriptors; uint8_t bNumDescriptors;
uint8_t bReportDescriptorType; uint8_t bReportDescriptorType;
uint16_t wReportDescriptorLength; uint16_t wReportDescriptorLength;
} usb_hid_descriptor_t; } usb_hid_descriptor_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
usb_interface_descriptor_t iface; usb_interface_descriptor_t iface;
usb_hid_descriptor_t hid; usb_hid_descriptor_t hid;
usb_endpoint_descriptor_t ep_in; usb_endpoint_descriptor_t ep_in;
usb_endpoint_descriptor_t ep_out; usb_endpoint_descriptor_t ep_out;
} usb_hid_descriptor_block_t; } usb_hid_descriptor_block_t;
/* usb_hid_info_t contains all information for setting up a HID interface. All /* usb_hid_info_t contains all information for setting up a HID interface. All
* passed pointers need to live at least until the interface is disabled * passed pointers need to live at least until the interface is disabled
* (usb_stop is called). */ * (usb_stop is called). */
typedef struct { typedef struct {
const uint8_t *report_desc; // With length of report_desc_len bytes const uint8_t *report_desc; // With length of report_desc_len bytes
uint8_t *rx_buffer; // With length of max_packet_len bytes uint8_t *rx_buffer; // With length of max_packet_len bytes
uint8_t iface_num; // Address of this HID interface uint8_t iface_num; // Address of this HID interface
uint8_t ep_in; // Address of IN endpoint (with the highest bit set) uint8_t ep_in; // Address of IN endpoint (with the highest bit set)
uint8_t ep_out; // Address of OUT endpoint uint8_t ep_out; // Address of OUT endpoint
uint8_t subclass; // usb_iface_subclass_t uint8_t subclass; // usb_iface_subclass_t
uint8_t protocol; // usb_iface_protocol_t uint8_t protocol; // usb_iface_protocol_t
uint8_t polling_interval; // In units of 1ms uint8_t polling_interval; // In units of 1ms
uint8_t max_packet_len; // Length of the biggest report and of rx_buffer uint8_t max_packet_len; // Length of the biggest report and of rx_buffer
uint8_t report_desc_len; // Length of report_desc uint8_t report_desc_len; // Length of report_desc
} usb_hid_info_t; } usb_hid_info_t;
/* usb_hid_state_t encapsulates all state used by enabled HID interface. It /* usb_hid_state_t encapsulates all state used by enabled HID interface. It
@ -55,19 +55,19 @@ typedef struct {
* usb_hid_class_init. See usb_hid_info_t for details of the configuration * usb_hid_class_init. See usb_hid_info_t for details of the configuration
* fields. */ * fields. */
typedef struct { typedef struct {
const usb_hid_descriptor_block_t *desc_block; const usb_hid_descriptor_block_t *desc_block;
const uint8_t *report_desc; const uint8_t *report_desc;
uint8_t *rx_buffer; uint8_t *rx_buffer;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_out; uint8_t ep_out;
uint8_t max_packet_len; uint8_t max_packet_len;
uint8_t report_desc_len; uint8_t report_desc_len;
uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs
uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs
uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs
uint8_t last_read_len; // Length of data read into rx_buffer uint8_t last_read_len; // Length of data read into rx_buffer
uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle
} usb_hid_state_t; } usb_hid_state_t;
secbool __wur usb_hid_add(const usb_hid_info_t *hid_info); secbool __wur usb_hid_add(const usb_hid_info_t *hid_info);
@ -77,5 +77,7 @@ int __wur usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len);
int __wur usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len); int __wur usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len);
int __wur usb_hid_read_select(uint32_t timeout); int __wur usb_hid_read_select(uint32_t timeout);
int __wur usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, int timeout); int __wur usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len,
int __wur usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, int timeout); int timeout);
int __wur usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf,
uint32_t len, int timeout);

@ -17,330 +17,340 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define USB_CLASS_HID 0x03 #define USB_CLASS_HID 0x03
#define USB_DESC_TYPE_HID 0x21 #define USB_DESC_TYPE_HID 0x21
#define USB_DESC_TYPE_REPORT 0x22 #define USB_DESC_TYPE_REPORT 0x22
#define USB_HID_REQ_SET_PROTOCOL 0x0B #define USB_HID_REQ_SET_PROTOCOL 0x0B
#define USB_HID_REQ_GET_PROTOCOL 0x03 #define USB_HID_REQ_GET_PROTOCOL 0x03
#define USB_HID_REQ_SET_IDLE 0x0A #define USB_HID_REQ_SET_IDLE 0x0A
#define USB_HID_REQ_GET_IDLE 0x02 #define USB_HID_REQ_GET_IDLE 0x02
/* usb_hid_add adds and configures new USB HID interface according to /* usb_hid_add adds and configures new USB HID interface according to
* configuration options passed in `info`. */ * configuration options passed in `info`. */
secbool usb_hid_add(const usb_hid_info_t *info) { secbool usb_hid_add(const usb_hid_info_t *info) {
usb_iface_t *iface = usb_get_iface(info->iface_num);
usb_iface_t *iface = usb_get_iface(info->iface_num);
if (iface == NULL) {
if (iface == NULL) { return secfalse; // Invalid interface number
return secfalse; // Invalid interface number }
} if (iface->type != USB_IFACE_TYPE_DISABLED) {
if (iface->type != USB_IFACE_TYPE_DISABLED) { return secfalse; // Interface is already enabled
return secfalse; // Interface is already enabled }
}
usb_hid_descriptor_block_t *d =
usb_hid_descriptor_block_t *d = usb_desc_alloc_iface(sizeof(usb_hid_descriptor_block_t)); usb_desc_alloc_iface(sizeof(usb_hid_descriptor_block_t));
if (d == NULL) { if (d == NULL) {
return secfalse; // Not enough space in the configuration descriptor return secfalse; // Not enough space in the configuration descriptor
} }
if ((info->ep_in & USB_EP_DIR_MASK) != USB_EP_DIR_IN) { if ((info->ep_in & USB_EP_DIR_MASK) != USB_EP_DIR_IN) {
return secfalse; // IN EP is invalid return secfalse; // IN EP is invalid
} }
if ((info->ep_out & USB_EP_DIR_MASK) != USB_EP_DIR_OUT) { if ((info->ep_out & USB_EP_DIR_MASK) != USB_EP_DIR_OUT) {
return secfalse; // OUT EP is invalid return secfalse; // OUT EP is invalid
} }
if (info->rx_buffer == NULL) { if (info->rx_buffer == NULL) {
return secfalse; return secfalse;
} }
if (info->report_desc == NULL) { if (info->report_desc == NULL) {
return secfalse; return secfalse;
} }
// Interface descriptor // Interface descriptor
d->iface.bLength = sizeof(usb_interface_descriptor_t); d->iface.bLength = sizeof(usb_interface_descriptor_t);
d->iface.bDescriptorType = USB_DESC_TYPE_INTERFACE; d->iface.bDescriptorType = USB_DESC_TYPE_INTERFACE;
d->iface.bInterfaceNumber = info->iface_num; d->iface.bInterfaceNumber = info->iface_num;
d->iface.bAlternateSetting = 0; d->iface.bAlternateSetting = 0;
d->iface.bNumEndpoints = 2; d->iface.bNumEndpoints = 2;
d->iface.bInterfaceClass = USB_CLASS_HID; d->iface.bInterfaceClass = USB_CLASS_HID;
d->iface.bInterfaceSubClass = info->subclass; d->iface.bInterfaceSubClass = info->subclass;
d->iface.bInterfaceProtocol = info->protocol; d->iface.bInterfaceProtocol = info->protocol;
d->iface.iInterface = USBD_IDX_INTERFACE_STR; d->iface.iInterface = USBD_IDX_INTERFACE_STR;
// HID descriptor // HID descriptor
d->hid.bLength = sizeof(usb_hid_descriptor_t); d->hid.bLength = sizeof(usb_hid_descriptor_t);
d->hid.bDescriptorType = USB_DESC_TYPE_HID; d->hid.bDescriptorType = USB_DESC_TYPE_HID;
d->hid.bcdHID = 0x0111; // HID Class Spec release number (1.11) d->hid.bcdHID = 0x0111; // HID Class Spec release number (1.11)
d->hid.bCountryCode = 0; // Hardware target country d->hid.bCountryCode = 0; // Hardware target country
d->hid.bNumDescriptors = 1; // Number of HID class descriptors d->hid.bNumDescriptors = 1; // Number of HID class descriptors
d->hid.bReportDescriptorType = USB_DESC_TYPE_REPORT; d->hid.bReportDescriptorType = USB_DESC_TYPE_REPORT;
d->hid.wReportDescriptorLength = info->report_desc_len; d->hid.wReportDescriptorLength = info->report_desc_len;
// IN endpoint (sending) // IN endpoint (sending)
d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t);
d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT; d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT;
d->ep_in.bEndpointAddress = info->ep_in; d->ep_in.bEndpointAddress = info->ep_in;
d->ep_in.bmAttributes = USBD_EP_TYPE_INTR; d->ep_in.bmAttributes = USBD_EP_TYPE_INTR;
d->ep_in.wMaxPacketSize = info->max_packet_len; d->ep_in.wMaxPacketSize = info->max_packet_len;
d->ep_in.bInterval = info->polling_interval; d->ep_in.bInterval = info->polling_interval;
// OUT endpoint (receiving) // OUT endpoint (receiving)
d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t);
d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT; d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT;
d->ep_out.bEndpointAddress = info->ep_out; d->ep_out.bEndpointAddress = info->ep_out;
d->ep_out.bmAttributes = USBD_EP_TYPE_INTR; d->ep_out.bmAttributes = USBD_EP_TYPE_INTR;
d->ep_out.wMaxPacketSize = info->max_packet_len; d->ep_out.wMaxPacketSize = info->max_packet_len;
d->ep_out.bInterval = info->polling_interval; d->ep_out.bInterval = info->polling_interval;
// Config descriptor // Config descriptor
usb_desc_add_iface(sizeof(usb_hid_descriptor_block_t)); usb_desc_add_iface(sizeof(usb_hid_descriptor_block_t));
// Interface state // Interface state
iface->type = USB_IFACE_TYPE_HID; iface->type = USB_IFACE_TYPE_HID;
iface->hid.desc_block = d; iface->hid.desc_block = d;
iface->hid.report_desc = info->report_desc; iface->hid.report_desc = info->report_desc;
iface->hid.rx_buffer = info->rx_buffer; iface->hid.rx_buffer = info->rx_buffer;
iface->hid.ep_in = info->ep_in; iface->hid.ep_in = info->ep_in;
iface->hid.ep_out = info->ep_out; iface->hid.ep_out = info->ep_out;
iface->hid.max_packet_len = info->max_packet_len; iface->hid.max_packet_len = info->max_packet_len;
iface->hid.report_desc_len = info->report_desc_len; iface->hid.report_desc_len = info->report_desc_len;
iface->hid.protocol = 0; iface->hid.protocol = 0;
iface->hid.idle_rate = 0; iface->hid.idle_rate = 0;
iface->hid.alt_setting = 0; iface->hid.alt_setting = 0;
iface->hid.last_read_len = 0; iface->hid.last_read_len = 0;
iface->hid.ep_in_is_idle = 1; iface->hid.ep_in_is_idle = 1;
return sectrue; return sectrue;
} }
secbool usb_hid_can_read(uint8_t iface_num) { secbool usb_hid_can_read(uint8_t iface_num) {
usb_iface_t *iface = usb_get_iface(iface_num); usb_iface_t *iface = usb_get_iface(iface_num);
if (iface == NULL) { if (iface == NULL) {
return secfalse; // Invalid interface number return secfalse; // Invalid interface number
} }
if (iface->type != USB_IFACE_TYPE_HID) { if (iface->type != USB_IFACE_TYPE_HID) {
return secfalse; // Invalid interface type return secfalse; // Invalid interface type
} }
if (iface->hid.last_read_len == 0) { if (iface->hid.last_read_len == 0) {
return secfalse; // Nothing in the receiving buffer return secfalse; // Nothing in the receiving buffer
} }
if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) {
return secfalse; // Device is not configured return secfalse; // Device is not configured
} }
return sectrue; return sectrue;
} }
secbool usb_hid_can_write(uint8_t iface_num) { secbool usb_hid_can_write(uint8_t iface_num) {
usb_iface_t *iface = usb_get_iface(iface_num); usb_iface_t *iface = usb_get_iface(iface_num);
if (iface == NULL) { if (iface == NULL) {
return secfalse; // Invalid interface number return secfalse; // Invalid interface number
} }
if (iface->type != USB_IFACE_TYPE_HID) { if (iface->type != USB_IFACE_TYPE_HID) {
return secfalse; // Invalid interface type return secfalse; // Invalid interface type
} }
if (iface->hid.ep_in_is_idle == 0) { if (iface->hid.ep_in_is_idle == 0) {
return secfalse; // Last transmission is not over yet return secfalse; // Last transmission is not over yet
} }
if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) {
return secfalse; // Device is not configured return secfalse; // Device is not configured
} }
return sectrue; return sectrue;
} }
int usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { int usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len) {
usb_iface_t *iface = usb_get_iface(iface_num); usb_iface_t *iface = usb_get_iface(iface_num);
if (iface == NULL) { if (iface == NULL) {
return -1; // Invalid interface number return -1; // Invalid interface number
} }
if (iface->type != USB_IFACE_TYPE_HID) { if (iface->type != USB_IFACE_TYPE_HID) {
return -2; // Invalid interface type return -2; // Invalid interface type
} }
usb_hid_state_t *state = &iface->hid; usb_hid_state_t *state = &iface->hid;
// Copy maximum possible amount of data and truncate the buffer length // Copy maximum possible amount of data and truncate the buffer length
if (len < state->last_read_len) { if (len < state->last_read_len) {
return 0; // Not enough data in the read buffer return 0; // Not enough data in the read buffer
} }
len = state->last_read_len; len = state->last_read_len;
state->last_read_len = 0; state->last_read_len = 0;
memcpy(buf, state->rx_buffer, len); memcpy(buf, state->rx_buffer, len);
// Clear NAK to indicate we are ready to read more data // Clear NAK to indicate we are ready to read more data
usb_ep_clear_nak(&usb_dev_handle, state->ep_out); usb_ep_clear_nak(&usb_dev_handle, state->ep_out);
return len; return len;
} }
int usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { int usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) {
usb_iface_t *iface = usb_get_iface(iface_num); usb_iface_t *iface = usb_get_iface(iface_num);
if (iface == NULL) { if (iface == NULL) {
return -1; // Invalid interface number return -1; // Invalid interface number
} }
if (iface->type != USB_IFACE_TYPE_HID) { if (iface->type != USB_IFACE_TYPE_HID) {
return -2; // Invalid interface type return -2; // Invalid interface type
} }
usb_hid_state_t *state = &iface->hid; usb_hid_state_t *state = &iface->hid;
state->ep_in_is_idle = 0; state->ep_in_is_idle = 0;
USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len); USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len);
return len; return len;
} }
int usb_hid_read_select(uint32_t timeout) { int usb_hid_read_select(uint32_t timeout) {
const uint32_t start = HAL_GetTick(); const uint32_t start = HAL_GetTick();
for (;;) { for (;;) {
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
if (sectrue == usb_hid_can_read(i)) { if (sectrue == usb_hid_can_read(i)) {
return i; return i;
} }
} }
if (HAL_GetTick() - start >= timeout) { if (HAL_GetTick() - start >= timeout) {
break; break;
}
__WFI(); // Enter sleep mode, waiting for interrupt
} }
return -1; // Timeout __WFI(); // Enter sleep mode, waiting for interrupt
}
return -1; // Timeout
} }
int usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, int timeout) { int usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len,
const uint32_t start = HAL_GetTick(); int timeout) {
while (sectrue != usb_hid_can_read(iface_num)) { const uint32_t start = HAL_GetTick();
if (timeout >= 0 && HAL_GetTick() - start >= timeout) { while (sectrue != usb_hid_can_read(iface_num)) {
return 0; // Timeout if (timeout >= 0 && HAL_GetTick() - start >= timeout) {
} return 0; // Timeout
__WFI(); // Enter sleep mode, waiting for interrupt
} }
return usb_hid_read(iface_num, buf, len); __WFI(); // Enter sleep mode, waiting for interrupt
}
return usb_hid_read(iface_num, buf, len);
} }
int usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, int timeout) { int usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len,
const uint32_t start = HAL_GetTick(); int timeout) {
while (sectrue != usb_hid_can_write(iface_num)) { const uint32_t start = HAL_GetTick();
if (timeout >= 0 && HAL_GetTick() - start >= timeout) { while (sectrue != usb_hid_can_write(iface_num)) {
return 0; // Timeout if (timeout >= 0 && HAL_GetTick() - start >= timeout) {
} return 0; // Timeout
__WFI(); // Enter sleep mode, waiting for interrupt
} }
return usb_hid_write(iface_num, buf, len); __WFI(); // Enter sleep mode, waiting for interrupt
}
return usb_hid_write(iface_num, buf, len);
} }
static void usb_hid_class_init(USBD_HandleTypeDef *dev, usb_hid_state_t *state, uint8_t cfg_idx) { static void usb_hid_class_init(USBD_HandleTypeDef *dev, usb_hid_state_t *state,
// Open endpoints uint8_t cfg_idx) {
USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_INTR, state->max_packet_len); // Open endpoints
USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_INTR, state->max_packet_len); USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_INTR, state->max_packet_len);
USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_INTR, state->max_packet_len);
// Reset the state
state->protocol = 0; // Reset the state
state->idle_rate = 0; state->protocol = 0;
state->alt_setting = 0; state->idle_rate = 0;
state->last_read_len = 0; state->alt_setting = 0;
state->ep_in_is_idle = 1; state->last_read_len = 0;
state->ep_in_is_idle = 1;
// Prepare the OUT EP to receive next packet
USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_buffer, state->max_packet_len); // Prepare the OUT EP to receive next packet
USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_buffer,
state->max_packet_len);
} }
static void usb_hid_class_deinit(USBD_HandleTypeDef *dev, usb_hid_state_t *state, uint8_t cfg_idx) { static void usb_hid_class_deinit(USBD_HandleTypeDef *dev,
// Flush endpoints usb_hid_state_t *state, uint8_t cfg_idx) {
USBD_LL_FlushEP(dev, state->ep_in); // Flush endpoints
USBD_LL_FlushEP(dev, state->ep_out); USBD_LL_FlushEP(dev, state->ep_in);
// Close endpoints USBD_LL_FlushEP(dev, state->ep_out);
USBD_LL_CloseEP(dev, state->ep_in); // Close endpoints
USBD_LL_CloseEP(dev, state->ep_out); USBD_LL_CloseEP(dev, state->ep_in);
USBD_LL_CloseEP(dev, state->ep_out);
} }
static int usb_hid_class_setup(USBD_HandleTypeDef *dev, usb_hid_state_t *state, USBD_SetupReqTypedef *req) { static int usb_hid_class_setup(USBD_HandleTypeDef *dev, usb_hid_state_t *state,
switch (req->bmRequest & USB_REQ_TYPE_MASK) { USBD_SetupReqTypedef *req) {
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
// Class request // Class request
case USB_REQ_TYPE_CLASS: case USB_REQ_TYPE_CLASS:
switch (req->bRequest) { switch (req->bRequest) {
case USB_HID_REQ_SET_PROTOCOL:
case USB_HID_REQ_SET_PROTOCOL: state->protocol = req->wValue;
state->protocol = req->wValue; USBD_CtlSendStatus(dev);
USBD_CtlSendStatus(dev); return USBD_OK;
return USBD_OK;
case USB_HID_REQ_GET_PROTOCOL:
case USB_HID_REQ_GET_PROTOCOL: USBD_CtlSendData(dev, &state->protocol, sizeof(state->protocol));
USBD_CtlSendData(dev, &state->protocol, sizeof(state->protocol)); return USBD_OK;
return USBD_OK;
case USB_HID_REQ_SET_IDLE:
case USB_HID_REQ_SET_IDLE: state->idle_rate = req->wValue >> 8;
state->idle_rate = req->wValue >> 8; USBD_CtlSendStatus(dev);
USBD_CtlSendStatus(dev); return USBD_OK;
return USBD_OK;
case USB_HID_REQ_GET_IDLE:
case USB_HID_REQ_GET_IDLE: USBD_CtlSendData(dev, &state->idle_rate, sizeof(state->idle_rate));
USBD_CtlSendData(dev, &state->idle_rate, sizeof(state->idle_rate)); return USBD_OK;
return USBD_OK;
default:
default: USBD_CtlError(dev, req);
USBD_CtlError(dev, req); return USBD_FAIL;
return USBD_FAIL; }
} break;
break;
// Interface & Endpoint request
// Interface & Endpoint request case USB_REQ_TYPE_STANDARD:
case USB_REQ_TYPE_STANDARD: switch (req->bRequest) {
switch (req->bRequest) { case USB_REQ_SET_INTERFACE:
state->alt_setting = req->wValue;
case USB_REQ_SET_INTERFACE: USBD_CtlSendStatus(dev);
state->alt_setting = req->wValue; return USBD_OK;
USBD_CtlSendStatus(dev);
return USBD_OK; case USB_REQ_GET_INTERFACE:
USBD_CtlSendData(dev, &state->alt_setting,
case USB_REQ_GET_INTERFACE: sizeof(state->alt_setting));
USBD_CtlSendData(dev, &state->alt_setting, sizeof(state->alt_setting)); return USBD_OK;
return USBD_OK;
case USB_REQ_GET_DESCRIPTOR:
case USB_REQ_GET_DESCRIPTOR: switch (req->wValue >> 8) {
switch (req->wValue >> 8) { case USB_DESC_TYPE_HID:
USBD_CtlSendData(
case USB_DESC_TYPE_HID: dev, UNCONST(&state->desc_block->hid),
USBD_CtlSendData(dev, UNCONST(&state->desc_block->hid), MIN_8bits(req->wLength, sizeof(state->desc_block->hid))); MIN_8bits(req->wLength, sizeof(state->desc_block->hid)));
return USBD_OK; return USBD_OK;
case USB_DESC_TYPE_REPORT: case USB_DESC_TYPE_REPORT:
USBD_CtlSendData(dev, UNCONST(state->report_desc), MIN_8bits(req->wLength, state->report_desc_len)); USBD_CtlSendData(dev, UNCONST(state->report_desc),
return USBD_OK; MIN_8bits(req->wLength, state->report_desc_len));
return USBD_OK;
default:
USBD_CtlError(dev, req); default:
return USBD_FAIL; USBD_CtlError(dev, req);
} return USBD_FAIL;
break; }
break;
default:
USBD_CtlError(dev, req); default:
return USBD_FAIL; USBD_CtlError(dev, req);
} return USBD_FAIL;
break; }
} break;
}
return USBD_OK;
return USBD_OK;
} }
static void usb_hid_class_data_in(USBD_HandleTypeDef *dev, usb_hid_state_t *state, uint8_t ep_num) { static void usb_hid_class_data_in(USBD_HandleTypeDef *dev,
if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { usb_hid_state_t *state, uint8_t ep_num) {
state->ep_in_is_idle = 1; if ((ep_num | USB_EP_DIR_IN) == state->ep_in) {
} state->ep_in_is_idle = 1;
}
} }
static void usb_hid_class_data_out(USBD_HandleTypeDef *dev, usb_hid_state_t *state, uint8_t ep_num) { static void usb_hid_class_data_out(USBD_HandleTypeDef *dev,
if (ep_num == state->ep_out) { usb_hid_state_t *state, uint8_t ep_num) {
state->last_read_len = USBD_LL_GetRxDataSize(dev, ep_num); if (ep_num == state->ep_out) {
state->last_read_len = USBD_LL_GetRxDataSize(dev, ep_num);
// Prepare the OUT EP to receive next packet // Prepare the OUT EP to receive next packet
// User should provide state->rx_buffer that is big enough for state->max_packet_len bytes // User should provide state->rx_buffer that is big enough for
USBD_LL_PrepareReceive(dev, ep_num, state->rx_buffer, state->max_packet_len); // state->max_packet_len bytes
USBD_LL_PrepareReceive(dev, ep_num, state->rx_buffer,
if (state->last_read_len > 0) { state->max_packet_len);
// Block the OUT EP until we process received data
usb_ep_set_nak(dev, ep_num); if (state->last_read_len > 0) {
} // Block the OUT EP until we process received data
usb_ep_set_nak(dev, ep_num);
} }
}
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save