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
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/*')
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
clang-format -i $(shell find embed -type f -name *.[ch])
clang-format -i embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
## code generation:

@ -21,8 +21,8 @@
#include "common.h"
#include "display.h"
#include "image.h"
#include "flash.h"
#include "image.h"
#include "rng.h"
#include "sdcard.h"
@ -45,158 +45,164 @@ static const uint8_t * const BOARDLOADER_KEYS[] = {
#endif
};
static uint32_t check_sdcard(void)
{
if (sectrue != sdcard_power_on()) {
return 0;
}
uint64_t cap = sdcard_get_capacity_in_bytes();
if (cap < 1024 * 1024) {
sdcard_power_off();
return 0;
}
static uint32_t check_sdcard(void) {
if (sectrue != sdcard_power_on()) {
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))) {
return hdr.codelen;
} else {
return 0;
}
}
image_header hdr;
static void progress_callback(int pos, int len) {
display_printf(".");
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))) {
return hdr.codelen;
} else {
return 0;
}
}
static secbool copy_sdcard(void)
{
display_backlight(255);
static void progress_callback(int pos, int len) { display_printf("."); }
display_printf("TREZOR Boardloader\n");
display_printf("==================\n\n");
static secbool copy_sdcard(void) {
display_backlight(255);
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");
display_printf("TREZOR Boardloader\n");
display_printf("==================\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--) {
display_printf("%d ", i);
hal_delay(1000);
codelen = check_sdcard();
if (0 == codelen) {
display_printf("\n\nno SD card, aborting\n");
return secfalse;
}
}
uint32_t codelen;
display_printf("\n\nerasing flash:\n\n");
// erase all flash (except boardloader)
static const uint8_t sectors[] = {
FLASH_SECTOR_STORAGE_1,
FLASH_SECTOR_STORAGE_2,
3,
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;
for (int i = 10; i >= 0; i--) {
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(" 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);
}
}
display_printf("\n\nerasing flash:\n\n");
// erase all flash (except boardloader)
static const uint8_t sectors[] = {
FLASH_SECTOR_STORAGE_1,
FLASH_SECTOR_STORAGE_2,
3,
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);
// 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();
ensure(flash_lock_write(), NULL);
sdcard_power_off();
ensure(flash_lock_write(), NULL);
display_printf("\ndone\n\n");
display_printf("Unplug the device and remove the SD card\n");
display_printf("\ndone\n\n");
display_printf("Unplug the device and remove the SD card\n");
return sectrue;
return sectrue;
}
int main(void)
{
if (sectrue != reset_flags_check()) {
return 1;
}
int main(void) {
if (sectrue != reset_flags_check()) {
return 1;
}
// need the systick timer running before many HAL operations.
// want the PVD enabled before flash operations too.
periph_init();
// need the systick timer running before many HAL operations.
// want the PVD enabled before flash operations too.
periph_init();
if (sectrue != flash_configure_option_bytes()) {
// display is not initialized so don't call ensure
secbool r = flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL);
(void)r;
return 2;
}
if (sectrue != flash_configure_option_bytes()) {
// display is not initialized so don't call ensure
secbool r =
flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL);
(void)r;
return 2;
}
clear_otg_hs_memory();
clear_otg_hs_memory();
display_init();
sdcard_init();
display_init();
sdcard_init();
if (check_sdcard()) {
return copy_sdcard() == sectrue ? 0 : 3;
}
if (check_sdcard()) {
return copy_sdcard() == sectrue ? 0 : 3;
}
image_header hdr;
image_header hdr;
ensure(
load_image_header((const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE, BOARDLOADER_KEY_M, BOARDLOADER_KEY_N, BOARDLOADER_KEYS, &hdr),
"invalid bootloader header");
ensure(load_image_header((const uint8_t *)BOOTLOADER_START,
BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE,
BOARDLOADER_KEY_M, BOARDLOADER_KEY_N,
BOARDLOADER_KEYS, &hdr),
"invalid bootloader header");
const uint8_t sectors[] = {
FLASH_SECTOR_BOOTLOADER,
};
ensure(
check_image_contents(&hdr, IMAGE_HEADER_SIZE, sectors, 1),
"invalid bootloader hash");
const uint8_t sectors[] = {
FLASH_SECTOR_BOOTLOADER,
};
ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE, sectors, 1),
"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_MINOR 0
#define VERSION_PATCH 2
#define VERSION_BUILD 0
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_PATCH 2
#define VERSION_BUILD 0

@ -28,9 +28,9 @@
#include "icon_cancel.h"
#include "icon_confirm.h"
#include "icon_info.h"
#include "icon_done.h"
#include "icon_fail.h"
#include "icon_info.h"
#include "icon_install.h"
#include "icon_wipe.h"
@ -40,283 +40,319 @@
#define BACKLIGHT_NORMAL 150
#define COLOR_BL_FAIL RGB16(0xFF, 0x00, 0x00) // red
#define COLOR_BL_DONE RGB16(0x00, 0xAE, 0x0B) // green
#define COLOR_BL_PROCESS RGB16(0x4A, 0x90, 0xE2) // blue
#define COLOR_BL_GRAY RGB16(0x99, 0x99, 0x99) // gray
#define COLOR_BL_FAIL RGB16(0xFF, 0x00, 0x00) // red
#define COLOR_BL_DONE RGB16(0x00, 0xAE, 0x0B) // green
#define COLOR_BL_PROCESS RGB16(0x4A, 0x90, 0xE2) // blue
#define COLOR_BL_GRAY RGB16(0x99, 0x99, 0x99) // gray
// common shared functions
static void ui_confirm_cancel_buttons(void)
{
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, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL);
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 void ui_confirm_cancel_buttons(void) {
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,
toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE,
COLOR_BL_FAIL);
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 char ver_str[64];
mini_snprintf(ver_str, sizeof(ver_str), format,
(int)(version & 0xFF),
(int)((version >> 8) & 0xFF),
(int)((version >> 16) & 0xFF)
// ignore build field (int)((version >> 24) & 0xFF)
);
return ver_str;
static const char *format_ver(const char *format, uint32_t version) {
static char ver_str[64];
mini_snprintf(ver_str, sizeof(ver_str), format, (int)(version & 0xFF),
(int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF)
// ignore build field (int)((version >> 24) & 0xFF)
);
return ver_str;
}
// boot UI
static uint16_t boot_background;
void ui_screen_boot(const vendor_header * const vhdr, const image_header * const hdr)
{
const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
if ((vhdr->vtrust & VTRUST_RED) == 0) {
boot_background = COLOR_BL_FAIL;
} else {
boot_background = COLOR_BLACK;
}
const uint8_t *vimg = vhdr->vimg;
const uint32_t fw_version = hdr->version;
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, boot_background);
int image_top = show_string ? 30 : (DISPLAY_RESY - 120) / 2;
// check whether vendor image is 120x120
if (memcmp(vimg, "TOIf\x78\x00\x78\x00", 4) == 0) {
uint32_t datalen = *(uint32_t *)(vimg + 8);
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);
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(const vendor_header *const vhdr,
const image_header *const hdr) {
const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
if ((vhdr->vtrust & VTRUST_RED) == 0) {
boot_background = COLOR_BL_FAIL;
} else {
boot_background = COLOR_BLACK;
}
const uint8_t *vimg = vhdr->vimg;
const uint32_t fw_version = hdr->version;
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, boot_background);
int image_top = show_string ? 30 : (DISPLAY_RESY - 120) / 2;
// check whether vendor image is 120x120
if (memcmp(vimg, "TOIf\x78\x00\x78\x00", 4) == 0) {
uint32_t datalen = *(uint32_t *)(vimg + 8);
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);
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)
{
char wait_str[16];
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_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5, wait_str, -1, FONT_NORMAL, COLOR_WHITE, boot_background);
void ui_screen_boot_wait(int wait_seconds) {
char wait_str[16];
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_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5, wait_str, -1,
FONT_NORMAL, COLOR_WHITE, boot_background);
}
void ui_screen_boot_click(void) {
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_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);
}
// welcome UI
void ui_screen_first(void)
{
display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12, COLOR_BLACK, COLOR_WHITE);
void ui_screen_first(void) {
display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12,
COLOR_BLACK, COLOR_WHITE);
}
void ui_screen_second(void)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
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);
void ui_screen_second(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
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);
}
void ui_screen_third(void)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
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);
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
void ui_screen_third(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
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);
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL,
COLOR_BLACK, COLOR_WHITE);
}
// info UI
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);
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_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);
if (vhdr && hdr) {
ver_str = format_ver("Firmware %d.%d.%d", (hdr->version));
display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
display_text(55, 95, "by", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
display_text(55, 120, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
} else {
display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
}
if (sectrue == buttons) {
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(secbool buttons, const vendor_header *const vhdr,
const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
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_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);
if (vhdr && hdr) {
ver_str = format_ver("Firmware %d.%d.%d", (hdr->version));
display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
display_text(55, 95, "by", -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_WHITE);
display_text(55, 120, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL,
COLOR_BL_GRAY, COLOR_WHITE);
} else {
display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY,
COLOR_WHITE);
}
if (sectrue == buttons) {
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)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
static const char *hexdigits = "0123456789abcdef";
char fingerprint_str[64];
for (int i = 0; i < 32; i++) {
fingerprint_str[i * 2 ] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF];
fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF];
}
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_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);
void ui_screen_info_fingerprint(const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK);
static const char *hexdigits = "0123456789abcdef";
char fingerprint_str[64];
for (int i = 0; i < 32; i++) {
fingerprint_str[i * 2] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF];
fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF];
}
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_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
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_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
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_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
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_upgrade(const vendor_header *const vhdr,
const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
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_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
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)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Vendor change", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
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_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK, 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_confirm_newvendor(const vendor_header *const vhdr,
const image_header *const hdr) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Vendor change", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
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_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK,
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)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Installing firmware", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
void ui_screen_install(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install,
sizeof(toi_icon_install), COLOR_BLACK);
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)
{
display_loader(250 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK);
void ui_screen_install_progress_erase(int pos, int len) {
display_loader(250 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE,
toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK);
}
void ui_screen_install_progress_upload(int pos)
{
display_loader(pos, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK);
void ui_screen_install_progress_upload(int pos) {
display_loader(pos, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install,
sizeof(toi_icon_install), COLOR_BLACK);
}
// wipe UI
void ui_screen_wipe_confirm(void)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
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_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
display_text(55, 95, "wipe the device?", -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_wipe_confirm(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
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_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BLACK,
COLOR_WHITE);
display_text(55, 95, "wipe the device?", -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_wipe(void)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK);
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Wiping device", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE);
void ui_screen_wipe(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(0, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe,
sizeof(toi_icon_wipe), COLOR_BLACK);
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)
{
display_loader(1000 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK);
void ui_screen_wipe_progress(int pos, int len) {
display_loader(1000 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE,
toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BLACK);
}
// done UI
void ui_screen_done(int restart_seconds, secbool full_redraw)
{
const char *str;
char count_str[24];
if (restart_seconds >= 1) {
mini_snprintf(count_str, sizeof(count_str), "Done! Restarting in %d s", restart_seconds);
str = count_str;
} else {
str = "Done! Unplug the device.";
}
if (sectrue == full_redraw) {
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);
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);
void ui_screen_done(int restart_seconds, secbool full_redraw) {
const char *str;
char count_str[24];
if (restart_seconds >= 1) {
mini_snprintf(count_str, sizeof(count_str), "Done! Restarting in %d s",
restart_seconds);
str = count_str;
} else {
str = "Done! Unplug the device.";
}
if (sectrue == full_redraw) {
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);
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);
}
// error UI
void ui_screen_fail(void)
{
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(1000, -20, COLOR_BL_FAIL, COLOR_WHITE, toi_icon_fail, 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);
void ui_screen_fail(void) {
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE);
display_loader(1000, -20, COLOR_BL_FAIL, COLOR_WHITE, toi_icon_fail,
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);
}
// general functions
void ui_fadein(void)
{
display_fade(0, BACKLIGHT_NORMAL, 1000);
}
void ui_fadein(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); }
void ui_fadeout(void)
{
display_fade(BACKLIGHT_NORMAL, 0, 500);
display_clear();
void ui_fadeout(void) {
display_fade(BACKLIGHT_NORMAL, 0, 500);
display_clear();
}
int ui_user_input(int zones)
{
for (;;) {
uint32_t evt = touch_click();
uint16_t x = touch_unpack_x(evt);
uint16_t y = touch_unpack_y(evt);
// clicked on Cancel button
if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 && y < 184 + 50) {
return INPUT_CANCEL;
}
// clicked on Confirm button
if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 && 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) {
return INPUT_LONG_CONFIRM;
}
// clicked on Info icon
if ((zones & INPUT_INFO) && x >= 16 && x < 16 + 32 && y > 54 && y < 54 + 32) {
return INPUT_INFO;
}
int ui_user_input(int zones) {
for (;;) {
uint32_t evt = touch_click();
uint16_t x = touch_unpack_x(evt);
uint16_t y = touch_unpack_y(evt);
// clicked on Cancel button
if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 &&
y < 184 + 50) {
return INPUT_CANCEL;
}
// clicked on Confirm button
if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 &&
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) {
return INPUT_LONG_CONFIRM;
}
// 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__
#define __BOOTUI_H__
#include "secbool.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_click(void);
@ -31,11 +32,14 @@ void ui_screen_first(void);
void ui_screen_second(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_fingerprint(const image_header * const hdr);
void ui_screen_info(secbool buttons, const vendor_header* const vhdr,
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_newvendor(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);
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_progress_erase(int pos, int len);
void ui_screen_install_progress_upload(int pos);
@ -51,10 +55,10 @@ void ui_screen_fail(void);
void ui_fadein(void);
void ui_fadeout(void);
#define INPUT_CANCEL 0x01 // Cancel button
#define INPUT_CONFIRM 0x02 // Confirm button
#define INPUT_LONG_CONFIRM 0x04 // Long Confirm button
#define INPUT_INFO 0x08 // Info icon
#define INPUT_CANCEL 0x01 // Cancel button
#define INPUT_CONFIRM 0x02 // Confirm button
#define INPUT_LONG_CONFIRM 0x04 // Long Confirm button
#define INPUT_INFO 0x08 // Info icon
int ui_user_input(int zones);
#endif

@ -21,11 +21,11 @@
#include <sys/types.h>
#include "common.h"
#include "mpu.h"
#include "image.h"
#include "flash.h"
#include "display.h"
#include "flash.h"
#include "image.h"
#include "mini_printf.h"
#include "mpu.h"
#include "rng.h"
#include "secbool.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",
};
#define USB_IFACE_NUM 0
#define USB_IFACE_NUM 0
static void usb_init_all(void) {
static const usb_dev_info_t dev_info = {
.device_class = 0x00,
.device_subclass = 0x00,
.device_protocol = 0x00,
.vendor_id = 0x1209,
.product_id = 0x53C0,
.release_num = 0x0200,
.manufacturer = "SatoshiLabs",
.product = "TREZOR",
.serial_number = "000000000000000000000000",
.interface = "TREZOR Interface",
.usb21_enabled = sectrue,
.usb21_landing = sectrue,
};
static uint8_t rx_buffer[USB_PACKET_SIZE];
static const usb_webusb_info_t webusb_info = {
.iface_num = USB_IFACE_NUM,
.ep_in = USB_EP_DIR_IN | 0x01,
.ep_out = USB_EP_DIR_OUT | 0x01,
.subclass = 0,
.protocol = 0,
.max_packet_len = sizeof(rx_buffer),
.rx_buffer = rx_buffer,
.polling_interval = 1,
};
usb_init(&dev_info);
ensure(usb_webusb_add(&webusb_info), NULL);
usb_start();
static const usb_dev_info_t dev_info = {
.device_class = 0x00,
.device_subclass = 0x00,
.device_protocol = 0x00,
.vendor_id = 0x1209,
.product_id = 0x53C0,
.release_num = 0x0200,
.manufacturer = "SatoshiLabs",
.product = "TREZOR",
.serial_number = "000000000000000000000000",
.interface = "TREZOR Interface",
.usb21_enabled = sectrue,
.usb21_landing = sectrue,
};
static uint8_t rx_buffer[USB_PACKET_SIZE];
static const usb_webusb_info_t webusb_info = {
.iface_num = USB_IFACE_NUM,
.ep_in = USB_EP_DIR_IN | 0x01,
.ep_out = USB_EP_DIR_OUT | 0x01,
.subclass = 0,
.protocol = 0,
.max_packet_len = sizeof(rx_buffer),
.rx_buffer = rx_buffer,
.polling_interval = 1,
};
usb_init(&dev_info);
ensure(usb_webusb_add(&webusb_info), NULL);
usb_start();
}
static secbool bootloader_usb_loop(const vendor_header * const vhdr, const image_header * const hdr)
{
usb_init_all();
static secbool bootloader_usb_loop(const vendor_header *const vhdr,
const image_header *const hdr) {
usb_init_all();
uint8_t buf[USB_PACKET_SIZE];
uint8_t buf[USB_PACKET_SIZE];
for (;;) {
int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE, USB_TIMEOUT);
if (r != USB_PACKET_SIZE) {
continue;
for (;;) {
int r = usb_webusb_read_blocking(USB_IFACE_NUM, buf, USB_PACKET_SIZE,
USB_TIMEOUT);
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;
uint32_t msg_size;
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
// invalid header -> discard
continue;
ui_fadeout();
ui_screen_wipe();
ui_fadein();
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
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) {
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;
}
ui_fadeout();
ui_screen_wipe();
ui_fadein();
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
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
}
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 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;
}
}
}
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);
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);
}
static secbool check_vendor_keys_lock(const vendor_header * const vhdr) {
uint8_t lock[FLASH_OTP_BLOCK_SIZE];
ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK, 0, lock, FLASH_OTP_BLOCK_SIZE), NULL);
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)) {
return sectrue;
}
uint8_t hash[32];
vendor_keys_hash(vhdr, hash);
return sectrue * (0 == memcmp(lock, hash, 32));
static secbool check_vendor_keys_lock(const vendor_header *const vhdr) {
uint8_t lock[FLASH_OTP_BLOCK_SIZE];
ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK, 0, lock,
FLASH_OTP_BLOCK_SIZE),
NULL);
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)) {
return sectrue;
}
uint8_t hash[32];
vendor_keys_hash(vhdr, hash);
return sectrue * (0 == memcmp(lock, hash, 32));
}
// protection against bootloader downgrade
#if PRODUCTION
static void check_bootloader_version(void)
{
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
if (i < VERSION_MONOTONIC) {
bits[i / 8] &= ~(1 << (7 - (i % 8)));
} else {
bits[i / 8] |= (1 << (7 - (i % 8)));
}
static void check_bootloader_version(void) {
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
if (i < VERSION_MONOTONIC) {
bits[i / 8] &= ~(1 << (7 - (i % 8)));
} else {
bits[i / 8] |= (1 << (7 - (i % 8)));
}
ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
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");
}
ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits,
FLASH_OTP_BLOCK_SIZE),
NULL);
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
int main(void)
{
touch_init();
touch_power_on();
int main(void) {
touch_init();
touch_power_on();
mpu_config_bootloader();
mpu_config_bootloader();
#if PRODUCTION
check_bootloader_version();
check_bootloader_version();
#endif
main_start:
display_clear();
display_clear();
// delay to detect touch
uint32_t touched = 0;
for (int i = 0; i < 100; i++) {
touched = touch_is_detected() | touch_read();
if (touched) {
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);
// delay to detect touch
uint32_t touched = 0;
for (int i = 0; i < 100; i++) {
touched = touch_is_detected() | touch_read();
if (touched) {
break;
}
if (sectrue == firmware_present) {
firmware_present = check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT);
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) {
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 ...
if (firmware_present != sectrue) {
// show intro animation
// no ui_fadeout(); - we already start from black screen
ui_screen_first();
ui_fadein();
hal_delay(1000);
// no ui_fadeout(); - we already start from black screen
ui_screen_info(sectrue, &vhdr, &hdr);
ui_fadein();
ui_fadeout();
ui_screen_second();
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;
}
hal_delay(1000);
ui_fadeout();
ui_screen_third();
// if info icon was pressed -> show fingerprint
if (INPUT_INFO == response) {
// show fingerprint
ui_screen_info_fingerprint(&hdr);
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;
while (INPUT_LONG_CONFIRM != ui_user_input(INPUT_LONG_CONFIRM)) {
}
} else
// ... 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_fadeout();
ui_screen_info(sectrue, &vhdr, &hdr);
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(
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
"invalid vendor header");
// and start the usb loop
if (bootloader_usb_loop(&vhdr, &hdr) != sectrue) {
return 1;
}
}
ensure(
check_vendor_keys_lock(&vhdr),
"unauthorized vendor keys");
ensure(load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
"invalid vendor header");
ensure(
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(check_vendor_keys_lock(&vhdr), "unauthorized vendor keys");
ensure(
check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT),
"invalid firmware hash");
ensure(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");
// 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
ui_screen_boot(&vhdr, &hdr);
ui_fadein();
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
// ui_fadeout(); // no fadeout - we start from black screen
ui_screen_boot(&vhdr, &hdr);
ui_fadein();
int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT;
if (delay > 1) {
while (delay > 0) {
ui_screen_boot_wait(delay);
hal_delay(1000);
delay--;
}
} else if (delay == 1) {
hal_delay(1000);
}
if ((vhdr.vtrust & VTRUST_CLICK) == 0) {
ui_screen_boot_click();
touch_click();
}
int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT;
if (delay > 1) {
while (delay > 0) {
ui_screen_boot_wait(delay);
hal_delay(1000);
delay--;
}
} else if (delay == 1) {
hal_delay(1000);
}
ui_fadeout();
if ((vhdr.vtrust & VTRUST_CLICK) == 0) {
ui_screen_boot_click();
touch_click();
}
// mpu_config_firmware();
// jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE);
ui_fadeout();
}
// mpu_config_firmware();
// jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE);
mpu_config_off();
jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE);
mpu_config_off();
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 "secbool.h"
#define USB_TIMEOUT 500
#define USB_PACKET_SIZE 64
#define USB_TIMEOUT 500
#define USB_PACKET_SIZE 64
#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 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_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_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_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_FirmwareErase(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
int process_msg_FirmwareUpload(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);
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);
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_MINOR 0
#define VERSION_PATCH 3
#define VERSION_BUILD 0
#define VERSION_UINT32 (VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | (VERSION_BUILD << 24))
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_PATCH 3
#define VERSION_BUILD 0
#define VERSION_UINT32 \
(VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | \
(VERSION_BUILD << 24))
#define FIX_VERSION_MAJOR 2
#define FIX_VERSION_MINOR 0
#define FIX_VERSION_PATCH 0
#define FIX_VERSION_BUILD 0
#define FIX_VERSION_MAJOR 2
#define FIX_VERSION_MINOR 0
#define FIX_VERSION_PATCH 0
#define FIX_VERSION_BUILD 0
#define VERSION_MONOTONIC 1
#define VERSION_MONOTONIC 1

@ -19,31 +19,32 @@
#include <string.h>
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/objstr.h"
#include "py/runtime.h"
#if MICROPY_PY_TREZORCONFIG
#include "embed/extmod/trezorobj.h"
#include "storage.h"
#include "common.h"
#include "memzero.h"
#include "storage.h"
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) {
if (mp_obj_is_callable(ui_wait_callback)) {
mp_obj_t args[3];
args[0] = mp_obj_new_int(wait);
args[1] = mp_obj_new_int(progress);
args[2] = mp_obj_new_str(message, strlen(message));
if (mp_call_function_n_kw(ui_wait_callback, 3, 0, args) == mp_const_true) {
return sectrue;
}
STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress,
const char *message) {
if (mp_obj_is_callable(ui_wait_callback)) {
mp_obj_t args[3];
args[0] = mp_obj_new_int(wait);
args[1] = mp_obj_new_int(progress);
args[2] = mp_obj_new_str(message, strlen(message));
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:
@ -52,29 +53,31 @@ STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress, const
/// called from this module!
/// '''
STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) {
if (n_args > 0) {
ui_wait_callback = args[0];
storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
} else {
storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
}
memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA));
return mp_const_none;
if (n_args > 0) {
ui_wait_callback = args[0];
storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
} else {
storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN);
}
memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA));
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:
/// '''
/// Check the given PIN. Returns True on success, False on failure.
/// '''
STATIC mp_obj_t mod_trezorconfig_check_pin(mp_obj_t pin) {
uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) {
return mp_const_false;
}
return mp_const_true;
uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) {
return mp_const_false;
}
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:
/// '''
@ -82,205 +85,227 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_check_pin_obj, mod_trezorconfi
/// success, False on failure.
/// '''
STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin) {
uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) {
return mp_const_false;
}
return mp_const_true;
uint32_t pin_i = trezor_obj_get_uint(pin);
if (sectrue != storage_unlock(pin_i)) {
return mp_const_false;
}
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:
/// '''
/// Locks the storage.
/// '''
STATIC mp_obj_t mod_trezorconfig_lock(void) {
storage_lock();
return mp_const_none;
storage_lock();
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:
/// '''
/// Returns True if storage has a configured PIN, False otherwise.
/// '''
STATIC mp_obj_t mod_trezorconfig_has_pin(void) {
if (sectrue != storage_has_pin()) {
return mp_const_false;
}
return mp_const_true;
if (sectrue != storage_has_pin()) {
return mp_const_false;
}
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:
/// '''
/// Returns the number of remaining PIN entry attempts.
/// '''
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:
/// '''
/// 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) {
uint32_t pin_i = trezor_obj_get_uint(pin);
uint32_t newpin_i = trezor_obj_get_uint(newpin);
if (sectrue != storage_change_pin(pin_i, newpin_i)) {
return mp_const_false;
}
return mp_const_true;
uint32_t pin_i = trezor_obj_get_uint(pin);
uint32_t newpin_i = trezor_obj_get_uint(newpin);
if (sectrue != storage_change_pin(pin_i, newpin_i)) {
return mp_const_false;
}
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:
/// '''
/// 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) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
uint16_t len = 0;
if (sectrue != storage_get(appkey, NULL, 0, &len)) {
return mp_const_none;
}
if (len == 0) {
return mp_const_empty_bytes;
}
vstr_t vstr;
vstr_init_len(&vstr, len);
if (sectrue != storage_get(appkey, vstr.buf, vstr.len, &len)) {
vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to get value from storage.");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
uint16_t len = 0;
if (sectrue != storage_get(appkey, NULL, 0, &len)) {
return mp_const_none;
}
if (len == 0) {
return mp_const_empty_bytes;
}
vstr_t vstr;
vstr_init_len(&vstr, len);
if (sectrue != storage_get(appkey, vstr.buf, vstr.len, &len)) {
vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to get value from storage.");
}
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:
/// '''
/// 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) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 3 && args[3] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
mp_buffer_info_t value;
mp_get_buffer_raise(args[2], &value, MP_BUFFER_READ);
if (sectrue != storage_set(appkey, value.buf, value.len)) {
mp_raise_msg(&mp_type_RuntimeError, "Could not save value");
}
return mp_const_none;
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 3 && args[3] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
mp_buffer_info_t value;
mp_get_buffer_raise(args[2], &value, MP_BUFFER_READ);
if (sectrue != storage_set(appkey, value.buf, value.len)) {
mp_raise_msg(&mp_type_RuntimeError, "Could not save value");
}
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:
/// '''
/// Deletes the given key of the given app.
/// '''
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 key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
if (sectrue != storage_delete(appkey)) {
return mp_const_false;
}
return mp_const_true;
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
if (sectrue != storage_delete(appkey)) {
return mp_const_false;
}
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.
/// '''
STATIC mp_obj_t mod_trezorconfig_set_counter(size_t n_args, const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 3 && args[3] == mp_const_true) {
app |= 0xC0;
} else {
app |= 0x80;
STATIC mp_obj_t mod_trezorconfig_set_counter(size_t n_args,
const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 3 && args[3] == mp_const_true) {
app |= 0xC0;
} 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;
if (args[2] == mp_const_none) {
if (sectrue != storage_delete(appkey)) {
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;
}
} 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:
/// '''
/// 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) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0xC0;
} else {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
uint32_t count = 0;
if (sectrue != storage_next_counter(appkey, &count)) {
return mp_const_none;
}
return mp_obj_new_int_from_uint(count);
STATIC mp_obj_t mod_trezorconfig_next_counter(size_t n_args,
const mp_obj_t *args) {
uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F;
uint8_t key = trezor_obj_get_uint8(args[1]);
if (n_args > 2 && args[2] == mp_const_true) {
app |= 0xC0;
} else {
app |= 0x80;
}
uint16_t appkey = (app << 8) | key;
uint32_t count = 0;
if (sectrue != storage_next_counter(appkey, &count)) {
return mp_const_none;
}
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:
/// '''
/// Erases the whole config. Use with caution!
/// '''
STATIC mp_obj_t mod_trezorconfig_wipe(void) {
storage_wipe();
return mp_const_none;
storage_wipe();
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[] = {
{ 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_check_pin), MP_ROM_PTR(&mod_trezorconfig_check_pin_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj) },
{ MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorconfig_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_pin_rem), MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj) },
{ MP_ROM_QSTR(MP_QSTR_change_pin), MP_ROM_PTR(&mod_trezorconfig_change_pin_obj) },
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj) },
{ MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_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) },
{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_check_pin),
MP_ROM_PTR(&mod_trezorconfig_check_pin_obj)},
{MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj)},
{MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorconfig_lock_obj)},
{MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj)},
{MP_ROM_QSTR(MP_QSTR_get_pin_rem),
MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj)},
{MP_ROM_QSTR(MP_QSTR_change_pin),
MP_ROM_PTR(&mod_trezorconfig_change_pin_obj)},
{MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj)},
{MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_trezorconfig_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mp_module_trezorconfig_globals,
};
#endif // MICROPY_PY_TREZORCONFIG
#endif // MICROPY_PY_TREZORCONFIG

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

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

@ -23,11 +23,11 @@
#include "memzero.h"
enum AESMode {
ECB = 0x00,
CBC = 0x01,
CFB = 0x02,
OFB = 0x03,
CTR = 0x04,
ECB = 0x00,
CBC = 0x01,
CFB = 0x02,
OFB = 0x03,
CTR = 0x04,
};
/// package: trezorcrypto.__init__
@ -37,102 +37,114 @@ enum AESMode {
/// AES context.
/// '''
typedef struct _mp_obj_AES_t {
mp_obj_base_t base;
aes_encrypt_ctx encrypt_ctx;
aes_decrypt_ctx decrypt_ctx;
mp_int_t mode;
uint8_t iv[AES_BLOCK_SIZE];
mp_obj_base_t base;
aes_encrypt_ctx encrypt_ctx;
aes_decrypt_ctx decrypt_ctx;
mp_int_t mode;
uint8_t iv[AES_BLOCK_SIZE];
} mp_obj_AES_t;
/// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None:
/// '''
/// 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) {
mp_arg_check_num(n_args, n_kw, 2, 3, false);
mp_obj_AES_t *o = m_new_obj(mp_obj_AES_t);
o->base.type = type;
o->mode = mp_obj_get_int(args[0]);
if (o->mode < ECB || o->mode > CTR) {
mp_raise_ValueError("Invalid AES mode");
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) {
mp_arg_check_num(n_args, n_kw, 2, 3, false);
mp_obj_AES_t *o = m_new_obj(mp_obj_AES_t);
o->base.type = type;
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;
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)");
}
memcpy(o->iv, iv.buf, AES_BLOCK_SIZE);
} else {
memzero(o->iv, AES_BLOCK_SIZE);
}
switch (key.len) {
case 16:
aes_decrypt_key128(key.buf, &(o->decrypt_ctx));
aes_encrypt_key128(key.buf, &(o->encrypt_ctx));
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);
memcpy(o->iv, iv.buf, AES_BLOCK_SIZE);
} else {
memzero(o->iv, AES_BLOCK_SIZE);
}
switch (key.len) {
case 16:
aes_decrypt_key128(key.buf, &(o->decrypt_ctx));
aes_encrypt_key128(key.buf, &(o->encrypt_ctx));
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) {
mp_buffer_info_t buf;
mp_get_buffer_raise(data, &buf, MP_BUFFER_READ);
if (buf.len == 0) {
return mp_const_empty_bytes;
}
vstr_t vstr;
vstr_init_len(&vstr, buf.len);
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
switch (o->mode) {
case ECB:
if (buf.len & (AES_BLOCK_SIZE - 1)) {
mp_raise_ValueError("Invalid data length");
}
if (encrypt) {
aes_ecb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, &(o->encrypt_ctx));
} else {
aes_ecb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, &(o->decrypt_ctx));
}
break;
case CBC:
if (buf.len & (AES_BLOCK_SIZE - 1)) {
mp_raise_ValueError("Invalid data length");
}
if (encrypt) {
aes_cbc_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx));
} else {
aes_cbc_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->decrypt_ctx));
}
break;
case CFB:
if (encrypt) {
aes_cfb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx));
} else {
aes_cfb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv, &(o->encrypt_ctx)); // decrypt uses encrypt_ctx
}
break;
case OFB: // (encrypt == decrypt)
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);
mp_buffer_info_t buf;
mp_get_buffer_raise(data, &buf, MP_BUFFER_READ);
if (buf.len == 0) {
return mp_const_empty_bytes;
}
vstr_t vstr;
vstr_init_len(&vstr, buf.len);
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
switch (o->mode) {
case ECB:
if (buf.len & (AES_BLOCK_SIZE - 1)) {
mp_raise_ValueError("Invalid data length");
}
if (encrypt) {
aes_ecb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len,
&(o->encrypt_ctx));
} else {
aes_ecb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len,
&(o->decrypt_ctx));
}
break;
case CBC:
if (buf.len & (AES_BLOCK_SIZE - 1)) {
mp_raise_ValueError("Invalid data length");
}
if (encrypt) {
aes_cbc_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
&(o->encrypt_ctx));
} else {
aes_cbc_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
&(o->decrypt_ctx));
}
break;
case CFB:
if (encrypt) {
aes_cfb_encrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
&(o->encrypt_ctx));
} else {
aes_cfb_decrypt(buf.buf, (uint8_t *)vstr.buf, buf.len, o->iv,
&(o->encrypt_ctx)); // decrypt uses encrypt_ctx
}
break;
case OFB: // (encrypt == decrypt)
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:
@ -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.
/// '''
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:
/// '''
/// Decrypt data and update AES context.
/// '''
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) {
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->encrypt_ctx), sizeof(aes_encrypt_ctx));
memzero(&(o->decrypt_ctx), sizeof(aes_decrypt_ctx));
memzero(o->iv, AES_BLOCK_SIZE);
return mp_const_none;
mp_obj_AES_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->encrypt_ctx), sizeof(aes_encrypt_ctx));
memzero(&(o->decrypt_ctx), sizeof(aes_decrypt_ctx));
memzero(o->iv, AES_BLOCK_SIZE);
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[] = {
{ MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&mod_trezorcrypto_AES_encrypt_obj) },
{ MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&mod_trezorcrypto_AES_decrypt_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_AES___del___obj) },
{ MP_ROM_QSTR(MP_QSTR_ECB), MP_OBJ_NEW_SMALL_INT(ECB) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_encrypt),
MP_ROM_PTR(&mod_trezorcrypto_AES_encrypt_obj)},
{MP_ROM_QSTR(MP_QSTR_decrypt),
MP_ROM_PTR(&mod_trezorcrypto_AES_decrypt_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_AES___del___obj)},
{MP_ROM_QSTR(MP_QSTR_ECB), MP_OBJ_NEW_SMALL_INT(ECB)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_AES,
.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.
/// '''
typedef struct _mp_obj_HDNode_t {
mp_obj_base_t base;
uint32_t fingerprint;
HDNode hdnode;
mp_obj_base_t base;
uint32_t fingerprint;
HDNode hdnode;
} mp_obj_HDNode_t;
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:
/// '''
/// '''
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 const mp_arg_t allowed_args[] = {
{ MP_QSTR_depth, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_fingerprint, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_child_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_chain_code, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_private_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_public_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_curve_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
};
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_buffer_info_t chain_code;
mp_buffer_info_t private_key;
mp_buffer_info_t public_key;
mp_buffer_info_t curve_name;
const uint32_t depth = trezor_obj_get_uint(vals[0].u_obj);
const uint32_t fingerprint = trezor_obj_get_uint(vals[1].u_obj);
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);
mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ);
mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ);
if (32 != chain_code.len) {
mp_raise_ValueError("chain_code is invalid");
}
if (0 == public_key.len && 0 == private_key.len) {
mp_raise_ValueError("either public_key or private_key is required");
}
if (0 != private_key.len && 32 != private_key.len) {
mp_raise_ValueError("private_key is invalid");
}
if (0 != public_key.len && 33 != public_key.len) {
mp_raise_ValueError("public_key is invalid");
}
const curve_info *curve = NULL;
if (0 == curve_name.len) {
curve = get_curve_by_name(SECP256K1_NAME);
} else {
curve = get_curve_by_name(curve_name.buf);
}
if (NULL == curve) {
mp_raise_ValueError("curve_name is invalid");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
o->base.type = type;
o->fingerprint = fingerprint;
o->hdnode.depth = depth;
o->hdnode.child_num = child_num;
if (32 == chain_code.len) {
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);
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 const mp_arg_t allowed_args[] = {
{MP_QSTR_depth,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_fingerprint,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_child_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_chain_code,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_private_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_public_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_curve_name,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
};
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_buffer_info_t chain_code;
mp_buffer_info_t private_key;
mp_buffer_info_t public_key;
mp_buffer_info_t curve_name;
const uint32_t depth = trezor_obj_get_uint(vals[0].u_obj);
const uint32_t fingerprint = trezor_obj_get_uint(vals[1].u_obj);
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);
mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ);
mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ);
if (32 != chain_code.len) {
mp_raise_ValueError("chain_code is invalid");
}
if (0 == public_key.len && 0 == private_key.len) {
mp_raise_ValueError("either public_key or private_key is required");
}
if (0 != private_key.len && 32 != private_key.len) {
mp_raise_ValueError("private_key is invalid");
}
if (0 != public_key.len && 33 != public_key.len) {
mp_raise_ValueError("public_key is invalid");
}
const curve_info *curve = NULL;
if (0 == curve_name.len) {
curve = get_curve_by_name(SECP256K1_NAME);
} else {
curve = get_curve_by_name(curve_name.buf);
}
if (NULL == curve) {
mp_raise_ValueError("curve_name is invalid");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
o->base.type = type;
o->fingerprint = fingerprint;
o->hdnode.depth = depth;
o->hdnode.child_num = child_num;
if (32 == chain_code.len) {
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:
/// '''
/// Derive a BIP0032 child node in place.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args, const mp_obj_t *args) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
uint32_t i = trezor_obj_get_uint(args[1]);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
bool public = n_args > 2 && args[2] == mp_const_true;
int res;
if (public) {
res = hdnode_public_ckd(&o->hdnode, i);
} else {
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)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
res = hdnode_private_ckd(&o->hdnode, i);
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args,
const mp_obj_t *args) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
uint32_t i = trezor_obj_get_uint(args[1]);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
bool public = n_args > 2 && args[2] == mp_const_true;
int res;
if (public) {
res = hdnode_public_ckd(&o->hdnode, i);
} else {
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)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
if (!res) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive");
}
o->fingerprint = fp;
res = hdnode_private_ckd(&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_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:
/// '''
/// 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) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t i = mp_obj_get_int_truncated(index);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
int res;
// same as in derive
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)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
// special for cardano
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;
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_cardano(mp_obj_t self,
mp_obj_t index) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t i = mp_obj_get_int_truncated(index);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
int res;
// same as in derive
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)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
// special for cardano
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:
/// '''
/// 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);
// get path objects and length
size_t plen;
mp_obj_t *pitems;
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];
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;
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive path");
}
/// 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);
// get path objects and length
size_t plen;
mp_obj_t *pitems;
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];
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;
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_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);
char xpub[XPUB_MAXLEN] = {0};
int written;
if (use_public) {
hdnode_fill_public_key(&o->hdnode);
written = hdnode_serialize_public(&o->hdnode, o->fingerprint, version, xpub, XPUB_MAXLEN);
} else {
written = hdnode_serialize_private(&o->hdnode, o->fingerprint, version, xpub, XPUB_MAXLEN);
}
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
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);
char xpub[XPUB_MAXLEN] = {0};
int written;
if (use_public) {
hdnode_fill_public_key(&o->hdnode);
written = hdnode_serialize_public(&o->hdnode, o->fingerprint, version, xpub,
XPUB_MAXLEN);
} else {
written = hdnode_serialize_private(&o->hdnode, o->fingerprint, version,
xpub, XPUB_MAXLEN);
}
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:
/// '''
/// 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) {
uint32_t ver = trezor_obj_get_uint(version);
return serialize_public_private(self, true, ver);
STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_public(mp_obj_t self,
mp_obj_t version) {
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:
/// '''
/// 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) {
uint32_t ver = trezor_obj_get_uint(version);
return serialize_public_private(self, false, ver);
STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_private(mp_obj_t self,
mp_obj_t version) {
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:
/// '''
/// Returns a copy of the HD node.
/// '''
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 *copy = m_new_obj(mp_obj_HDNode_t);
copy->base.type = &mod_trezorcrypto_HDNode_type;
copy->hdnode = o->hdnode;
copy->fingerprint = o->fingerprint;
return MP_OBJ_FROM_PTR(copy);
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
mp_obj_HDNode_t *copy = m_new_obj(mp_obj_HDNode_t);
copy->base.type = &mod_trezorcrypto_HDNode_type;
copy->hdnode = o->hdnode;
copy->fingerprint = o->fingerprint;
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:
/// '''
/// Returns a depth of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_depth(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.depth);
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// 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) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->fingerprint);
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// Returns a child index of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_child_num(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.child_num);
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// Returns a chain code of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_chain_code(mp_obj_t 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));
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// Returns a private key of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key(mp_obj_t 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));
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// Returns a private key extension of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key_ext(mp_obj_t 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));
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));
}
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:
/// '''
/// Returns a public key of the HD node.
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_public_key(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
hdnode_fill_public_key(&o->hdnode);
return mp_obj_new_bytes(o->hdnode.public_key, sizeof(o->hdnode.public_key));
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
hdnode_fill_public_key(&o->hdnode);
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:
/// '''
/// 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) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t 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};
hdnode_get_address(&o->hdnode, v, address, ADDRESS_MAXLEN);
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)address, strlen(address));
char address[ADDRESS_MAXLEN] = {0};
hdnode_get_address(&o->hdnode, v, address, ADDRESS_MAXLEN);
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:
/// '''
/// 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) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_address(mp_obj_t 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
if (!hdnode_get_nem_address(&o->hdnode, n, 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));
char address[NEM_ADDRESS_SIZE + 1] = {0}; // + 1 for the 0 byte
if (!hdnode_get_nem_address(&o->hdnode, n, 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));
}
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
/// '''
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_encrypt(size_t n_args, 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);
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);
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);
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);
if (payload.len == 0) {
mp_raise_ValueError("payload is empty");
}
vstr_t vstr;
vstr_init_len(&vstr, NEM_ENCRYPTED_SIZE(payload.len));
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)) {
mp_raise_ValueError("HDNode nem encrypt failed");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_encrypt(size_t n_args,
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);
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);
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);
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);
if (payload.len == 0) {
mp_raise_ValueError("payload is empty");
}
vstr_t vstr;
vstr_init_len(&vstr, NEM_ENCRYPTED_SIZE(payload.len));
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)) {
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:
/// '''
/// Compute an Ethereum pubkeyhash (aka address) from the HD node.
/// '''
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];
hdnode_get_ethereum_pubkeyhash(&o->hdnode, pkh);
return mp_obj_new_bytes(pkh, sizeof(pkh));
uint8_t pkh[20];
hdnode_get_ethereum_pubkeyhash(&o->hdnode, 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) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
o->fingerprint = 0;
memzero(&o->hdnode, sizeof(o->hdnode));
return mp_const_none;
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
o->fingerprint = 0;
memzero(&o->hdnode, sizeof(o->hdnode));
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[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorcrypto_HDNode___del___obj) },
{ MP_ROM_QSTR(MP_QSTR_derive), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj) },
{ MP_ROM_QSTR(MP_QSTR_derive_cardano), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_cardano_obj) },
{ MP_ROM_QSTR(MP_QSTR_derive_path), MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj) },
{ MP_ROM_QSTR(MP_QSTR_serialize_private), MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_private_obj) },
{ MP_ROM_QSTR(MP_QSTR_serialize_public), MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_public_obj) },
{ MP_ROM_QSTR(MP_QSTR_clone), MP_ROM_PTR(&mod_trezorcrypto_HDNode_clone_obj) },
{ MP_ROM_QSTR(MP_QSTR_depth), MP_ROM_PTR(&mod_trezorcrypto_HDNode_depth_obj) },
{ MP_ROM_QSTR(MP_QSTR_fingerprint), 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) },
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_HDNode___del___obj)},
{MP_ROM_QSTR(MP_QSTR_derive),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj)},
{MP_ROM_QSTR(MP_QSTR_derive_cardano),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_cardano_obj)},
{MP_ROM_QSTR(MP_QSTR_derive_path),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj)},
{MP_ROM_QSTR(MP_QSTR_serialize_private),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_private_obj)},
{MP_ROM_QSTR(MP_QSTR_serialize_public),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_public_obj)},
{MP_ROM_QSTR(MP_QSTR_clone),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_clone_obj)},
{MP_ROM_QSTR(MP_QSTR_depth),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_depth_obj)},
{MP_ROM_QSTR(MP_QSTR_fingerprint),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_HDNode,
.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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_bip32_deserialize(mp_obj_t value, mp_obj_t version_public, mp_obj_t version_private) {
mp_buffer_info_t valueb;
mp_get_buffer_raise(value, &valueb, MP_BUFFER_READ);
if (valueb.len == 0) {
mp_raise_ValueError("Invalid value");
}
uint32_t vpub = trezor_obj_get_uint(version_public);
uint32_t vpriv = trezor_obj_get_uint(version_private);
HDNode hdnode;
uint32_t fingerprint;
if (hdnode_deserialize(valueb.buf, vpub, vpriv, SECP256K1_NAME, &hdnode, &fingerprint) < 0) {
mp_raise_ValueError("Failed to deserialize");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = fingerprint;
return MP_OBJ_FROM_PTR(o);
STATIC mp_obj_t mod_trezorcrypto_bip32_deserialize(mp_obj_t value,
mp_obj_t version_public,
mp_obj_t version_private) {
mp_buffer_info_t valueb;
mp_get_buffer_raise(value, &valueb, MP_BUFFER_READ);
if (valueb.len == 0) {
mp_raise_ValueError("Invalid value");
}
uint32_t vpub = trezor_obj_get_uint(version_public);
uint32_t vpriv = trezor_obj_get_uint(version_private);
HDNode hdnode;
uint32_t fingerprint;
if (hdnode_deserialize(valueb.buf, vpub, vpriv, SECP256K1_NAME, &hdnode,
&fingerprint) < 0) {
mp_raise_ValueError("Failed to deserialize");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
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:
/// '''
/// 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) {
mp_buffer_info_t seedb;
mp_get_buffer_raise(seed, &seedb, MP_BUFFER_READ);
if (seedb.len == 0) {
mp_raise_ValueError("Invalid seed");
}
mp_buffer_info_t curveb;
mp_get_buffer_raise(curve_name, &curveb, MP_BUFFER_READ);
if (curveb.len == 0) {
mp_raise_ValueError("Invalid curve name");
}
HDNode hdnode;
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;
o->hdnode = hdnode;
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
STATIC mp_obj_t mod_trezorcrypto_bip32_from_seed(mp_obj_t seed,
mp_obj_t curve_name) {
mp_buffer_info_t seedb;
mp_get_buffer_raise(seed, &seedb, MP_BUFFER_READ);
if (seedb.len == 0) {
mp_raise_ValueError("Invalid seed");
}
mp_buffer_info_t curveb;
mp_get_buffer_raise(curve_name, &curveb, MP_BUFFER_READ);
if (curveb.len == 0) {
mp_raise_ValueError("Invalid curve name");
}
HDNode hdnode;
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;
o->hdnode = hdnode;
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:
/// '''
/// Convert mnemonic to hdnode
/// '''
STATIC mp_obj_t mod_trezorcrypto_bip32_from_mnemonic_cardano(mp_obj_t mnemonic, mp_obj_t passphrase) {
mp_buffer_info_t mnemo, phrase;
mp_get_buffer_raise(mnemonic, &mnemo, MP_BUFFER_READ);
mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ);
HDNode hdnode;
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);
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);
if (!res) {
mp_raise_ValueError("Secret key generation from mnemonic is looping forever");
} else
if (res == -1) {
mp_raise_ValueError("Invalid mnemonic");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
STATIC mp_obj_t mod_trezorcrypto_bip32_from_mnemonic_cardano(
mp_obj_t mnemonic, mp_obj_t passphrase) {
mp_buffer_info_t mnemo, phrase;
mp_get_buffer_raise(mnemonic, &mnemo, MP_BUFFER_READ);
mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ);
HDNode hdnode;
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);
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);
if (!res) {
mp_raise_ValueError(
"Secret key generation from mnemonic is looping forever");
} else if (res == -1) {
mp_raise_ValueError("Invalid mnemonic");
}
mp_obj_HDNode_t *o = m_new_obj(mp_obj_HDNode_t);
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[] = {
{ 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_deserialize), MP_ROM_PTR(&mod_trezorcrypto_bip32_deserialize_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) },
{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_deserialize),
MP_ROM_PTR(&mod_trezorcrypto_bip32_deserialize_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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_bip32_globals,
.base = {&mp_type_module},
.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/>.
*/
#include "py/runtime.h"
#include "py/objstr.h"
#include "py/runtime.h"
#include "bip39.h"
@ -28,138 +28,157 @@
/// '''
/// Return the first word from the wordlist starting with prefix.
/// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_find_word(mp_obj_t prefix)
{
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
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));
}
}
STATIC mp_obj_t mod_trezorcrypto_bip39_find_word(mp_obj_t prefix) {
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
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;
}
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:
/// '''
/// 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)
{
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len == 0) {
return mp_obj_new_int(0xFFFFFFFF); // all letters
STATIC mp_obj_t mod_trezorcrypto_bip39_complete_word(mp_obj_t prefix) {
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len == 0) {
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;
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);
}
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:
/// '''
/// 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) {
int bits = mp_obj_get_int(strength);
if (bits % 32 || bits < 128 || bits > 256) {
mp_raise_ValueError("Invalid bit strength (only 128, 160, 192, 224 and 256 values are allowed)");
}
const char *mnemo = mnemonic_generate(bits);
mp_obj_t res = mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)mnemo, strlen(mnemo));
mnemonic_clear();
return res;
int bits = mp_obj_get_int(strength);
if (bits % 32 || bits < 128 || bits > 256) {
mp_raise_ValueError(
"Invalid bit strength (only 128, 160, 192, 224 and 256 values are "
"allowed)");
}
const char *mnemo = mnemonic_generate(bits);
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:
/// '''
/// 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) {
mp_buffer_info_t bin;
mp_get_buffer_raise(data, &bin, MP_BUFFER_READ);
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)");
}
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));
mnemonic_clear();
return res;
mp_buffer_info_t bin;
mp_get_buffer_raise(data, &bin, MP_BUFFER_READ);
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)");
}
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));
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:
/// '''
/// Check whether given mnemonic is valid.
/// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_check(mp_obj_t mnemonic) {
mp_buffer_info_t text;
mp_get_buffer_raise(mnemonic, &text, MP_BUFFER_READ);
return (text.len > 0 && mnemonic_check(text.buf)) ? mp_const_true : mp_const_false;
mp_buffer_info_t text;
mp_get_buffer_raise(mnemonic, &text, MP_BUFFER_READ);
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 void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
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));
}
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));
}
}
/// 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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_bip39_seed(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t mnemo;
mp_buffer_info_t phrase;
mp_get_buffer_raise(args[0], &mnemo, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &phrase, MP_BUFFER_READ);
uint8_t seed[64];
const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : "";
const char *ppassphrase = phrase.len > 0 ? phrase.buf : "";
if (n_args > 2) {
// generate with a progress callback
ui_wait_callback = args[2];
mnemonic_to_seed(pmnemonic, ppassphrase, seed, wrapped_ui_wait_callback);
ui_wait_callback = mp_const_none;
} else {
// generate without callback
mnemonic_to_seed(pmnemonic, ppassphrase, seed, NULL);
}
return mp_obj_new_bytes(seed, sizeof(seed));
STATIC mp_obj_t mod_trezorcrypto_bip39_seed(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t mnemo;
mp_buffer_info_t phrase;
mp_get_buffer_raise(args[0], &mnemo, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &phrase, MP_BUFFER_READ);
uint8_t seed[64];
const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : "";
const char *ppassphrase = phrase.len > 0 ? phrase.buf : "";
if (n_args > 2) {
// generate with a progress callback
ui_wait_callback = args[2];
mnemonic_to_seed(pmnemonic, ppassphrase, seed, wrapped_ui_wait_callback);
ui_wait_callback = mp_const_none;
} else {
// generate without callback
mnemonic_to_seed(pmnemonic, ppassphrase, seed, NULL);
}
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[] = {
{ 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_complete_word), MP_ROM_PTR(&mod_trezorcrypto_bip39_complete_word_obj) },
{ MP_ROM_QSTR(MP_QSTR_generate), 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) },
{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_complete_word),
MP_ROM_PTR(&mod_trezorcrypto_bip39_complete_word_obj)},
{MP_ROM_QSTR(MP_QSTR_generate),
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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_bip39_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_bip39_globals,
};

@ -29,8 +29,8 @@
/// Blake256 context.
/// '''
typedef struct _mp_obj_Blake256_t {
mp_obj_base_t base;
BLAKE256_CTX ctx;
mp_obj_base_t base;
BLAKE256_CTX ctx;
} mp_obj_Blake256_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Blake256_t *o = m_new_obj(mp_obj_Blake256_t);
o->base.type = type;
blake256_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Blake256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Blake256_t *o = m_new_obj(mp_obj_Blake256_t);
o->base.type = type;
blake256_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Blake256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake256_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake256_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Blake256_digest(mp_obj_t self) {
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
uint8_t hash[BLAKE256_DIGEST_LENGTH];
BLAKE256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE256_CTX));
blake256_Final(&ctx, hash);
memzero(&ctx, sizeof(BLAKE256_CTX));
return mp_obj_new_bytes(hash, sizeof(hash));
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
uint8_t hash[BLAKE256_DIGEST_LENGTH];
BLAKE256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE256_CTX));
blake256_Final(&ctx, hash);
memzero(&ctx, sizeof(BLAKE256_CTX));
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) {
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE256_CTX));
return mp_const_none;
mp_obj_Blake256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE256_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake256_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake256_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Blake256_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Blake256_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Blake256,
.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.
/// '''
typedef struct _mp_obj_Blake2b_t {
mp_obj_base_t base;
BLAKE2B_CTX ctx;
mp_obj_base_t base;
BLAKE2B_CTX ctx;
} mp_obj_Blake2b_t;
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.
/// '''
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 const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_outlen, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLAKE2B_DIGEST_LENGTH} },
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_personal, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
};
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);
size_t data_len;
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;
size_t key_len;
const uint8_t *key = (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
const uint8_t *personal = (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
if (key_len > 0 && personal_len > 0) {
mp_raise_ValueError("Invalid Blake2b parameters: cannot use key and personal at the same time");
}
mp_obj_Blake2b_t *o = m_new_obj(mp_obj_Blake2b_t);
o->base.type = type;
int res = 0;
if (key_len > 0) {
res = blake2b_InitKey(&(o->ctx), outlen, key, key_len);
} else if (personal_len > 0) {
res = blake2b_InitPersonal(&(o->ctx), outlen, personal, personal_len);
} 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);
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 const mp_arg_t allowed_args[] = {
{MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes}},
{MP_QSTR_outlen,
MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = BLAKE2B_DIGEST_LENGTH}},
{MP_QSTR_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_personal,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
};
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);
size_t data_len;
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;
size_t key_len;
const uint8_t *key =
(const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
const uint8_t *personal =
(const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
if (key_len > 0 && personal_len > 0) {
mp_raise_ValueError(
"Invalid Blake2b parameters: cannot use key and personal at the same "
"time");
}
mp_obj_Blake2b_t *o = m_new_obj(mp_obj_Blake2b_t);
o->base.type = type;
int res = 0;
if (key_len > 0) {
res = blake2b_InitKey(&(o->ctx), outlen, key, key_len);
} else if (personal_len > 0) {
res = blake2b_InitPersonal(&(o->ctx), outlen, personal, personal_len);
} 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:
@ -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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake2b_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake2b_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2b_digest(mp_obj_t self) {
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2B_DIGEST_LENGTH];
BLAKE2B_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2B_CTX));
blake2b_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2B_CTX));
return mp_obj_new_bytes(out, o->ctx.outlen);
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2B_DIGEST_LENGTH];
BLAKE2B_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2B_CTX));
blake2b_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2B_CTX));
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) {
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2B_CTX));
return mp_const_none;
mp_obj_Blake2b_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2B_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Blake2b_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Blake2b_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Blake2b,
.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.
/// '''
typedef struct _mp_obj_Blake2s_t {
mp_obj_base_t base;
BLAKE2S_CTX ctx;
mp_obj_base_t base;
BLAKE2S_CTX ctx;
} mp_obj_Blake2s_t;
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.
/// '''
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 const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_outlen, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = BLAKE2S_DIGEST_LENGTH} },
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_personal, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
};
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);
size_t data_len;
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;
size_t key_len;
const uint8_t *key = (const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
const uint8_t *personal = (const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
if (key_len > 0 && personal_len > 0) {
mp_raise_ValueError("Invalid Blake2s parameters: cannot use key and personal at the same time");
}
mp_obj_Blake2s_t *o = m_new_obj(mp_obj_Blake2s_t);
o->base.type = type;
int res = 0;
if (key_len > 0) {
res = blake2s_InitKey(&(o->ctx), outlen, key, key_len);
} else if (personal_len > 0) {
res = blake2s_InitPersonal(&(o->ctx), outlen, personal, personal_len);
} 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);
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 const mp_arg_t allowed_args[] = {
{MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes}},
{MP_QSTR_outlen,
MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = BLAKE2S_DIGEST_LENGTH}},
{MP_QSTR_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_personal,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
};
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);
size_t data_len;
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;
size_t key_len;
const uint8_t *key =
(const uint8_t *)mp_obj_str_get_data(vals[2].u_obj, &key_len);
size_t personal_len;
const uint8_t *personal =
(const uint8_t *)mp_obj_str_get_data(vals[3].u_obj, &personal_len);
if (key_len > 0 && personal_len > 0) {
mp_raise_ValueError(
"Invalid Blake2s parameters: cannot use key and personal at the same "
"time");
}
mp_obj_Blake2s_t *o = m_new_obj(mp_obj_Blake2s_t);
o->base.type = type;
int res = 0;
if (key_len > 0) {
res = blake2s_InitKey(&(o->ctx), outlen, key, key_len);
} else if (personal_len > 0) {
res = blake2s_InitPersonal(&(o->ctx), outlen, personal, personal_len);
} 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:
@ -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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake2s_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
blake2s_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Blake2s_digest(mp_obj_t self) {
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2S_DIGEST_LENGTH];
BLAKE2S_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2S_CTX));
blake2s_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2S_CTX));
return mp_obj_new_bytes(out, o->ctx.outlen);
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[BLAKE2S_DIGEST_LENGTH];
BLAKE2S_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(BLAKE2S_CTX));
blake2s_Final(&ctx, out, ctx.outlen);
memzero(&ctx, sizeof(BLAKE2S_CTX));
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) {
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2S_CTX));
return mp_const_none;
mp_obj_Blake2s_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(BLAKE2S_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Blake2s_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Blake2s_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Blake2s,
.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.
/// '''
typedef struct _mp_obj_ChaCha20Poly1305_t {
mp_obj_base_t base;
chacha20poly1305_ctx ctx;
int64_t alen, plen;
mp_obj_base_t base;
chacha20poly1305_ctx ctx;
int64_t alen, plen;
} mp_obj_ChaCha20Poly1305_t;
/// 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
/// 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) {
mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_obj_ChaCha20Poly1305_t *o = m_new_obj(mp_obj_ChaCha20Poly1305_t);
o->base.type = type;
mp_buffer_info_t key, nonce;
mp_get_buffer_raise(args[0], &key, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &nonce, MP_BUFFER_READ);
if (key.len != 32) {
mp_raise_ValueError("Invalid length of key");
}
if (nonce.len != 12) {
mp_raise_ValueError("Invalid length of nonce");
}
rfc7539_init(&(o->ctx), key.buf, nonce.buf);
o->alen = 0;
o->plen = 0;
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_obj_ChaCha20Poly1305_t *o = m_new_obj(mp_obj_ChaCha20Poly1305_t);
o->base.type = type;
mp_buffer_info_t key, nonce;
mp_get_buffer_raise(args[0], &key, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &nonce, MP_BUFFER_READ);
if (key.len != 32) {
mp_raise_ValueError("Invalid length of key");
}
if (nonce.len != 12) {
mp_raise_ValueError("Invalid length of nonce");
}
rfc7539_init(&(o->ctx), key.buf, nonce.buf);
o->alen = 0;
o->plen = 0;
return MP_OBJ_FROM_PTR(o);
}
/// 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) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_t vstr;
vstr_init_len(&vstr, in.len);
chacha20poly1305_encrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
o->plen += in.len;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_encrypt(mp_obj_t self,
mp_obj_t data) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_t vstr;
vstr_init_len(&vstr, in.len);
chacha20poly1305_encrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
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:
/// '''
/// 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) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_t vstr;
vstr_init_len(&vstr, in.len);
chacha20poly1305_decrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
o->plen += in.len;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_decrypt(mp_obj_t self,
mp_obj_t data) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
vstr_t vstr;
vstr_init_len(&vstr, in.len);
chacha20poly1305_decrypt(&(o->ctx), in.buf, (uint8_t *)vstr.buf, in.len);
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:
/// '''
@ -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
/// to encryption or decryption.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_auth(mp_obj_t self, mp_obj_t data) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
rfc7539_auth(&(o->ctx), in.buf, in.len);
o->alen += in.len;
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_auth(mp_obj_t self,
mp_obj_t data) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t in;
mp_get_buffer_raise(data, &in, MP_BUFFER_READ);
rfc7539_auth(&(o->ctx), in.buf, in.len);
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:
/// '''
/// Compute RFC 7539-style Poly1305 MAC.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ChaCha20Poly1305_finish(mp_obj_t self) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[16];
rfc7539_finish(&(o->ctx), o->alen, o->plen, out);
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[16];
rfc7539_finish(&(o->ctx), o->alen, o->plen, 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) {
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(chacha20poly1305_ctx));
o->alen = 0;
o->plen = 0;
return mp_const_none;
mp_obj_ChaCha20Poly1305_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(chacha20poly1305_ctx));
o->alen = 0;
o->plen = 0;
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[] = {
{ MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj) },
{ MP_ROM_QSTR(MP_QSTR_decrypt), 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 const mp_rom_map_elem_t
mod_trezorcrypto_ChaCha20Poly1305_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_encrypt),
MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_encrypt_obj)},
{MP_ROM_QSTR(MP_QSTR_decrypt),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_ChaCha20Poly1305,
.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"
mp_obj_t mod_trezorcrypto_crc_crc32(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
uint32_t crc = (n_args > 1) ? trezor_obj_get_uint(args[1]) : 0;
crc = checksum_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
uint32_t crc = (n_args > 1) ? trezor_obj_get_uint(args[1]) : 0;
crc = checksum_crc32(bufinfo.buf, bufinfo.len, 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[] = {
{ 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___name__), MP_ROM_QSTR(MP_QSTR_crc)},
{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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_crc_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_crc_globals,
};

@ -30,62 +30,71 @@
/// Generate secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_generate_secret() {
uint8_t out[32];
random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html
out[0] &= 248;
out[31] &= 127;
out[31] |= 64;
return mp_obj_new_bytes(out, sizeof(out));
uint8_t out[32];
random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html
out[0] &= 248;
out[31] &= 127;
out[31] |= 64;
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:
/// '''
/// Computes public key from secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_publickey(mp_obj_t secret_key) {
mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
uint8_t out[32];
curve25519_scalarmult_basepoint(out, (const uint8_t *)sk.buf);
return mp_obj_new_bytes(out, sizeof(out));
mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
uint8_t out[32];
curve25519_scalarmult_basepoint(out, (const uint8_t *)sk.buf);
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:
/// '''
/// Multiplies point defined by public_key with scalar defined by secret_key.
/// Useful for ECDH.
/// Multiplies point defined by public_key with scalar defined by
/// secret_key. Useful for ECDH.
/// '''
STATIC mp_obj_t mod_trezorcrypto_curve25519_multiply(mp_obj_t secret_key, mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret 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);
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_curve25519_multiply(mp_obj_t secret_key,
mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret 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);
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[] = {
{ 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_publickey), MP_ROM_PTR(&mod_trezorcrypto_curve25519_publickey_obj) },
{ MP_ROM_QSTR(MP_QSTR_multiply), MP_ROM_PTR(&mod_trezorcrypto_curve25519_multiply_obj) },
{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_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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_curve25519_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_curve25519_globals,
};

@ -19,8 +19,8 @@
#include "py/objstr.h"
#include "ed25519-donna/ed25519.h"
#include "ed25519-donna/ed25519-keccak.h"
#include "ed25519-donna/ed25519.h"
#include "rand.h"
@ -31,220 +31,266 @@
/// Generate secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_generate_secret() {
uint8_t out[32];
random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html
out[0] &= 248;
out[31] &= 127;
out[31] |= 64;
return mp_obj_new_bytes(out, sizeof(out));
uint8_t out[32];
random_buffer(out, 32);
// taken from https://cr.yp.to/ecdh.html
out[0] &= 248;
out[31] &= 127;
out[31] |= 64;
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:
/// '''
/// Computes public key from secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_publickey(mp_obj_t secret_key) {
mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
uint8_t out[32];
ed25519_publickey(*(const ed25519_secret_key *)sk.buf, *(ed25519_public_key *)out);
return mp_obj_new_bytes(out, sizeof(out));
mp_buffer_info_t sk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
uint8_t out[32];
ed25519_publickey(*(const ed25519_secret_key *)sk.buf,
*(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:
/// '''
/// 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) {
mp_buffer_info_t sk, msg;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (msg.len == 0) {
mp_raise_ValueError("Empty data to sign");
}
ed25519_public_key pk;
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 hash_func == 'keccak':
if (memcmp(hash_func.buf, "keccak", sizeof("keccak")) == 0) {
ed25519_publickey_keccak(*(const ed25519_secret_key *)sk.buf, pk);
ed25519_sign_keccak(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, pk, *(ed25519_signature *)out);
} else {
mp_raise_ValueError("Unknown hash function");
}
STATIC mp_obj_t mod_trezorcrypto_ed25519_sign(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk, msg;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (msg.len == 0) {
mp_raise_ValueError("Empty data to sign");
}
ed25519_public_key pk;
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 hash_func == 'keccak':
if (memcmp(hash_func.buf, "keccak", sizeof("keccak")) == 0) {
ed25519_publickey_keccak(*(const ed25519_secret_key *)sk.buf, pk);
ed25519_sign_keccak(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);
mp_raise_ValueError("Unknown hash function");
}
} 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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_key, mp_obj_t secret_extension, mp_obj_t message) {
mp_buffer_info_t sk, skext, msg;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(secret_extension, &skext, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (skext.len != 32) {
mp_raise_ValueError("Invalid length of secret key extension");
}
if (msg.len == 0) {
mp_raise_ValueError("Empty data to sign");
}
ed25519_public_key pk;
STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_key,
mp_obj_t secret_extension,
mp_obj_t message) {
mp_buffer_info_t sk, skext, msg;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(secret_extension, &skext, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (skext.len != 32) {
mp_raise_ValueError("Invalid length of secret key extension");
}
if (msg.len == 0) {
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);
uint8_t out[64];
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));
ed25519_publickey_ext(*(const ed25519_secret_key *)sk.buf,
*(const ed25519_secret_key *)skext.buf, pk);
uint8_t out[64];
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:
/// '''
/// Uses public key to verify the signature of the message.
/// 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) {
mp_buffer_info_t pk, sig, msg;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
if (pk.len != 32) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64) {
mp_raise_ValueError("Invalid length of signature");
}
if (msg.len == 0) {
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_obj_t mod_trezorcrypto_ed25519_verify(mp_obj_t public_key,
mp_obj_t signature,
mp_obj_t message) {
mp_buffer_info_t pk, sig, msg;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
if (pk.len != 32) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64) {
mp_raise_ValueError("Invalid length of signature");
}
if (msg.len == 0) {
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:
/// '''
/// 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) {
size_t pklen;
mp_obj_t *pkitems;
mp_obj_get_array(public_keys, &pklen, &pkitems);
if (pklen > 15) {
mp_raise_ValueError("Can't combine more than 15 public keys");
}
mp_buffer_info_t buf;
ed25519_public_key pks[pklen];
for (int i = 0; i < pklen; i++) {
mp_get_buffer_raise(pkitems[i], &buf, MP_BUFFER_READ);
if (buf.len != 32) {
mp_raise_ValueError("Invalid length of public key");
}
memcpy(pks[i], buf.buf, buf.len);
STATIC mp_obj_t
mod_trezorcrypto_ed25519_cosi_combine_publickeys(mp_obj_t public_keys) {
size_t pklen;
mp_obj_t *pkitems;
mp_obj_get_array(public_keys, &pklen, &pkitems);
if (pklen > 15) {
mp_raise_ValueError("Can't combine more than 15 public keys");
}
mp_buffer_info_t buf;
ed25519_public_key pks[pklen];
for (int i = 0; i < pklen; i++) {
mp_get_buffer_raise(pkitems[i], &buf, MP_BUFFER_READ);
if (buf.len != 32) {
mp_raise_ValueError("Invalid length of public key");
}
uint8_t out[32];
if (0 != 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));
memcpy(pks[i], buf.buf, buf.len);
}
uint8_t out[32];
if (0 !=
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:
/// '''
/// 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) {
mp_buffer_info_t sigR;
mp_get_buffer_raise(R, &sigR, MP_BUFFER_READ);
if (sigR.len != 32) {
mp_raise_ValueError("Invalid length of R");
}
size_t siglen;
mp_obj_t *sigitems;
mp_obj_get_array(signatures, &siglen, &sigitems);
if (siglen > 15) {
mp_raise_ValueError("Can't combine more than 15 COSI signatures");
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_combine_signatures(
mp_obj_t R, mp_obj_t signatures) {
mp_buffer_info_t sigR;
mp_get_buffer_raise(R, &sigR, MP_BUFFER_READ);
if (sigR.len != 32) {
mp_raise_ValueError("Invalid length of R");
}
size_t siglen;
mp_obj_t *sigitems;
mp_obj_get_array(signatures, &siglen, &sigitems);
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;
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");
}
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));
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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t sk, msg, nonce, sigR, pk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
mp_get_buffer_raise(args[2], &nonce, MP_BUFFER_READ);
mp_get_buffer_raise(args[3], &sigR, MP_BUFFER_READ);
mp_get_buffer_raise(args[4], &pk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (nonce.len != 32) {
mp_raise_ValueError("Invalid length of nonce");
}
if (sigR.len != 32) {
mp_raise_ValueError("Invalid length of R");
}
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);
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk, msg, nonce, sigR, pk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &msg, MP_BUFFER_READ);
mp_get_buffer_raise(args[2], &nonce, MP_BUFFER_READ);
mp_get_buffer_raise(args[3], &sigR, MP_BUFFER_READ);
mp_get_buffer_raise(args[4], &pk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
if (nonce.len != 32) {
mp_raise_ValueError("Invalid length of nonce");
}
if (sigR.len != 32) {
mp_raise_ValueError("Invalid length of R");
}
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);
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[] = {
{ 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_publickey), MP_ROM_PTR(&mod_trezorcrypto_ed25519_publickey_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign_ext), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_ext_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) },
{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_publickey),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_obj)},
{MP_ROM_QSTR(MP_QSTR_sign_ext),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_sign_ext_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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_ed25519_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_ed25519_globals,
};

@ -32,76 +32,90 @@
/// GROESTL512 context.
/// '''
typedef struct _mp_obj_Groestl512_t {
mp_obj_base_t base;
GROESTL512_CTX ctx;
mp_obj_base_t base;
GROESTL512_CTX ctx;
} 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:
/// '''
/// 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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Groestl512_t *o = m_new_obj(mp_obj_Groestl512_t);
o->base.type = type;
groestl512_Init(&(o->ctx));
if (n_args == 1) {
mod_trezorcrypto_Groestl512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Groestl512_t *o = m_new_obj(mp_obj_Groestl512_t);
o->base.type = type;
groestl512_Init(&(o->ctx));
if (n_args == 1) {
mod_trezorcrypto_Groestl512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// def update(self, data: bytes) -> None:
/// '''
/// Update the hash context with hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
groestl512_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_Groestl512_update(mp_obj_t self,
mp_obj_t data) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
groestl512_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Groestl512_digest(mp_obj_t self) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[GROESTL512_DIGEST_LENGTH];
GROESTL512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(GROESTL512_CTX));
groestl512_Final(&ctx, out);
memzero(&ctx, sizeof(GROESTL512_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[GROESTL512_DIGEST_LENGTH];
GROESTL512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(GROESTL512_CTX));
groestl512_Final(&ctx, out);
memzero(&ctx, sizeof(GROESTL512_CTX));
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) {
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(GROESTL512_CTX));
return mp_const_none;
mp_obj_Groestl512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(GROESTL512_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Groestl512_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), 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 const mp_rom_map_elem_t
mod_trezorcrypto_Groestl512_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Groestl512_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Groestl512,
.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
/// '''
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;
mp_get_buffer_raise(address, &addr, MP_BUFFER_READ);
uint32_t n = trezor_obj_get_uint(network);
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:
/// '''
/// 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) {
mp_buffer_info_t p;
mp_get_buffer_raise(public_key, &p, MP_BUFFER_READ);
STATIC mp_obj_t mod_trezorcrypto_nem_compute_address(mp_obj_t public_key,
mp_obj_t network) {
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
if (!nem_get_address(p.buf, n, address)) {
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));
char address[NEM_ADDRESS_SIZE + 1]; // + 1 for the 0 byte
if (!nem_get_address(p.buf, n, address)) {
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));
}
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
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_compute_address), MP_ROM_PTR(&mod_trezorcrypto_nem_compute_address_obj) },
{MP_ROM_QSTR(MP_QSTR_validate_address),
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
STATIC const mp_obj_module_t mod_trezorcrypto_nem_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_nem_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_nem_globals,
};

@ -29,158 +29,199 @@
/// Generate secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_generate_secret() {
uint8_t out[32];
for (;;) {
random_buffer(out, 32);
// 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 <= 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));
uint8_t out[32];
for (;;) {
random_buffer(out, 32);
// 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 <=
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:
/// '''
/// Computes public key from secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_publickey(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t sk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
bool compressed = n_args < 2 || args[1] == mp_const_true;
if (compressed) {
uint8_t out[33];
ecdsa_get_public_key33(&nist256p1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
} else {
uint8_t out[65];
ecdsa_get_public_key65(&nist256p1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
}
STATIC mp_obj_t mod_trezorcrypto_nist256p1_publickey(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
bool compressed = n_args < 2 || args[1] == mp_const_true;
if (compressed) {
uint8_t out[33];
ecdsa_get_public_key33(&nist256p1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
} else {
uint8_t out[65];
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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_sign(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
bool compressed = n_args < 3 || args[2] == mp_const_true;
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
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)) {
mp_raise_ValueError("Signing failed");
}
out[0] = 27 + pby + compressed * 4;
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_nist256p1_sign(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
bool compressed = n_args < 3 || args[2] == mp_const_true;
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
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)) {
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_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:
/// '''
/// Uses public key to verify the signature of the digest.
/// 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) {
mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64 && sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
int offset = sig.len - 64;
if (dig.len != 32) {
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_obj_t mod_trezorcrypto_nist256p1_verify(mp_obj_t public_key,
mp_obj_t signature,
mp_obj_t digest) {
mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64 && sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
int offset = sig.len - 64;
if (dig.len != 32) {
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:
/// '''
/// Uses signature of the digest to verify the digest and recover the public key.
/// Returns public key on success, None on failure.
/// Uses signature of the digest to verify the digest and recover the public
/// 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) {
mp_buffer_info_t sig, dig;
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest");
}
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
if (recid >= 8) {
mp_raise_ValueError("Invalid recid in signature");
}
bool compressed = (recid >= 4);
recid &= 3;
uint8_t out[65];
if (0 == ecdsa_recover_pub_from_sig(&nist256p1, out, (const uint8_t *)sig.buf + 1, (const uint8_t *)dig.buf, recid)) {
if (compressed) {
out[0] = 0x02 | (out[64] & 1);
return mp_obj_new_bytes(out, 33);
}
return mp_obj_new_bytes(out, sizeof(out));
} else {
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_nist256p1_verify_recover(mp_obj_t signature,
mp_obj_t digest) {
mp_buffer_info_t sig, dig;
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest");
}
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
if (recid >= 8) {
mp_raise_ValueError("Invalid recid in signature");
}
bool compressed = (recid >= 4);
recid &= 3;
uint8_t out[65];
if (0 == ecdsa_recover_pub_from_sig(&nist256p1, out,
(const uint8_t *)sig.buf + 1,
(const uint8_t *)dig.buf, recid)) {
if (compressed) {
out[0] = 0x02 | (out[64] & 1);
return mp_obj_new_bytes(out, 33);
}
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:
/// '''
/// Multiplies point defined by public_key with scalar defined by secret_key.
/// Useful for ECDH.
/// Multiplies point defined by public_key with scalar defined by
/// secret_key. Useful for ECDH.
/// '''
STATIC mp_obj_t mod_trezorcrypto_nist256p1_multiply(mp_obj_t secret_key, mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
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");
}
uint8_t out[65];
if (0 != ecdh_multiply(&nist256p1, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf, out)) {
mp_raise_ValueError("Multiply failed");
}
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_nist256p1_multiply(mp_obj_t secret_key,
mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
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");
}
uint8_t out[65];
if (0 != ecdh_multiply(&nist256p1, (const uint8_t *)sk.buf,
(const uint8_t *)pk.buf, 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[] = {
{ 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_publickey), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_publickey_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign), 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) },
{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_publickey),
MP_ROM_PTR(&mod_trezorcrypto_nist256p1_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_sign),
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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_nist256p1_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_nist256p1_globals,
};

@ -19,8 +19,8 @@
#include "py/objstr.h"
#include "pbkdf2.h"
#include "memzero.h"
#include "pbkdf2.h"
#define PRF_HMAC_SHA256 256
#define PRF_HMAC_SHA512 512
@ -32,121 +32,132 @@
/// PBKDF2 context.
/// '''
typedef struct _mp_obj_Pbkdf2_t {
mp_obj_base_t base;
union {
PBKDF2_HMAC_SHA256_CTX ctx256;
PBKDF2_HMAC_SHA512_CTX ctx512;
};
uint32_t prf;
mp_obj_base_t base;
union {
PBKDF2_HMAC_SHA256_CTX ctx256;
PBKDF2_HMAC_SHA512_CTX ctx512;
};
uint32_t prf;
} mp_obj_Pbkdf2_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 3, 4, false);
mp_obj_Pbkdf2_t *o = m_new_obj(mp_obj_Pbkdf2_t);
o->base.type = type;
mp_buffer_info_t password;
mp_get_buffer_raise(args[1], &password, MP_BUFFER_READ);
mp_buffer_info_t salt;
mp_get_buffer_raise(args[2], &salt, MP_BUFFER_READ);
if (password.len == 0) {
password.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]);
}
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);
} else
if (o->prf == PRF_HMAC_SHA512) {
pbkdf2_hmac_sha512_Init(&(o->ctx512), password.buf, password.len, salt.buf, salt.len, blocknr);
} else {
mp_raise_ValueError("Invalid PRF");
}
// constructor called with iterations as fourth parameter
if (n_args > 3) {
mod_trezorcrypto_Pbkdf2_update(MP_OBJ_FROM_PTR(o), args[3]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 3, 4, false);
mp_obj_Pbkdf2_t *o = m_new_obj(mp_obj_Pbkdf2_t);
o->base.type = type;
mp_buffer_info_t password;
mp_get_buffer_raise(args[1], &password, MP_BUFFER_READ);
mp_buffer_info_t salt;
mp_get_buffer_raise(args[2], &salt, MP_BUFFER_READ);
if (password.len == 0) {
password.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]);
}
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);
} else if (o->prf == PRF_HMAC_SHA512) {
pbkdf2_hmac_sha512_Init(&(o->ctx512), password.buf, password.len, salt.buf,
salt.len, blocknr);
} else {
mp_raise_ValueError("Invalid PRF");
}
// constructor called with iterations as fourth parameter
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:
/// '''
/// Update a PBKDF2 context.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self, mp_obj_t iterations) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
uint32_t iter = trezor_obj_get_uint(iterations);
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);
}
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_update(mp_obj_t self,
mp_obj_t iterations) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
uint32_t iter = trezor_obj_get_uint(iterations);
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);
}
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:
/// '''
/// Retrieve derived key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Pbkdf2_key(mp_obj_t self) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
if (o->prf == PRF_HMAC_SHA256) {
PBKDF2_HMAC_SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
uint8_t out[SHA256_DIGEST_LENGTH];
pbkdf2_hmac_sha256_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
return mp_obj_new_bytes(out, sizeof(out));
}
if (o->prf == PRF_HMAC_SHA512) {
PBKDF2_HMAC_SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
uint8_t out[SHA512_DIGEST_LENGTH];
pbkdf2_hmac_sha512_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA512_CTX));
return mp_obj_new_bytes(out, sizeof(out));
}
return mp_const_none;
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
if (o->prf == PRF_HMAC_SHA256) {
PBKDF2_HMAC_SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
uint8_t out[SHA256_DIGEST_LENGTH];
pbkdf2_hmac_sha256_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
return mp_obj_new_bytes(out, sizeof(out));
}
if (o->prf == PRF_HMAC_SHA512) {
PBKDF2_HMAC_SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
uint8_t out[SHA512_DIGEST_LENGTH];
pbkdf2_hmac_sha512_Final(&ctx, out);
memzero(&ctx, sizeof(PBKDF2_HMAC_SHA512_CTX));
return mp_obj_new_bytes(out, sizeof(out));
}
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) {
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
memzero(&(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
return mp_const_none;
mp_obj_Pbkdf2_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx256), sizeof(PBKDF2_HMAC_SHA256_CTX));
memzero(&(o->ctx512), sizeof(PBKDF2_HMAC_SHA512_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_key), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_key_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_update_obj)},
{MP_ROM_QSTR(MP_QSTR_key), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_key_obj)},
{MP_ROM_QSTR(MP_QSTR___del__),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Pbkdf2,
.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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_random_uniform(mp_obj_t n) {
uint32_t nn = trezor_obj_get_uint(n);
if (nn == 0) {
mp_raise_ValueError("Maximum can't be zero");
}
return mp_obj_new_int_from_uint(random_uniform(nn));
uint32_t nn = trezor_obj_get_uint(n);
if (nn == 0) {
mp_raise_ValueError("Maximum can't be zero");
}
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:
/// '''
/// Generate random bytes sequence of length len.
/// '''
STATIC mp_obj_t mod_trezorcrypto_random_bytes(mp_obj_t len) {
uint32_t l = trezor_obj_get_uint(len);
if (l > 1024) {
mp_raise_ValueError("Maximum requested size is 1024");
}
vstr_t vstr;
vstr_init_len(&vstr, l);
random_buffer((uint8_t *)vstr.buf, l);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
uint32_t l = trezor_obj_get_uint(len);
if (l > 1024) {
mp_raise_ValueError("Maximum requested size is 1024");
}
vstr_t vstr;
vstr_init_len(&vstr, l);
random_buffer((uint8_t *)vstr.buf, l);
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:
/// '''
/// Shuffles items of given list (in-place).
/// '''
STATIC mp_obj_t mod_trezorcrypto_random_shuffle(mp_obj_t data) {
size_t count;
mp_obj_t *items;
mp_obj_get_array(data, &count, &items);
if (count > 256) {
mp_raise_ValueError("Maximum list size is 256 items");
}
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;
}
size_t count;
mp_obj_t *items;
mp_obj_get_array(data, &count, &items);
if (count > 256) {
mp_raise_ValueError("Maximum list size is 256 items");
}
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;
}
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[] = {
{ 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_bytes), MP_ROM_PTR(&mod_trezorcrypto_random_bytes_obj) },
{ MP_ROM_QSTR(MP_QSTR_shuffle), MP_ROM_PTR(&mod_trezorcrypto_random_shuffle_obj) },
{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_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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_random_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_random_globals,
};

@ -28,29 +28,31 @@
/// RFC6979 context.
/// '''
typedef struct _mp_obj_Rfc6979_t {
mp_obj_base_t base;
rfc6979_state rng;
mp_obj_base_t base;
rfc6979_state rng;
} mp_obj_Rfc6979_t;
/// def __init__(self, secret_key: bytes, hash: bytes) -> None:
/// '''
/// 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) {
mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_obj_Rfc6979_t *o = m_new_obj(mp_obj_Rfc6979_t);
o->base.type = type;
mp_buffer_info_t pkey, hash;
mp_get_buffer_raise(args[0], &pkey, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ);
if (pkey.len != 32) {
mp_raise_ValueError("Secret key has to be 32 bytes long");
}
if (hash.len != 32) {
mp_raise_ValueError("Hash has to be 32 bytes long");
}
init_rfc6979((const uint8_t *)pkey.buf, (const uint8_t *)hash.buf, &(o->rng));
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 2, 2, false);
mp_obj_Rfc6979_t *o = m_new_obj(mp_obj_Rfc6979_t);
o->base.type = type;
mp_buffer_info_t pkey, hash;
mp_get_buffer_raise(args[0], &pkey, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &hash, MP_BUFFER_READ);
if (pkey.len != 32) {
mp_raise_ValueError("Secret key has to be 32 bytes long");
}
if (hash.len != 32) {
mp_raise_ValueError("Hash has to be 32 bytes long");
}
init_rfc6979((const uint8_t *)pkey.buf, (const uint8_t *)hash.buf, &(o->rng));
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Rfc6979_next(mp_obj_t self) {
mp_obj_Rfc6979_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[32];
generate_rfc6979(out, &(o->rng));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Rfc6979_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[32];
generate_rfc6979(out, &(o->rng));
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[] = {
{ 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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Rfc6979,
.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 "ripemd160.h"
#include "memzero.h"
#include "ripemd160.h"
/// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// RIPEMD160 context.
/// '''
typedef struct _mp_obj_Ripemd160_t {
mp_obj_base_t base;
RIPEMD160_CTX ctx;
mp_obj_base_t base;
RIPEMD160_CTX ctx;
} mp_obj_Ripemd160_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Ripemd160_t *o = m_new_obj(mp_obj_Ripemd160_t);
o->base.type = type;
ripemd160_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Ripemd160_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Ripemd160_t *o = m_new_obj(mp_obj_Ripemd160_t);
o->base.type = type;
ripemd160_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Ripemd160_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// def update(self, data: bytes) -> None:
/// '''
/// Update the hash context with hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
ripemd160_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self,
mp_obj_t data) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
ripemd160_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Ripemd160_digest(mp_obj_t self) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[RIPEMD160_DIGEST_LENGTH];
RIPEMD160_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(RIPEMD160_CTX));
ripemd160_Final(&ctx, out);
memzero(&ctx, sizeof(RIPEMD160_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[RIPEMD160_DIGEST_LENGTH];
RIPEMD160_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(RIPEMD160_CTX));
ripemd160_Final(&ctx, out);
memzero(&ctx, sizeof(RIPEMD160_CTX));
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) {
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(RIPEMD160_CTX));
return mp_const_none;
mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(RIPEMD160_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), 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 const mp_rom_map_elem_t
mod_trezorcrypto_Ripemd160_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Ripemd160,
.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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_generate_secret() {
uint8_t out[32];
for (;;) {
random_buffer(out, 32);
// 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 <= 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));
uint8_t out[32];
for (;;) {
random_buffer(out, 32);
// 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 <=
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:
/// '''
/// Computes public key from secret key.
/// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_publickey(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t sk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
bool compressed = n_args < 2 || args[1] == mp_const_true;
if (compressed) {
uint8_t out[33];
ecdsa_get_public_key33(&secp256k1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
} else {
uint8_t out[65];
ecdsa_get_public_key65(&secp256k1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
}
STATIC mp_obj_t mod_trezorcrypto_secp256k1_publickey(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
bool compressed = n_args < 2 || args[1] == mp_const_true;
if (compressed) {
uint8_t out[33];
ecdsa_get_public_key33(&secp256k1, (const uint8_t *)sk.buf, out);
return mp_obj_new_bytes(out, sizeof(out));
} else {
uint8_t out[65];
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])
{
(void)signature;
return (v & 2) == 0;
static int ethereum_is_canonical(uint8_t v, uint8_t signature[64]) {
(void)signature;
return (v & 2) == 0;
}
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.
/// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_sign(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
bool compressed = (n_args < 3) || (args[2] == mp_const_true);
mp_int_t canonical = (n_args > 3) ? mp_obj_get_int(args[3]) : 0;
int (*is_canonical)(uint8_t by, uint8_t sig[64]) = NULL;
switch (canonical) {
case CANONICAL_SIG_ETHEREUM:
is_canonical = ethereum_is_canonical;
break;
}
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
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)) {
mp_raise_ValueError("Signing failed");
}
out[0] = 27 + pby + compressed * 4;
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_secp256k1_sign(size_t n_args,
const mp_obj_t *args) {
mp_buffer_info_t sk, dig;
mp_get_buffer_raise(args[0], &sk, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &dig, MP_BUFFER_READ);
bool compressed = (n_args < 3) || (args[2] == mp_const_true);
mp_int_t canonical = (n_args > 3) ? mp_obj_get_int(args[3]) : 0;
int (*is_canonical)(uint8_t by, uint8_t sig[64]) = NULL;
switch (canonical) {
case CANONICAL_SIG_ETHEREUM:
is_canonical = ethereum_is_canonical;
break;
}
if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key");
}
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)) {
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:
/// '''
/// Uses public key to verify the signature of the digest.
/// 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) {
mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64 && sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
int offset = sig.len - 64;
if (dig.len != 32) {
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_obj_t mod_trezorcrypto_secp256k1_verify(mp_obj_t public_key,
mp_obj_t signature,
mp_obj_t digest) {
mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key");
}
if (sig.len != 64 && sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
int offset = sig.len - 64;
if (dig.len != 32) {
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:
/// '''
/// Uses signature of the digest to verify the digest and recover the public key.
/// Returns public key on success, None on failure.
/// Uses signature of the digest to verify the digest and recover the public
/// 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) {
mp_buffer_info_t sig, dig;
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest");
}
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
if (recid >= 8) {
mp_raise_ValueError("Invalid recid in signature");
}
bool compressed = (recid >= 4);
recid &= 3;
uint8_t out[65];
if (0 == ecdsa_recover_pub_from_sig(&secp256k1, out, (const uint8_t *)sig.buf + 1, (const uint8_t *)dig.buf, recid)) {
if (compressed) {
out[0] = 0x02 | (out[64] & 1);
return mp_obj_new_bytes(out, 33);
}
return mp_obj_new_bytes(out, sizeof(out));
} else {
return mp_const_none;
STATIC mp_obj_t mod_trezorcrypto_secp256k1_verify_recover(mp_obj_t signature,
mp_obj_t digest) {
mp_buffer_info_t sig, dig;
mp_get_buffer_raise(signature, &sig, MP_BUFFER_READ);
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature");
}
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest");
}
uint8_t recid = ((const uint8_t *)sig.buf)[0] - 27;
if (recid >= 8) {
mp_raise_ValueError("Invalid recid in signature");
}
bool compressed = (recid >= 4);
recid &= 3;
uint8_t out[65];
if (0 == ecdsa_recover_pub_from_sig(&secp256k1, out,
(const uint8_t *)sig.buf + 1,
(const uint8_t *)dig.buf, recid)) {
if (compressed) {
out[0] = 0x02 | (out[64] & 1);
return mp_obj_new_bytes(out, 33);
}
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:
/// '''
/// Multiplies point defined by public_key with scalar defined by secret_key.
/// Useful for ECDH.
/// Multiplies point defined by public_key with scalar defined by
/// secret_key. Useful for ECDH.
/// '''
STATIC mp_obj_t mod_trezorcrypto_secp256k1_multiply(mp_obj_t secret_key, mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
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");
}
uint8_t out[65];
if (0 != ecdh_multiply(&secp256k1, (const uint8_t *)sk.buf, (const uint8_t *)pk.buf, out)) {
mp_raise_ValueError("Multiply failed");
}
return mp_obj_new_bytes(out, sizeof(out));
STATIC mp_obj_t mod_trezorcrypto_secp256k1_multiply(mp_obj_t secret_key,
mp_obj_t public_key) {
mp_buffer_info_t sk, pk;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(public_key, &pk, MP_BUFFER_READ);
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");
}
uint8_t out[65];
if (0 != ecdh_multiply(&secp256k1, (const uint8_t *)sk.buf,
(const uint8_t *)pk.buf, 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[] = {
{ 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_publickey), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_publickey_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_secp256k1_sign_obj) },
{ 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) },
{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_publickey),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_publickey_obj)},
{MP_ROM_QSTR(MP_QSTR_sign),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_sign_obj)},
{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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mod_trezorcrypto_secp256k1_globals,
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_secp256k1_globals,
};

@ -19,8 +19,8 @@
#include "py/objstr.h"
#include "sha2.h"
#include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA1 context.
/// '''
typedef struct _mp_obj_Sha1_t {
mp_obj_base_t base;
SHA1_CTX ctx;
mp_obj_base_t base;
SHA1_CTX ctx;
} mp_obj_Sha1_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha1_t *o = m_new_obj(mp_obj_Sha1_t);
o->base.type = type;
sha1_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha1_t *o = m_new_obj(mp_obj_Sha1_t);
o->base.type = type;
sha1_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha1_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha1_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Sha1_digest(mp_obj_t self) {
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA1_DIGEST_LENGTH];
SHA1_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA1_CTX));
sha1_Final(&ctx, out);
memzero(&ctx, sizeof(SHA1_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA1_DIGEST_LENGTH];
SHA1_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA1_CTX));
sha1_Final(&ctx, out);
memzero(&ctx, sizeof(SHA1_CTX));
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) {
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA1_CTX));
return mp_const_none;
mp_obj_Sha1_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA1_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha1_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha1_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Sha1_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Sha1_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Sha1,
.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 "sha2.h"
#include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA256 context.
/// '''
typedef struct _mp_obj_Sha256_t {
mp_obj_base_t base;
SHA256_CTX ctx;
mp_obj_base_t base;
SHA256_CTX ctx;
} mp_obj_Sha256_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha256_t *o = m_new_obj(mp_obj_Sha256_t);
o->base.type = type;
sha256_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha256_t *o = m_new_obj(mp_obj_Sha256_t);
o->base.type = type;
sha256_Init(&(o->ctx));
// constructor called with bytes/str as first parameter
if (n_args == 1) {
mod_trezorcrypto_Sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha256_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha256_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Sha256_digest(mp_obj_t self) {
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA256_CTX));
sha256_Final(&ctx, out);
memzero(&ctx, sizeof(SHA256_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA256_DIGEST_LENGTH];
SHA256_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA256_CTX));
sha256_Final(&ctx, out);
memzero(&ctx, sizeof(SHA256_CTX));
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) {
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA256_CTX));
return mp_const_none;
mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA256_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha256_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha256_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Sha256_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Sha256_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Sha256,
.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 "sha3.h"
#include "memzero.h"
#include "sha3.h"
/// package: trezorcrypto.__init__
@ -29,9 +29,9 @@
/// SHA3_256 context.
/// '''
typedef struct _mp_obj_Sha3_256_t {
mp_obj_base_t base;
SHA3_CTX ctx;
bool keccak;
mp_obj_base_t base;
SHA3_CTX ctx;
bool keccak;
} mp_obj_Sha3_256_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, true);
mp_obj_Sha3_256_t *o = m_new_obj(mp_obj_Sha3_256_t);
o->base.type = type;
o->keccak = 0;
sha3_256_Init(&(o->ctx));
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, true);
mp_obj_Sha3_256_t *o = m_new_obj(mp_obj_Sha3_256_t);
o->base.type = type;
o->keccak = 0;
sha3_256_Init(&(o->ctx));
STATIC const mp_arg_t allowed_args[] = {
{ 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_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);
if (vals[1].u_obj != MP_OBJ_NULL){
o->keccak = mp_obj_is_true(vals[1].u_obj);
}
STATIC const mp_arg_t allowed_args[] = {
{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_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);
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){
mod_trezorcrypto_Sha3_256_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
}
return MP_OBJ_FROM_PTR(o);
if (vals[0].u_obj != mp_const_none) {
mod_trezorcrypto_Sha3_256_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_digest(mp_obj_t self) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_256_DIGEST_LENGTH];
SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) {
keccak_Final(&ctx, out);
} else {
sha3_Final(&ctx, out);
}
memzero(&ctx, sizeof(SHA3_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_256_DIGEST_LENGTH];
SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) {
keccak_Final(&ctx, out);
} else {
sha3_Final(&ctx, out);
}
memzero(&ctx, sizeof(SHA3_CTX));
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:
/// '''
/// 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) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(args[0]);
mp_obj_Sha3_256_t *out = m_new_obj(mp_obj_Sha3_256_t);
out->base.type = o->base.type;
out->keccak = o->keccak;
memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX));
return MP_OBJ_FROM_PTR(out);
STATIC mp_obj_t mod_trezorcrypto_Sha3_256_copy(size_t n_args,
const mp_obj_t *args) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(args[0]);
mp_obj_Sha3_256_t *out = m_new_obj(mp_obj_Sha3_256_t);
out->base.type = o->base.type;
out->keccak = o->keccak;
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) {
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX));
return mp_const_none;
mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_digest_obj) },
{ MP_ROM_QSTR(MP_QSTR_copy), 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_256_digest_obj)},
{MP_ROM_QSTR(MP_QSTR_copy),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Sha3_256,
.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 "sha3.h"
#include "memzero.h"
#include "sha3.h"
/// package: trezorcrypto.__init__
@ -29,9 +29,9 @@
/// SHA3_512 context.
/// '''
typedef struct _mp_obj_Sha3_512_t {
mp_obj_base_t base;
SHA3_CTX ctx;
bool keccak;
mp_obj_base_t base;
SHA3_CTX ctx;
bool keccak;
} mp_obj_Sha3_512_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, true);
mp_obj_Sha3_512_t *o = m_new_obj(mp_obj_Sha3_512_t);
o->base.type = type;
o->keccak = 0;
sha3_512_Init(&(o->ctx));
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, true);
mp_obj_Sha3_512_t *o = m_new_obj(mp_obj_Sha3_512_t);
o->base.type = type;
o->keccak = 0;
sha3_512_Init(&(o->ctx));
STATIC const mp_arg_t allowed_args[] = {
{ 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_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);
if (vals[1].u_obj != MP_OBJ_NULL){
o->keccak = mp_obj_is_true(vals[1].u_obj);
}
STATIC const mp_arg_t allowed_args[] = {
{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_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);
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){
mod_trezorcrypto_Sha3_512_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
}
return MP_OBJ_FROM_PTR(o);
if (vals[0].u_obj != mp_const_none) {
mod_trezorcrypto_Sha3_512_update(MP_OBJ_FROM_PTR(o), vals[0].u_obj);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha3_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_digest(mp_obj_t self) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_512_DIGEST_LENGTH];
SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) {
keccak_Final(&ctx, out);
} else {
sha3_Final(&ctx, out);
}
memzero(&ctx, sizeof(SHA3_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA3_512_DIGEST_LENGTH];
SHA3_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA3_CTX));
if (o->keccak) {
keccak_Final(&ctx, out);
} else {
sha3_Final(&ctx, out);
}
memzero(&ctx, sizeof(SHA3_CTX));
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:
/// '''
/// 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) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(args[0]);
mp_obj_Sha3_512_t *out = m_new_obj(mp_obj_Sha3_512_t);
out->base.type = o->base.type;
out->keccak = o->keccak;
memcpy(&(out->ctx), &(o->ctx), sizeof(SHA3_CTX));
return MP_OBJ_FROM_PTR(out);
STATIC mp_obj_t mod_trezorcrypto_Sha3_512_copy(size_t n_args,
const mp_obj_t *args) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(args[0]);
mp_obj_Sha3_512_t *out = m_new_obj(mp_obj_Sha3_512_t);
out->base.type = o->base.type;
out->keccak = o->keccak;
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) {
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX));
return mp_const_none;
mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA3_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_digest_obj) },
{ MP_ROM_QSTR(MP_QSTR_copy), 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Sha3_512_digest_obj)},
{MP_ROM_QSTR(MP_QSTR_copy),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Sha3_512,
.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 "sha2.h"
#include "memzero.h"
#include "sha2.h"
/// package: trezorcrypto.__init__
@ -29,8 +29,8 @@
/// SHA512 context.
/// '''
typedef struct _mp_obj_Sha512_t {
mp_obj_base_t base;
SHA512_CTX ctx;
mp_obj_base_t base;
SHA512_CTX ctx;
} mp_obj_Sha512_t;
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.
/// '''
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha512_t *o = m_new_obj(mp_obj_Sha512_t);
o->base.type = type;
sha512_Init(&(o->ctx));
if (n_args == 1) {
mod_trezorcrypto_Sha512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_Sha512_t *o = m_new_obj(mp_obj_Sha512_t);
o->base.type = type;
sha512_Init(&(o->ctx));
if (n_args == 1) {
mod_trezorcrypto_Sha512_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha512_Update(&(o->ctx), msg.buf, msg.len);
}
return mp_const_none;
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t msg;
mp_get_buffer_raise(data, &msg, MP_BUFFER_READ);
if (msg.len > 0) {
sha512_Update(&(o->ctx), msg.buf, msg.len);
}
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:
/// '''
/// Returns the digest of hashed data.
/// '''
STATIC mp_obj_t mod_trezorcrypto_Sha512_digest(mp_obj_t self) {
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA512_DIGEST_LENGTH];
SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA512_CTX));
sha512_Final(&ctx, out);
memzero(&ctx, sizeof(SHA512_CTX));
return mp_obj_new_bytes(out, sizeof(out));
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
uint8_t out[SHA512_DIGEST_LENGTH];
SHA512_CTX ctx;
memcpy(&ctx, &(o->ctx), sizeof(SHA512_CTX));
sha512_Final(&ctx, out);
memzero(&ctx, sizeof(SHA512_CTX));
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) {
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA512_CTX));
return mp_const_none;
mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self);
memzero(&(o->ctx), sizeof(SHA512_CTX));
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[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_trezorcrypto_Sha512_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_trezorcrypto_Sha512_digest_obj) },
{ 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) },
{MP_ROM_QSTR(MP_QSTR_update),
MP_ROM_PTR(&mod_trezorcrypto_Sha512_update_obj)},
{MP_ROM_QSTR(MP_QSTR_digest),
MP_ROM_PTR(&mod_trezorcrypto_Sha512_digest_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Sha512,
.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/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "py/runtime.h"
@ -35,9 +35,10 @@
#include "modtrezorcrypto-crc.h"
#include "modtrezorcrypto-curve25519.h"
#include "modtrezorcrypto-ed25519.h"
#include "modtrezorcrypto-nist256p1.h"
#include "modtrezorcrypto-groestl.h"
#include "modtrezorcrypto-monero.h"
#include "modtrezorcrypto-nem.h"
#include "modtrezorcrypto-nist256p1.h"
#include "modtrezorcrypto-pbkdf2.h"
#include "modtrezorcrypto-random.h"
#include "modtrezorcrypto-rfc6979.h"
@ -45,43 +46,53 @@
#include "modtrezorcrypto-secp256k1.h"
#include "modtrezorcrypto-sha1.h"
#include "modtrezorcrypto-sha256.h"
#include "modtrezorcrypto-sha512.h"
#include "modtrezorcrypto-sha3-256.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[] = {
{ 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_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_blake256), MP_ROM_PTR(&mod_trezorcrypto_Blake256_type) },
{ MP_ROM_QSTR(MP_QSTR_blake2b), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_type) },
{ MP_ROM_QSTR(MP_QSTR_blake2s), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_type) },
{ MP_ROM_QSTR(MP_QSTR_chacha20poly1305), MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_type) },
{ MP_ROM_QSTR(MP_QSTR_crc), MP_ROM_PTR(&mod_trezorcrypto_crc_module) },
{ MP_ROM_QSTR(MP_QSTR_curve25519), MP_ROM_PTR(&mod_trezorcrypto_curve25519_module) },
{ MP_ROM_QSTR(MP_QSTR_ed25519), MP_ROM_PTR(&mod_trezorcrypto_ed25519_module) },
{ MP_ROM_QSTR(MP_QSTR_monero), MP_ROM_PTR(&mod_trezorcrypto_monero_module) },
{ MP_ROM_QSTR(MP_QSTR_nist256p1), MP_ROM_PTR(&mod_trezorcrypto_nist256p1_module) },
{ MP_ROM_QSTR(MP_QSTR_groestl512), MP_ROM_PTR(&mod_trezorcrypto_Groestl512_type) },
{ MP_ROM_QSTR(MP_QSTR_nem), MP_ROM_PTR(&mod_trezorcrypto_nem_module) },
{ MP_ROM_QSTR(MP_QSTR_pbkdf2), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_type) },
{ MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_trezorcrypto_random_module) },
{ MP_ROM_QSTR(MP_QSTR_rfc6979), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_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) },
{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_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_blake256),
MP_ROM_PTR(&mod_trezorcrypto_Blake256_type)},
{MP_ROM_QSTR(MP_QSTR_blake2b), MP_ROM_PTR(&mod_trezorcrypto_Blake2b_type)},
{MP_ROM_QSTR(MP_QSTR_blake2s), MP_ROM_PTR(&mod_trezorcrypto_Blake2s_type)},
{MP_ROM_QSTR(MP_QSTR_chacha20poly1305),
MP_ROM_PTR(&mod_trezorcrypto_ChaCha20Poly1305_type)},
{MP_ROM_QSTR(MP_QSTR_crc), MP_ROM_PTR(&mod_trezorcrypto_crc_module)},
{MP_ROM_QSTR(MP_QSTR_curve25519),
MP_ROM_PTR(&mod_trezorcrypto_curve25519_module)},
{MP_ROM_QSTR(MP_QSTR_ed25519),
MP_ROM_PTR(&mod_trezorcrypto_ed25519_module)},
{MP_ROM_QSTR(MP_QSTR_monero), MP_ROM_PTR(&mod_trezorcrypto_monero_module)},
{MP_ROM_QSTR(MP_QSTR_nist256p1),
MP_ROM_PTR(&mod_trezorcrypto_nist256p1_module)},
{MP_ROM_QSTR(MP_QSTR_groestl512),
MP_ROM_PTR(&mod_trezorcrypto_Groestl512_type)},
{MP_ROM_QSTR(MP_QSTR_nem), MP_ROM_PTR(&mod_trezorcrypto_nem_module)},
{MP_ROM_QSTR(MP_QSTR_pbkdf2), MP_ROM_PTR(&mod_trezorcrypto_Pbkdf2_type)},
{MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_trezorcrypto_random_module)},
{MP_ROM_QSTR(MP_QSTR_rfc6979), MP_ROM_PTR(&mod_trezorcrypto_Rfc6979_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 = {
.base = { &mp_type_module },
.base = {&mp_type_module},
.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 "rng.h"
uint32_t random32(void)
{
return rng_get();
}
uint32_t random32(void) { return rng_get(); }

@ -25,85 +25,95 @@
/// '''
/// '''
typedef struct _mp_obj_FlashOTP_t {
mp_obj_base_t base;
mp_obj_base_t base;
} mp_obj_FlashOTP_t;
/// 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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_FlashOTP_t *o = m_new_obj(mp_obj_FlashOTP_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
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:
/// '''
/// Writes data to OTP flash
/// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_write(size_t n_args, const mp_obj_t *args) {
uint8_t block = trezor_obj_get_uint8(args[1]);
uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_buffer_info_t data;
mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ);
if (sectrue != flash_otp_write(block, offset, data.buf, data.len)) {
mp_raise_ValueError("write failed");
}
return mp_const_none;
STATIC mp_obj_t mod_trezorio_FlashOTP_write(size_t n_args,
const mp_obj_t *args) {
uint8_t block = trezor_obj_get_uint8(args[1]);
uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_buffer_info_t data;
mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ);
if (sectrue != flash_otp_write(block, offset, data.buf, data.len)) {
mp_raise_ValueError("write failed");
}
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:
/// '''
/// Reads data from OTP flash
/// '''
STATIC mp_obj_t mod_trezorio_FlashOTP_read(size_t n_args, const mp_obj_t *args) {
uint8_t block = trezor_obj_get_uint8(args[1]);
uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_buffer_info_t data;
mp_get_buffer_raise(args[3], &data, MP_BUFFER_WRITE);
if (sectrue != flash_otp_read(block, offset, data.buf, data.len)) {
mp_raise_ValueError("read failed");
}
return mp_const_none;
STATIC mp_obj_t mod_trezorio_FlashOTP_read(size_t n_args,
const mp_obj_t *args) {
uint8_t block = trezor_obj_get_uint8(args[1]);
uint8_t offset = trezor_obj_get_uint8(args[2]);
mp_buffer_info_t data;
mp_get_buffer_raise(args[3], &data, MP_BUFFER_WRITE);
if (sectrue != flash_otp_read(block, offset, data.buf, data.len)) {
mp_raise_ValueError("read failed");
}
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:
/// '''
/// Lock OTP flash 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);
if (sectrue != flash_otp_lock(b)) {
mp_raise_ValueError("lock failed");
}
return mp_const_none;
uint8_t b = trezor_obj_get_uint8(block);
if (sectrue != flash_otp_lock(b)) {
mp_raise_ValueError("lock failed");
}
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:
/// '''
/// Is OTP flash block locked?
/// '''
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);
return (sectrue == flash_otp_is_locked(b)) ? mp_const_true : mp_const_false;
uint8_t b = trezor_obj_get_uint8(block);
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[] = {
{ 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_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_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_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)},
};
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_FlashOTP,
.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.
/// '''
typedef struct _mp_obj_HID_t {
mp_obj_base_t base;
usb_hid_info_t info;
mp_obj_base_t base;
usb_hid_info_t info;
} mp_obj_HID_t;
/// def __init__(self,
@ -37,57 +37,68 @@ typedef struct _mp_obj_HID_t {
/// 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[] = {
{ 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);
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t ep_in = vals[1].u_int;
const mp_int_t ep_out = vals[2].u_int;
const mp_int_t subclass = vals[3].u_int;
const mp_int_t protocol = vals[4].u_int;
const mp_int_t polling_interval = vals[5].u_int;
const mp_int_t max_packet_len = vals[6].u_int;
mp_buffer_info_t report_desc;
mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ);
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t ep_in = vals[1].u_int;
const mp_int_t ep_out = vals[2].u_int;
const mp_int_t subclass = vals[3].u_int;
const mp_int_t protocol = vals[4].u_int;
const mp_int_t polling_interval = vals[5].u_int;
const mp_int_t max_packet_len = vals[6].u_int;
mp_buffer_info_t report_desc;
mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ);
if (report_desc.buf == NULL || report_desc.len == 0 ||
report_desc.len > 255) {
mp_raise_ValueError("report_desc is invalid");
}
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)
if (report_desc.buf == NULL || report_desc.len == 0 || report_desc.len > 255) {
mp_raise_ValueError("report_desc is invalid");
}
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->base.type = type;
mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t);
o->base.type = type;
o->info.rx_buffer = m_new(uint8_t, max_packet_len);
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);
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);
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
STATIC mp_obj_t mod_trezorio_HID_iface_num(mp_obj_t self) {
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// 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) {
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_hid_write(o->info.iface_num, buf.buf, buf.len);
return MP_OBJ_NEW_SMALL_INT(r);
mp_obj_HID_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_hid_write(o->info.iface_num, buf.buf, buf.len);
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[] = {
{ MP_ROM_QSTR(MP_QSTR_iface_num), MP_ROM_PTR(&mod_trezorio_HID_iface_num_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_HID_write_obj) },
{MP_ROM_QSTR(MP_QSTR_iface_num),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_HID,
.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 <unistd.h>
#include "embed/extmod/trezorobj.h"
#include "usb.h"
#define TOUCH_IFACE (255)
#define POLL_READ (0x0000)
#define POLL_READ (0x0000)
#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:
/// '''
/// Wait until one of `ifaces` is ready to read or write (using masks
@ -40,80 +32,82 @@
/// `list_ref`:
///
/// `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
///
/// 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) {
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 2) {
mp_raise_TypeError("invalid list_ref");
}
STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref,
mp_obj_t timeout_us) {
mp_obj_list_t *ret = MP_OBJ_TO_PTR(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 deadline = mp_hal_ticks_us() + timeout;
mp_obj_iter_buf_t iterbuf;
const mp_uint_t timeout = trezor_obj_get_uint(timeout_us);
const mp_uint_t deadline = mp_hal_ticks_us() + timeout;
mp_obj_iter_buf_t iterbuf;
for (;;) {
mp_obj_t iter = mp_getiter(ifaces, &iterbuf);
mp_obj_t item;
while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
const mp_uint_t i = trezor_obj_get_uint(item);
const mp_uint_t iface = i & 0x00FF;
const mp_uint_t mode = i & 0xFF00;
for (;;) {
mp_obj_t iter = mp_getiter(ifaces, &iterbuf);
mp_obj_t item;
while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
const mp_uint_t i = trezor_obj_get_uint(item);
const mp_uint_t iface = i & 0x00FF;
const mp_uint_t mode = i & 0xFF00;
if (iface == TOUCH_IFACE) {
const uint32_t evt = touch_read();
if (evt) {
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[1] = MP_OBJ_NEW_SMALL_INT((evt >> 12) & 0xFFFU); // x position
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(evt & 0xFFFU); // y position
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = MP_OBJ_FROM_PTR(tuple);
return mp_const_true;
}
} else
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;
}
}
if (iface == TOUCH_IFACE) {
const uint32_t evt = touch_read();
if (evt) {
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[1] =
MP_OBJ_NEW_SMALL_INT((evt >> 12) & 0xFFFU); // x position
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(evt & 0xFFFU); // y position
ret->items[0] = MP_OBJ_NEW_SMALL_INT(i);
ret->items[1] = MP_OBJ_FROM_PTR(tuple);
return mp_const_true;
}
if (mp_hal_ticks_us() >= deadline) {
break;
} else {
MICROPY_EVENT_POLL_HOOK
} else 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;
}
}
}
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);

@ -23,38 +23,43 @@
/// '''
/// '''
typedef struct _mp_obj_SBU_t {
mp_obj_base_t base;
mp_obj_base_t base;
} mp_obj_SBU_t;
/// 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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_SBU_t *o = m_new_obj(mp_obj_SBU_t);
o->base.type = type;
sbu_init();
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_SBU_t *o = m_new_obj(mp_obj_SBU_t);
o->base.type = type;
sbu_init();
return MP_OBJ_FROM_PTR(o);
}
/// def set(self, sbu1: bool, sbu2: bool) -> None:
/// '''
/// 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) {
sbu_set(sectrue * mp_obj_is_true(sbu1), sectrue * mp_obj_is_true(sbu2));
return mp_const_none;
STATIC mp_obj_t mod_trezorio_SBU_set(mp_obj_t self, mp_obj_t sbu1,
mp_obj_t sbu2) {
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[] = {
{ 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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_SBU,
.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 {
mp_obj_base_t base;
mp_obj_base_t base;
} mp_obj_SDCard_t;
/// 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) {
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;
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) {
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
sdcard_init();
sdcard_init();
#endif
return MP_OBJ_FROM_PTR(o);
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
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:
/// '''
@ -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.
/// '''
STATIC mp_obj_t mod_trezorio_SDCard_power(mp_obj_t self, mp_obj_t state) {
if (mp_obj_is_true(state)) {
return mp_obj_new_bool(sdcard_power_on());
} else {
sdcard_power_off();
return mp_const_true;
}
if (mp_obj_is_true(state)) {
return mp_obj_new_bool(sdcard_power_on());
} else {
sdcard_power_off();
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:
/// '''
/// 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) {
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:
/// '''
/// 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.
/// Returns True if in case of success, False otherwise.
/// Number of bytes read is length of buf rounded down to multiply of
/// 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) {
uint32_t block = trezor_obj_get_uint(block_num);
mp_buffer_info_t bufinfo;
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_obj_t mod_trezorio_SDCard_read(mp_obj_t self, mp_obj_t block_num,
mp_obj_t buf) {
uint32_t block = trezor_obj_get_uint(block_num);
mp_buffer_info_t bufinfo;
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:
/// '''
/// 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.
/// Returns True if in case of success, False otherwise.
/// Number of bytes written is length of buf rounded down to multiply of
/// 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) {
uint32_t block = trezor_obj_get_uint(block_num);
mp_buffer_info_t bufinfo;
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_obj_t mod_trezorio_SDCard_write(mp_obj_t self, mp_obj_t block_num,
mp_obj_t buf) {
uint32_t block = trezor_obj_get_uint(block_num);
mp_buffer_info_t bufinfo;
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[] = {
{ MP_ROM_QSTR(MP_QSTR_present), MP_ROM_PTR(&mod_trezorio_SDCard_present_obj) },
{ MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&mod_trezorio_SDCard_power_obj) },
{ MP_ROM_QSTR(MP_QSTR_capacity), MP_ROM_PTR(&mod_trezorio_SDCard_capacity_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) },
{MP_ROM_QSTR(MP_QSTR_present),
MP_ROM_PTR(&mod_trezorio_SDCard_present_obj)},
{MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&mod_trezorio_SDCard_power_obj)},
{MP_ROM_QSTR(MP_QSTR_capacity),
MP_ROM_PTR(&mod_trezorio_SDCard_capacity_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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_SDCard,
.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);
enum {
USB_CLOSED = 0,
USB_OPENED = 1,
USB_CLOSED = 0,
USB_OPENED = 1,
};
/// class USB:
@ -29,24 +29,24 @@ enum {
/// USB device configuration.
/// '''
typedef struct _mp_obj_USB_t {
mp_obj_base_t base;
mp_obj_list_t ifaces;
usb_dev_info_t info;
mp_int_t state;
mp_obj_base_t base;
mp_obj_list_t ifaces;
usb_dev_info_t info;
mp_int_t state;
} mp_obj_USB_t;
static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) {
size_t len;
const char *s = mp_obj_str_get_data(o, &len);
if ((len >= min_len) && (len <= max_len)) {
if (len == 0 && s == NULL) {
return "";
} else {
return s;
}
size_t len;
const char *s = mp_obj_str_get_data(o, &len);
if ((len >= min_len) && (len <= max_len)) {
if (len == 0 && s == NULL) {
return "";
} else {
return NULL;
return s;
}
} else {
return NULL;
}
}
/// 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:
/// '''
/// '''
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 const mp_arg_t allowed_args[] = {
{ MP_QSTR_device_class, 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_device_protocol, 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_product_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_release_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_manufacturer, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_product, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_serial_number, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_interface, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
{ MP_QSTR_usb21_enabled, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_usb21_landing, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
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 device_class = vals[0].u_int;
const mp_int_t device_subclass = vals[1].u_int;
const mp_int_t device_protocol = vals[2].u_int;
const mp_int_t vendor_id = vals[3].u_int;
const mp_int_t product_id = vals[4].u_int;
const mp_int_t release_num = vals[5].u_int;
const char *manufacturer = get_0str(vals[6].u_obj, 0, 32);
const char *product = get_0str(vals[7].u_obj, 0, 32);
const char *serial_number = get_0str(vals[8].u_obj, 0, 32);
const char *interface = get_0str(vals[9].u_obj, 0, 32);
const secbool usb21_enabled = vals[10].u_bool ? sectrue : secfalse;
const secbool usb21_landing = vals[11].u_bool ? sectrue : secfalse;
CHECK_PARAM_RANGE(device_class, 0, 255)
CHECK_PARAM_RANGE(device_subclass, 0, 255)
CHECK_PARAM_RANGE(device_protocol, 0, 255)
CHECK_PARAM_RANGE(vendor_id, 0, 65535)
CHECK_PARAM_RANGE(product_id, 0, 65535)
CHECK_PARAM_RANGE(release_num, 0, 65535)
if (manufacturer == NULL) {
mp_raise_ValueError("manufacturer is invalid");
}
if (product == NULL) {
mp_raise_ValueError("product is invalid");
}
if (serial_number == NULL) {
mp_raise_ValueError("serial_number is invalid");
}
if (interface == NULL) {
mp_raise_ValueError("interface is invalid");
}
mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t);
o->base.type = type;
o->state = USB_CLOSED;
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);
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 const mp_arg_t allowed_args[] = {
{MP_QSTR_device_class, 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_device_protocol, 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_product_id,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_release_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT,
{.u_int = 0}},
{MP_QSTR_manufacturer,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_product,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_serial_number,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_interface,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_usb21_enabled, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true}},
{MP_QSTR_usb21_landing, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true}},
};
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 device_class = vals[0].u_int;
const mp_int_t device_subclass = vals[1].u_int;
const mp_int_t device_protocol = vals[2].u_int;
const mp_int_t vendor_id = vals[3].u_int;
const mp_int_t product_id = vals[4].u_int;
const mp_int_t release_num = vals[5].u_int;
const char *manufacturer = get_0str(vals[6].u_obj, 0, 32);
const char *product = get_0str(vals[7].u_obj, 0, 32);
const char *serial_number = get_0str(vals[8].u_obj, 0, 32);
const char *interface = get_0str(vals[9].u_obj, 0, 32);
const secbool usb21_enabled = vals[10].u_bool ? sectrue : secfalse;
const secbool usb21_landing = vals[11].u_bool ? sectrue : secfalse;
CHECK_PARAM_RANGE(device_class, 0, 255)
CHECK_PARAM_RANGE(device_subclass, 0, 255)
CHECK_PARAM_RANGE(device_protocol, 0, 255)
CHECK_PARAM_RANGE(vendor_id, 0, 65535)
CHECK_PARAM_RANGE(product_id, 0, 65535)
CHECK_PARAM_RANGE(release_num, 0, 65535)
if (manufacturer == NULL) {
mp_raise_ValueError("manufacturer is invalid");
}
if (product == NULL) {
mp_raise_ValueError("product is invalid");
}
if (serial_number == NULL) {
mp_raise_ValueError("serial_number is invalid");
}
if (interface == NULL) {
mp_raise_ValueError("interface is invalid");
}
mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t);
o->base.type = type;
o->state = USB_CLOSED;
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:
@ -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.
/// '''
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) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized");
}
mp_obj_list_append(MP_OBJ_FROM_PTR(&o->ifaces), iface);
if (o->state != USB_CLOSED) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized");
}
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:
/// '''
/// Initializes the USB stack.
/// '''
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) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized");
}
if (o->state != USB_CLOSED) {
mp_raise_msg(&mp_type_RuntimeError, "already initialized");
}
size_t iface_cnt;
mp_obj_t *iface_objs;
mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs);
size_t iface_cnt;
mp_obj_t *iface_objs;
mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs);
// Initialize the USB stack
usb_init(&o->info);
// Initialize the USB stack
usb_init(&o->info);
int vcp_iface_num = -1;
int vcp_iface_num = -1;
// Add all interfaces
for (size_t i = 0; i < iface_cnt; i++) {
mp_obj_t iface = iface_objs[i];
// Add all interfaces
for (size_t i = 0; i < iface_cnt; i++) {
mp_obj_t iface = iface_objs[i];
if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_HID_type)) {
mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_hid_add(&hid->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add HID interface");
}
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_WebUSB_type)) {
mp_obj_WebUSB_t *webusb = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_webusb_add(&webusb->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add WebUSB interface");
}
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_VCP_type)) {
mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_vcp_add(&vcp->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface");
}
vcp_iface_num = vcp->info.iface_num;
} else {
usb_deinit();
mp_raise_TypeError("expected HID, WebUSB or VCP type");
}
if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_HID_type)) {
mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_hid_add(&hid->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add HID interface");
}
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_WebUSB_type)) {
mp_obj_WebUSB_t *webusb = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_webusb_add(&webusb->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add WebUSB interface");
}
} else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_VCP_type)) {
mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface);
if (sectrue != usb_vcp_add(&vcp->info)) {
usb_deinit();
mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface");
}
vcp_iface_num = vcp->info.iface_num;
} else {
usb_deinit();
mp_raise_TypeError("expected HID, WebUSB or VCP type");
}
}
// Start the USB stack
usb_start();
o->state = USB_OPENED;
// Start the USB stack
usb_start();
o->state = USB_OPENED;
// If we found any VCP interfaces, use the last one for stdio,
// otherwise disable the stdio support
mp_hal_set_vcp_iface(vcp_iface_num);
// If we found any VCP interfaces, use the last one for stdio,
// otherwise disable the stdio support
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:
/// '''
/// Cleans up the USB stack.
/// '''
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) {
mp_raise_msg(&mp_type_RuntimeError, "not initialized");
}
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();
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);
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;
}
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[] = {
{ 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_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_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_close), MP_ROM_PTR(&mod_trezorio_USB_close_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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_USB,
.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.
/// '''
typedef struct _mp_obj_VCP_t {
mp_obj_base_t base;
usb_vcp_info_t info;
mp_obj_base_t base;
usb_vcp_info_t info;
} mp_obj_VCP_t;
/// def __init__(self,
@ -36,53 +36,65 @@ typedef struct _mp_obj_VCP_t {
/// 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[] = {
{ 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);
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t data_iface_num = vals[1].u_int;
const mp_int_t ep_in = vals[2].u_int;
const mp_int_t ep_out = vals[3].u_int;
const mp_int_t ep_cmd = vals[4].u_int;
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t data_iface_num = vals[1].u_int;
const mp_int_t ep_in = vals[2].u_int;
const mp_int_t ep_out = vals[3].u_int;
const mp_int_t ep_cmd = vals[4].u_int;
CHECK_PARAM_RANGE(iface_num, 0, 32)
CHECK_PARAM_RANGE(data_iface_num, 0, 32)
CHECK_PARAM_RANGE(ep_in, 0, 255)
CHECK_PARAM_RANGE(ep_out, 0, 255)
CHECK_PARAM_RANGE(ep_cmd, 0, 255)
CHECK_PARAM_RANGE(iface_num, 0, 32)
CHECK_PARAM_RANGE(data_iface_num, 0, 32)
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;
const size_t vcp_packet_len = 64;
const size_t vcp_buffer_len = 1024;
const size_t vcp_packet_len = 64;
mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t);
o->base.type = type;
mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t);
o->base.type = type;
o->info.tx_packet = m_new(uint8_t, vcp_packet_len);
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);
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);
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
STATIC mp_obj_t mod_trezorio_VCP_iface_num(mp_obj_t self) {
mp_obj_VCP_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
mp_obj_VCP_t *o = MP_OBJ_TO_PTR(self);
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[] = {
{ 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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_VCP,
.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.
/// '''
typedef struct _mp_obj_WebUSB_t {
mp_obj_base_t base;
usb_webusb_info_t info;
mp_obj_base_t base;
usb_webusb_info_t info;
} mp_obj_WebUSB_t;
/// def __init__(self,
@ -36,49 +36,57 @@ typedef struct _mp_obj_WebUSB_t {
/// 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[] = {
{ 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);
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t ep_in = vals[1].u_int;
const mp_int_t ep_out = vals[2].u_int;
const mp_int_t subclass = vals[3].u_int;
const mp_int_t protocol = vals[4].u_int;
const mp_int_t polling_interval = vals[5].u_int;
const mp_int_t max_packet_len = vals[6].u_int;
const mp_int_t iface_num = vals[0].u_int;
const mp_int_t ep_in = vals[1].u_int;
const mp_int_t ep_out = vals[2].u_int;
const mp_int_t subclass = vals[3].u_int;
const mp_int_t protocol = vals[4].u_int;
const mp_int_t polling_interval = vals[5].u_int;
const mp_int_t max_packet_len = vals[6].u_int;
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)
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_WebUSB_t *o = m_new_obj(mp_obj_WebUSB_t);
o->base.type = type;
mp_obj_WebUSB_t *o = m_new_obj(mp_obj_WebUSB_t);
o->base.type = type;
o->info.rx_buffer = m_new(uint8_t, max_packet_len);
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);
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);
return MP_OBJ_FROM_PTR(o);
}
/// 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.
/// '''
STATIC mp_obj_t mod_trezorio_WebUSB_iface_num(mp_obj_t self) {
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
return MP_OBJ_NEW_SMALL_INT(o->info.iface_num);
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
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:
/// '''
/// 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) {
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_webusb_write(o->info.iface_num, buf.buf, buf.len);
return MP_OBJ_NEW_SMALL_INT(r);
mp_obj_WebUSB_t *o = MP_OBJ_TO_PTR(self);
mp_buffer_info_t buf;
mp_get_buffer_raise(msg, &buf, MP_BUFFER_READ);
ssize_t r = usb_webusb_write(o->info.iface_num, buf.buf, buf.len);
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[] = {
{ MP_ROM_QSTR(MP_QSTR_iface_num), MP_ROM_PTR(&mod_trezorio_WebUSB_iface_num_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_WebUSB_write_obj) },
{MP_ROM_QSTR(MP_QSTR_iface_num),
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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_WebUSB,
.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/>.
*/
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/objstr.h"
#include "py/runtime.h"
#if MICROPY_PY_TREZORIO
#include <unistd.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-hid.h"
#include "modtrezorio-poll.h"
#include "modtrezorio-sbu.h"
#include "modtrezorio-sdcard.h"
#include "modtrezorio-poll.h"
#include "modtrezorio-hid.h"
#include "modtrezorio-vcp.h"
#include "modtrezorio-webusb.h"
#include "modtrezorio-usb.h"
// clang-format on
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_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_WebUSB), MP_ROM_PTR(&mod_trezorio_WebUSB_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_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_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_WRITE), MP_OBJ_NEW_SMALL_INT(POLL_WRITE) },
{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_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_START), MP_OBJ_NEW_SMALL_INT((TOUCH_START >> 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) },
{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_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 = {
.base = { &mp_type_module },
.base = {&mp_type_module},
.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
#define OLED_BUFSIZE (DISPLAY_RESX * DISPLAY_RESY / 8)
#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y)/8) * DISPLAY_RESX)
#define OLED_MASK(x, y) (1 << (7 - (y) % 8))
#define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D
#define OLED_DC_PORT GPIOB
#define OLED_DC_PIN GPIO_PIN_0 // PB0 | Data/Command
#define OLED_CS_PORT GPIOA
#define OLED_CS_PIN GPIO_PIN_4 // PA4 | SPI Select
#define OLED_RST_PORT GPIOB
#define OLED_RST_PIN GPIO_PIN_1 // PB1 | Reset display
#define OLED_BUFSIZE (DISPLAY_RESX * DISPLAY_RESY / 8)
#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y) / 8) * DISPLAY_RESX)
#define OLED_MASK(x, y) (1 << (7 - (y) % 8))
#define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D
#define OLED_DC_PORT GPIOB
#define OLED_DC_PIN GPIO_PIN_0 // PB0 | Data/Command
#define OLED_CS_PORT GPIOA
#define OLED_CS_PIN GPIO_PIN_4 // PA4 | SPI Select
#define OLED_RST_PORT GPIOB
#define OLED_RST_PIN GPIO_PIN_1 // PB1 | Reset display
static uint8_t OLED_BUFFER[OLED_BUFSIZE];
static struct {
struct {
uint16_t x, y;
} start;
struct {
uint16_t x, y;
} end;
struct {
uint16_t x, y;
} pos;
struct {
uint16_t x, y;
} start;
struct {
uint16_t x, y;
} end;
struct {
uint16_t x, y;
} pos;
} PIXELWINDOW;
void PIXELDATA(uint16_t c) {
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
// set to white if highest bits of all R, G, B values are set to 1
// bin(10000 100000 10000) = hex(0x8410)
// otherwise set to black
if (c & 0x8410) {
OLED_BUFFER[OLED_OFFSET(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)] &= ~OLED_MASK(PIXELWINDOW.pos.x, PIXELWINDOW.pos.y);
}
}
PIXELWINDOW.pos.x++;
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x &&
PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
// set to white if highest bits of all R, G, B values are set to 1
// bin(10000 100000 10000) = hex(0x8410)
// otherwise set to black
if (c & 0x8410) {
OLED_BUFFER[OLED_OFFSET(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)] &=
~OLED_MASK(PIXELWINDOW.pos.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)
{
PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0;
PIXELWINDOW.end.x = x1; PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0; PIXELWINDOW.pos.y = y0;
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.end.x = x1;
PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0;
PIXELWINDOW.pos.y = y0;
}
static void display_set_orientation(int degrees)
{
display_refresh();
}
static void display_set_orientation(int degrees) { display_refresh(); }
static void display_set_backlight(int val)
{
}
static void display_set_backlight(int val) {}
SPI_HandleTypeDef spi_handle;
static inline void spi_send(const uint8_t *data, int len)
{
HAL_Delay(1);
if (HAL_OK != HAL_SPI_Transmit(&spi_handle, (uint8_t *)data, len, 1000)) {
// TODO: error
return;
}
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&spi_handle)) {
}
static inline void spi_send(const uint8_t *data, int len) {
HAL_Delay(1);
if (HAL_OK != HAL_SPI_Transmit(&spi_handle, (uint8_t *)data, len, 1000)) {
// TODO: error
return;
}
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&spi_handle)) {
}
}
void display_init(void)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
// set GPIO for OLED display
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_4;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// enable SPI 1 for OLED display
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
spi_handle.Instance = SPI1;
spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spi_handle.Init.CRCPolynomial = 7;
spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spi_handle.Init.NSS = SPI_NSS_HARD_OUTPUT;
spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
spi_handle.Init.Mode = SPI_MODE_MASTER;
if (HAL_OK != HAL_SPI_Init(&spi_handle)) {
// TODO: error
return;
}
// initialize display
static const uint8_t s[25] = {
OLED_DISPLAYOFF,
OLED_SETDISPLAYCLOCKDIV,
0x80,
OLED_SETMULTIPLEX,
0x3F, // 128x64
OLED_SETDISPLAYOFFSET,
0x00,
OLED_SETSTARTLINE | 0x00,
OLED_CHARGEPUMP,
0x14,
OLED_MEMORYMODE,
0x00,
OLED_SEGREMAP | 0x01,
OLED_COMSCANDEC,
OLED_SETCOMPINS,
0x12, // 128x64
OLED_SETCONTRAST,
0xCF,
OLED_SETPRECHARGE,
0xF1,
OLED_SETVCOMDETECT,
0x40,
OLED_DISPLAYALLON_RESUME,
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
// Reset the LCD
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
HAL_Delay(40);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(400);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
// init
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
spi_send(s, 25);
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
display_clear();
display_refresh();
void display_init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
// set GPIO for OLED display
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_4;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// enable SPI 1 for OLED display
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI1;
GPIO_InitStructure.Pin = GPIO_PIN_5 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
spi_handle.Instance = SPI1;
spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
spi_handle.Init.Direction = SPI_DIRECTION_2LINES;
spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;
spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;
spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spi_handle.Init.CRCPolynomial = 7;
spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;
spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spi_handle.Init.NSS = SPI_NSS_HARD_OUTPUT;
spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
spi_handle.Init.Mode = SPI_MODE_MASTER;
if (HAL_OK != HAL_SPI_Init(&spi_handle)) {
// TODO: error
return;
}
// initialize display
static const uint8_t s[25] = {OLED_DISPLAYOFF,
OLED_SETDISPLAYCLOCKDIV,
0x80,
OLED_SETMULTIPLEX,
0x3F, // 128x64
OLED_SETDISPLAYOFFSET,
0x00,
OLED_SETSTARTLINE | 0x00,
OLED_CHARGEPUMP,
0x14,
OLED_MEMORYMODE,
0x00,
OLED_SEGREMAP | 0x01,
OLED_COMSCANDEC,
OLED_SETCOMPINS,
0x12, // 128x64
OLED_SETCONTRAST,
0xCF,
OLED_SETPRECHARGE,
0xF1,
OLED_SETVCOMDETECT,
0x40,
OLED_DISPLAYALLON_RESUME,
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
// Reset the LCD
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
HAL_Delay(40);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(400);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
// init
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); // SPI select
spi_send(s, 25);
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); // SPI deselect
display_clear();
display_refresh();
}
static inline uint8_t reverse_byte(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
static void rotate_oled_buffer(void)
{
for (int i = 0; i < OLED_BUFSIZE / 2; i++) {
uint8_t b = OLED_BUFFER[i];
OLED_BUFFER[i] = reverse_byte(OLED_BUFFER[OLED_BUFSIZE - i]);
OLED_BUFFER[OLED_BUFSIZE - i] = reverse_byte(b);
}
static void rotate_oled_buffer(void) {
for (int i = 0; i < OLED_BUFSIZE / 2; i++) {
uint8_t b = OLED_BUFFER[i];
OLED_BUFFER[i] = reverse_byte(OLED_BUFFER[OLED_BUFSIZE - i]);
OLED_BUFFER[OLED_BUFSIZE - i] = reverse_byte(b);
}
}
void display_refresh(void)
{
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 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_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
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
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
void display_refresh(void) {
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 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_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
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
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
}
void display_save(const char *prefix)
{
}
void display_save(const char *prefix) {}

@ -20,332 +20,482 @@
#include STM32_HAL_H
// FSMC/FMC Bank 1 - NOR/PSRAM 1
#define DISPLAY_MEMORY_BASE 0x60000000
#define DISPLAY_MEMORY_PIN 16
#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 DATA(X) (ADDR) = (X)
#define PIXELDATA(X) DATA((X) >> 8); DATA((X) & 0xFF)
#define DISPLAY_MEMORY_BASE 0x60000000
#define DISPLAY_MEMORY_PIN 16
#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 DATA(X) (ADDR) = (X)
#define PIXELDATA(X) \
DATA((X) >> 8); \
DATA((X)&0xFF)
#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_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
#define DISPLAY_ID_ST7789V \
0x858552U // section "9.1.3 RDDID (04h): Read Display ID" of ST7789V
// 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) {
volatile uint8_t c;
uint32_t id = 0;
CMD(command);
c = ADDR; // first returned value is a dummy value and should be discarded
c = ADDR; id |= (c << 16);
c = ADDR; id |= (c << 8);
c = ADDR; id |= c;
return id;
volatile uint8_t c;
uint32_t id = 0;
CMD(command);
c = ADDR; // first returned value is a dummy value and should be discarded
c = ADDR;
id |= (c << 16);
c = ADDR;
id |= (c << 8);
c = ADDR;
id |= c;
return id;
}
static uint32_t display_identify(void)
{
static uint32_t id = 0x000000U;
static char id_set = 0;
if (id_set) return id; // return if id has been already set
id = read_display_id(0x04); // RDDID: Read Display ID
// the default RDDID for ILI9341 should be 0x8000.
// some display modules return 0x0.
// the ILI9341 has an extra id, let's check it here.
if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) { // if not ST7789V and not GC9307
uint32_t id4 = read_display_id(0xD3); // Read ID4
if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
id = id4;
}
static uint32_t display_identify(void) {
static uint32_t id = 0x000000U;
static char id_set = 0;
if (id_set) return id; // return if id has been already set
id = read_display_id(0x04); // RDDID: Read Display ID
// the default RDDID for ILI9341 should be 0x8000.
// some display modules return 0x0.
// the ILI9341 has an extra id, let's check it here.
if ((id != DISPLAY_ID_ST7789V) &&
(id != DISPLAY_ID_GC9307)) { // if not ST7789V and not GC9307
uint32_t id4 = read_display_id(0xD3); // Read ID4
if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
id = id4;
}
id_set = 1;
return id;
}
id_set = 1;
return id;
}
static void __attribute__((unused)) display_sleep(void)
{
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) {
CMD(0x28); // DISPOFF: Display Off
CMD(0x10); // SLPIN: Sleep in
HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before sending any new commands
}
static void __attribute__((unused)) display_sleep(void) {
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
CMD(0x28); // DISPOFF: Display Off
CMD(0x10); // SLPIN: Sleep in
HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before
// sending any new commands
}
}
static void display_unsleep(void)
{
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) {
CMD(0x11); // SLPOUT: Sleep Out
HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before sending any new commands
CMD(0x29); // DISPON: Display On
}
static void display_unsleep(void) {
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
CMD(0x11); // SLPOUT: Sleep Out
HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before
// sending any new commands
CMD(0x29); // DISPON: Display On
}
}
static struct {
uint16_t x, y;
} BUFFER_OFFSET;
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;
y0 += BUFFER_OFFSET.y; y1 += BUFFER_OFFSET.y;
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) {
CMD(0x2A); 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 struct { uint16_t x, y; } BUFFER_OFFSET;
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;
y0 += BUFFER_OFFSET.y;
y1 += BUFFER_OFFSET.y;
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
CMD(0x2A);
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)
{
char BX = 0, BY = 0;
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || (id == DISPLAY_ID_ST7789V)) {
#define RGB (1 << 3)
#define MV (1 << 5)
#define MX (1 << 6)
#define MY (1 << 7)
// MADCTL: Memory Data Access Control - reference:
// section 9.3 in the ILI9341 manual
// section 6.2.18 in the GC9307 manual
// section 8.12 in the ST7789V manual
uint8_t display_command_parameter = 0;
switch (degrees) {
case 0:
display_command_parameter = 0;
BY = (id == DISPLAY_ID_GC9307);
break;
case 90:
display_command_parameter = MV | MX;
BX = (id == DISPLAY_ID_GC9307);
break;
case 180:
display_command_parameter = MX | MY;
BY = (id != DISPLAY_ID_GC9307);
break;
case 270:
display_command_parameter = MV | MY;
BX = (id != DISPLAY_ID_GC9307);
break;
}
if (id == DISPLAY_ID_GC9307) {
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
static void display_set_orientation(int degrees) {
char BX = 0, BY = 0;
uint32_t id = display_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
#define RGB (1 << 3)
#define MV (1 << 5)
#define MX (1 << 6)
#define MY (1 << 7)
// MADCTL: Memory Data Access Control - reference:
// section 9.3 in the ILI9341 manual
// section 6.2.18 in the GC9307 manual
// section 8.12 in the ST7789V manual
uint8_t display_command_parameter = 0;
switch (degrees) {
case 0:
display_command_parameter = 0;
BY = (id == DISPLAY_ID_GC9307);
break;
case 90:
display_command_parameter = MV | MX;
BX = (id == DISPLAY_ID_GC9307);
break;
case 180:
display_command_parameter = MX | MY;
BY = (id != DISPLAY_ID_GC9307);
break;
case 270:
display_command_parameter = MV | MY;
BX = (id != DISPLAY_ID_GC9307);
break;
}
if (id == DISPLAY_ID_GC9307) {
display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
}
BUFFER_OFFSET.x = BX ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
BUFFER_OFFSET.y = BY ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
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;
BUFFER_OFFSET.y = BY ? (MAX_DISPLAY_RESY - DISPLAY_RESY) : 0;
}
static void display_set_backlight(int val)
{
TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
static void display_set_backlight(int val) {
TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
}
static void display_hardware_reset(void)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
// wait 10 milliseconds. only needs to be low for 10 microseconds.
// my dev display module ties display reset and touch panel reset together.
// keeping this low for max(display_reset_time, ctpm_reset_time) aids development and does not hurt.
HAL_Delay(10);
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)
// identify the controller we will communicate with
static void display_hardware_reset(void) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
// wait 10 milliseconds. only needs to be low for 10 microseconds.
// my dev display module ties display reset and touch panel reset together.
// keeping this low for max(display_reset_time, ctpm_reset_time) aids
// development and does not hurt.
HAL_Delay(10);
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)
// identify the controller we will communicate with
}
void display_init(void)
{
// init peripherials
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_FMC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
// LCD_PWM/PA7 (backlight control)
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF1_TIM1;
GPIO_InitStructure.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// enable PWM timer
TIM_HandleTypeDef TIM1_Handle;
TIM1_Handle.Instance = TIM1;
TIM1_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1;
// TIM1/APB2 source frequency equals to SystemCoreClock in our configuration, we want 1 MHz
TIM1_Handle.Init.Prescaler = SystemCoreClock / 1000000 - 1;
TIM1_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM1_Handle.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&TIM1_Handle);
TIM_OC_InitTypeDef TIM_OC_InitStructure;
TIM_OC_InitStructure.Pulse = 0;
TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM2;
TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE;
TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET;
HAL_TIM_PWM_ConfigChannel(&TIM1_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1);
display_backlight(0);
HAL_TIM_PWM_Start(&TIM1_Handle, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&TIM1_Handle, TIM_CHANNEL_1);
// LCD_RST/PC14
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_14;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, 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;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
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.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
// Reference UM1725 "Description of STM32F4 HAL and LL drivers", section 64.2.1 "How to use this driver"
SRAM_HandleTypeDef external_display_data_sram;
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
external_display_data_sram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
external_display_data_sram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
external_display_data_sram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
external_display_data_sram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
FMC_NORSRAM_TimingTypeDef normal_mode_timing;
normal_mode_timing.AddressSetupTime = 4;
normal_mode_timing.AddressHoldTime = 1;
normal_mode_timing.DataSetupTime = 4;
normal_mode_timing.BusTurnAroundDuration = 0;
normal_mode_timing.CLKDivision = 2;
normal_mode_timing.DataLatency = 2;
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
display_hardware_reset();
uint32_t id = display_identify();
if (id == DISPLAY_ID_GC9307) {
CMD(0xFE); // Inter Register Enable1
CMD(0xEF); // Inter Register Enable2
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(0xE8); DATA(0x12); DATA(0x00); // Frame Rate
CMD(0xC3); DATA(0x27); // Power Control 2
CMD(0xC4); DATA(0x18); // Power Control 3
CMD(0xC9); DATA(0x1F); // Power Control 4
CMD(0xC5); DATA(0x0F);
CMD(0xC6); DATA(0x00);
CMD(0xC7); DATA(0x10);
CMD(0xC8); DATA(0x01);
CMD(0xFF); DATA(0x62);
CMD(0x99); DATA(0x3E);
CMD(0x9D); DATA(0x4B);
CMD(0x8E); DATA(0x0F);
// SET_GAMMA1
CMD(0xF0); DATA(0x8F); DATA(0x1B); DATA(0x05); DATA(0x06); DATA(0x07); DATA(0x42);
// SET_GAMMA3
CMD(0xF2); DATA(0x5C); DATA(0x1F); DATA(0x12); DATA(0x10); DATA(0x07); DATA(0x43);
// SET_GAMMA2
CMD(0xF1); DATA(0x59); DATA(0xCF); DATA(0xCF); DATA(0x35); DATA(0x37); DATA(0x8F);
// 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_init(void) {
// init peripherials
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_FMC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
// LCD_PWM/PA7 (backlight control)
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF1_TIM1;
GPIO_InitStructure.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// enable PWM timer
TIM_HandleTypeDef TIM1_Handle;
TIM1_Handle.Instance = TIM1;
TIM1_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1;
// TIM1/APB2 source frequency equals to SystemCoreClock in our configuration,
// we want 1 MHz
TIM1_Handle.Init.Prescaler = SystemCoreClock / 1000000 - 1;
TIM1_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM1_Handle.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&TIM1_Handle);
TIM_OC_InitTypeDef TIM_OC_InitStructure;
TIM_OC_InitStructure.Pulse = 0;
TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM2;
TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE;
TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET;
HAL_TIM_PWM_ConfigChannel(&TIM1_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1);
display_backlight(0);
HAL_TIM_PWM_Start(&TIM1_Handle, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&TIM1_Handle, TIM_CHANNEL_1);
// LCD_RST/PC14
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_14;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14,
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;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
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.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4
// LCD_WR/PD5
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0
// LCD_D3/PD1
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9
// LCD_D7/PE10
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
// Reference UM1725 "Description of STM32F4 HAL and LL drivers",
// section 64.2.1 "How to use this driver"
SRAM_HandleTypeDef external_display_data_sram;
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
external_display_data_sram.Init.BurstAccessMode =
FMC_BURST_ACCESS_MODE_DISABLE;
external_display_data_sram.Init.WaitSignalPolarity =
FMC_WAIT_SIGNAL_POLARITY_LOW;
external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
external_display_data_sram.Init.AsynchronousWait =
FMC_ASYNCHRONOUS_WAIT_DISABLE;
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
external_display_data_sram.Init.ContinuousClock =
FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
FMC_NORSRAM_TimingTypeDef normal_mode_timing;
normal_mode_timing.AddressSetupTime = 4;
normal_mode_timing.AddressHoldTime = 1;
normal_mode_timing.DataSetupTime = 4;
normal_mode_timing.BusTurnAroundDuration = 0;
normal_mode_timing.CLKDivision = 2;
normal_mode_timing.DataLatency = 2;
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
display_hardware_reset();
uint32_t id = display_identify();
if (id == DISPLAY_ID_GC9307) {
CMD(0xFE); // Inter Register Enable1
CMD(0xEF); // Inter Register Enable2
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(0xE8); DATA(0x12); DATA(0x00); // Frame Rate
CMD(0xC3);
DATA(0x27); // Power Control 2
CMD(0xC4);
DATA(0x18); // Power Control 3
CMD(0xC9);
DATA(0x1F); // Power Control 4
CMD(0xC5);
DATA(0x0F);
CMD(0xC6);
DATA(0x00);
CMD(0xC7);
DATA(0x10);
CMD(0xC8);
DATA(0x01);
CMD(0xFF);
DATA(0x62);
CMD(0x99);
DATA(0x3E);
CMD(0x9D);
DATA(0x4B);
CMD(0x8E);
DATA(0x0F);
// SET_GAMMA1
CMD(0xF0);
DATA(0x8F);
DATA(0x1B);
DATA(0x05);
DATA(0x06);
DATA(0x07);
DATA(0x42);
// SET_GAMMA3
CMD(0xF2);
DATA(0x5C);
DATA(0x1F);
DATA(0x12);
DATA(0x10);
DATA(0x07);
DATA(0x43);
// SET_GAMMA2
CMD(0xF1);
DATA(0x59);
DATA(0xCF);
DATA(0xCF);
DATA(0x35);
DATA(0x37);
DATA(0x8F);
// 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)
{
uint32_t id = display_identify();
if (id && (id != DISPLAY_ID_GC9307)) {
// synchronize with the panel synchronization signal in order to avoid visual tearing effects
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
void display_refresh(void) {
uint32_t id = display_identify();
if (id && (id != DISPLAY_ID_GC9307)) {
// synchronize with the panel synchronization signal in order to avoid
// visual tearing effects
while (GPIO_PIN_RESET == 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
#ifdef TREZOR_EMULATOR_RASPI
#define WINDOW_WIDTH 480
#define WINDOW_HEIGHT 320
#define TOUCH_OFFSET_X 110
#define TOUCH_OFFSET_Y 40
#define WINDOW_WIDTH 480
#define WINDOW_HEIGHT 320
#define TOUCH_OFFSET_X 110
#define TOUCH_OFFSET_Y 40
#else
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 600
#define TOUCH_OFFSET_X 80
#define TOUCH_OFFSET_Y 110
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 600
#define TOUCH_OFFSET_X 80
#define TOUCH_OFFSET_Y 110
#endif
#elif TREZOR_MODEL == 1
#define WINDOW_WIDTH 200
#define WINDOW_HEIGHT 340
#define TOUCH_OFFSET_X 36
#define TOUCH_OFFSET_Y 92
#define WINDOW_WIDTH 200
#define WINDOW_HEIGHT 340
#define TOUCH_OFFSET_X 36
#define TOUCH_OFFSET_Y 92
#else
#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;
static struct {
struct {
uint16_t x, y;
} start;
struct {
uint16_t x, y;
} end;
struct {
uint16_t x, y;
} pos;
struct {
uint16_t x, y;
} start;
struct {
uint16_t x, y;
} end;
struct {
uint16_t x, y;
} pos;
} PIXELWINDOW;
void PIXELDATA(uint16_t c) {
#if TREZOR_MODEL == 1
// set to white if highest bits of all R, G, B values are set to 1
// bin(10000 100000 10000) = hex(0x8410)
// otherwise set to black
c = (c & 0x8410) ? 0xFFFF : 0x0000;
// set to white if highest bits of all R, G, B values are set to 1
// bin(10000 100000 10000) = hex(0x8410)
// otherwise set to black
c = (c & 0x8410) ? 0xFFFF : 0x0000;
#endif
if (!RENDERER) {
display_init();
}
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
((uint16_t *)BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch / sizeof(uint16_t)] = c;
}
PIXELWINDOW.pos.x++;
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
}
if (!RENDERER) {
display_init();
}
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x &&
PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
((uint16_t *)
BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch /
sizeof(uint16_t)] = c;
}
PIXELWINDOW.pos.x++;
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
PIXELWINDOW.pos.y++;
}
}
#else
#define PIXELDATA(X) (void)(X)
#endif
void display_init(void)
{
void display_init(void) {
#ifndef TREZOR_EMULATOR_NOUI
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_Init error");
}
atexit(SDL_Quit);
SDL_Window *win = SDL_CreateWindow("TREZOR Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_Init error");
}
atexit(SDL_Quit);
SDL_Window *win =
SDL_CreateWindow("TREZOR Emulator", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
#ifdef TREZOR_EMULATOR_RASPI
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
#else
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
#endif
);
if (!win) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_CreateWindow error");
}
RENDERER = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
if (!RENDERER) {
printf("%s\n", SDL_GetError());
SDL_DestroyWindow(win);
ensure(secfalse, "SDL_CreateRenderer error");
}
SDL_SetRenderDrawColor(RENDERER, 0, 0, 0, 255);
SDL_RenderClear(RENDERER);
BUFFER = SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16, 0xF800, 0x07E0, 0x001F, 0x0000);
TEXTURE = SDL_CreateTexture(RENDERER, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX, DISPLAY_RESY);
SDL_SetTextureBlendMode(TEXTURE, SDL_BLENDMODE_BLEND);
);
if (!win) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_CreateWindow error");
}
RENDERER = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
if (!RENDERER) {
printf("%s\n", SDL_GetError());
SDL_DestroyWindow(win);
ensure(secfalse, "SDL_CreateRenderer error");
}
SDL_SetRenderDrawColor(RENDERER, 0, 0, 0, 255);
SDL_RenderClear(RENDERER);
BUFFER = SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16,
0xF800, 0x07E0, 0x001F, 0x0000);
TEXTURE = SDL_CreateTexture(RENDERER, SDL_PIXELFORMAT_RGB565,
SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
DISPLAY_RESY);
SDL_SetTextureBlendMode(TEXTURE, SDL_BLENDMODE_BLEND);
#ifdef __APPLE__
// macOS Mojave SDL black screen workaround
SDL_PumpEvents();
SDL_SetWindowSize(win, WINDOW_WIDTH, WINDOW_HEIGHT);
// macOS Mojave SDL black screen workaround
SDL_PumpEvents();
SDL_SetWindowSize(win, WINDOW_WIDTH, WINDOW_HEIGHT);
#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
BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_raspi.jpg");
BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_raspi.jpg");
#else
BACKGROUND = IMG_LoadTexture(RENDERER, "../embed/unix/background_" XSTR(TREZOR_MODEL) ".jpg");
BACKGROUND = IMG_LoadTexture(
RENDERER, "../embed/unix/background_" XSTR(TREZOR_MODEL) ".jpg");
#endif
if (BACKGROUND) {
SDL_SetTextureBlendMode(BACKGROUND, SDL_BLENDMODE_NONE);
sdl_touch_offset_x = TOUCH_OFFSET_X;
sdl_touch_offset_y = TOUCH_OFFSET_Y;
} else {
SDL_SetWindowSize(win, DISPLAY_RESX + 2 * EMULATOR_BORDER, DISPLAY_RESY + 2 * EMULATOR_BORDER);
sdl_touch_offset_x = EMULATOR_BORDER;
sdl_touch_offset_y = EMULATOR_BORDER;
}
DISPLAY_BACKLIGHT = 0;
if (BACKGROUND) {
SDL_SetTextureBlendMode(BACKGROUND, SDL_BLENDMODE_NONE);
sdl_touch_offset_x = TOUCH_OFFSET_X;
sdl_touch_offset_y = TOUCH_OFFSET_Y;
} else {
SDL_SetWindowSize(win, DISPLAY_RESX + 2 * EMULATOR_BORDER,
DISPLAY_RESY + 2 * EMULATOR_BORDER);
sdl_touch_offset_x = EMULATOR_BORDER;
sdl_touch_offset_y = EMULATOR_BORDER;
}
DISPLAY_BACKLIGHT = 0;
#ifdef TREZOR_EMULATOR_RASPI
DISPLAY_ORIENTATION = 270;
SDL_ShowCursor(SDL_DISABLE);
DISPLAY_ORIENTATION = 270;
SDL_ShowCursor(SDL_DISABLE);
#else
DISPLAY_ORIENTATION = 0;
DISPLAY_ORIENTATION = 0;
#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
if (!RENDERER) {
display_init();
}
PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0;
PIXELWINDOW.end.x = x1; PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0; PIXELWINDOW.pos.y = y0;
if (!RENDERER) {
display_init();
}
PIXELWINDOW.start.x = x0;
PIXELWINDOW.start.y = y0;
PIXELWINDOW.end.x = x1;
PIXELWINDOW.end.y = y1;
PIXELWINDOW.pos.x = x0;
PIXELWINDOW.pos.y = y0;
#endif
}
void display_refresh(void)
{
void display_refresh(void) {
#ifndef TREZOR_EMULATOR_NOUI
if (!RENDERER) {
display_init();
}
if (BACKGROUND) {
SDL_RenderCopy(RENDERER, BACKGROUND, NULL, NULL);
} else {
SDL_RenderClear(RENDERER);
}
SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch);
if (!RENDERER) {
display_init();
}
if (BACKGROUND) {
SDL_RenderCopy(RENDERER, BACKGROUND, NULL, NULL);
} else {
SDL_RenderClear(RENDERER);
}
SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch);
#define BACKLIGHT_NORMAL 150
SDL_SetTextureAlphaMod(TEXTURE, MIN(255, 255 * DISPLAY_BACKLIGHT / BACKLIGHT_NORMAL));
if (BACKGROUND) {
const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX, DISPLAY_RESY};
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
} else {
const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX, DISPLAY_RESY};
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
}
SDL_RenderPresent(RENDERER);
SDL_SetTextureAlphaMod(TEXTURE,
MIN(255, 255 * DISPLAY_BACKLIGHT / BACKLIGHT_NORMAL));
if (BACKGROUND) {
const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX,
DISPLAY_RESY};
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
} else {
const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX,
DISPLAY_RESY};
SDL_RenderCopyEx(RENDERER, TEXTURE, NULL, &r, DISPLAY_ORIENTATION, NULL, 0);
}
SDL_RenderPresent(RENDERER);
#endif
}
static void display_set_orientation(int degrees)
{
display_refresh();
}
static void display_set_orientation(int degrees) { display_refresh(); }
static void display_set_backlight(int val)
{
display_refresh();
}
static void display_set_backlight(int val) { display_refresh(); }
void display_save(const char *prefix)
{
void display_save(const char *prefix) {
#ifndef TREZOR_EMULATOR_NOUI
if (!RENDERER) {
display_init();
}
static uint32_t cnt = 0;
char fname[256];
snprintf(fname, sizeof(fname), "%s%08d.png", prefix, cnt);
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_BlitSurface(BUFFER, &rect, crop, NULL);
IMG_SavePNG(crop, fname);
SDL_FreeSurface(crop);
fprintf(stderr, "Saved screenshot to %s\n", fname);
cnt++;
if (!RENDERER) {
display_init();
}
static uint32_t cnt = 0;
char fname[256];
snprintf(fname, sizeof(fname), "%s%08d.png", prefix, cnt);
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_BlitSurface(BUFFER, &rect, crop, NULL);
IMG_SavePNG(crop, fname);
SDL_FreeSurface(crop);
fprintf(stderr, "Saved screenshot to %s\n", fname);
cnt++;
#endif
}

File diff suppressed because it is too large Load Diff

@ -25,42 +25,42 @@
#if TREZOR_MODEL == T
// ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#elif TREZOR_MODEL == 1
#define MAX_DISPLAY_RESX 128
#define MAX_DISPLAY_RESY 64
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#define MAX_DISPLAY_RESX 128
#define MAX_DISPLAY_RESY 64
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#else
#error Unknown TREZOR Model
#endif
#define FONT_BPP 4
#define FONT_SIZE 20
#define AVATAR_IMAGE_SIZE 144
#define LOADER_ICON_SIZE 64
#define FONT_BPP 4
#define FONT_SIZE 20
#define AVATAR_IMAGE_SIZE 144
#define LOADER_ICON_SIZE 64
#define RGB16(R, G, B) ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3)
#define COLOR_WHITE 0xFFFF
#define COLOR_BLACK 0x0000
#define RGB16(R, G, B) ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3)
#define COLOR_WHITE 0xFFFF
#define COLOR_BLACK 0x0000
#ifdef TREZOR_FONT_NORMAL_ENABLE
#define FONT_NORMAL (-1)
#define FONT_NORMAL (-1)
#endif
#ifdef TREZOR_FONT_BOLD_ENABLE
#define FONT_BOLD (-2)
#define FONT_BOLD (-2)
#endif
#ifdef TREZOR_FONT_MONO_ENABLE
#define FONT_MONO (-3)
#define FONT_MONO (-3)
#endif
#ifdef TREZOR_FONT_MONO_BOLD_ENABLE
#define FONT_MONO_BOLD (-4)
#define FONT_MONO_BOLD (-4)
#endif
// provided by port
@ -74,22 +74,31 @@ void display_save(const char *prefix);
void display_clear(void);
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_avatar(int x, int y, const void *data, int datalen, uint16_t fgcolor, uint16_t bgcolor);
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);
void display_avatar(int x, int y, const void *data, int datalen,
uint16_t fgcolor, uint16_t bgcolor);
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
void display_print_color(uint16_t fgcolor, uint16_t bgcolor);
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
void display_text(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);
void display_text(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);
void display_qrcode(int x, int y, const char *data, int datalen, uint8_t scale);

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

@ -1,3 +1,3 @@
#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/>.
*/
// clang-format off
/*
* stream_inflate - tiny inflate library with output streaming
*

@ -22,6 +22,9 @@
#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

@ -1,3 +1,4 @@
// clang-format off
static const int img_loader_size = 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,},

@ -26,18 +26,20 @@
/// Provide access to device display.
/// '''
typedef struct _mp_obj_Display_t {
mp_obj_base_t base;
mp_obj_base_t base;
} mp_obj_Display_t;
/// def __init__(self) -> None:
/// '''
/// 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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_obj_Display_t *o = m_new_obj(mp_obj_Display_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
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) {
mp_arg_check_num(n_args, n_kw, 0, 0, false);
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:
@ -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.
/// '''
STATIC mp_obj_t mod_trezorui_Display_clear(mp_obj_t self) {
display_clear();
return mp_const_none;
display_clear();
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:
/// '''
/// Refresh display (update screen).
/// '''
STATIC mp_obj_t mod_trezorui_Display_refresh(mp_obj_t self) {
display_refresh();
return mp_const_none;
display_refresh();
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:
/// '''
/// 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) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
uint16_t c = mp_obj_get_int(args[5]);
display_bar(x, y, w, h, c);
return mp_const_none;
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
uint16_t c = mp_obj_get_int(args[5]);
display_bar(x, y, w, h, c);
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:
/// '''
/// 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.
/// '''
STATIC mp_obj_t mod_trezorui_Display_bar_radius(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
uint16_t c = mp_obj_get_int(args[5]);
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;
/// 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.
/// '''
STATIC mp_obj_t mod_trezorui_Display_bar_radius(size_t n_args,
const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
uint16_t c = mp_obj_get_int(args[5]);
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:
/// '''
/// Renders an image at position (x,y).
/// 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t image;
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
const uint8_t *data = image.buf;
if (image.len < 8 || memcmp(data, "TOIf", 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 != image.len - 12) {
mp_raise_ValueError("Invalid size of data");
}
display_image(x, y, w, h, data + 12, datalen);
return mp_const_none;
/// 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t image;
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
const uint8_t *data = image.buf;
if (image.len < 8 || memcmp(data, "TOIf", 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 != image.len - 12) {
mp_raise_ValueError("Invalid size of data");
}
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).
/// The image needs to be in TREZOR Optimized Image Format (TOIF) - 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t image;
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
const uint8_t *data = image.buf;
if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) {
mp_raise_ValueError("Invalid image format");
}
mp_int_t w = *(uint16_t *)(data + 4);
mp_int_t h = *(uint16_t *)(data + 6);
if (w != AVATAR_IMAGE_SIZE || h != AVATAR_IMAGE_SIZE) {
mp_raise_ValueError("Invalid image size");
}
mp_int_t datalen = *(uint32_t *)(data + 8);
if (datalen != image.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_avatar(x, y, data + 12, datalen, fgcolor, bgcolor);
return mp_const_none;
/// The image needs to be in TREZOR Optimized Image Format (TOIF) -
/// 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t image;
mp_get_buffer_raise(args[3], &image, MP_BUFFER_READ);
const uint8_t *data = image.buf;
if (image.len < 8 || memcmp(data, "TOIf", 4) != 0) {
mp_raise_ValueError("Invalid image format");
}
mp_int_t w = *(uint16_t *)(data + 4);
mp_int_t h = *(uint16_t *)(data + 6);
if (w != AVATAR_IMAGE_SIZE || h != AVATAR_IMAGE_SIZE) {
mp_raise_ValueError("Invalid image size");
}
mp_int_t datalen = *(uint32_t *)(data + 8);
if (datalen != image.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_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.
/// The icon needs to be in TREZOR Optimized Image Format (TOIF) - gray-scale mode.
/// Renders an icon at position (x,y), fgcolor is used as foreground color,
/// 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) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t x = mp_obj_get_int(args[1]);
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_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;
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 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");
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_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);
uint16_t iconfgcolor;
if (n_args > 6) { // icon color provided
iconfgcolor = mp_obj_get_int(args[6]);
} 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:
/// '''
/// 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) {
mp_buffer_info_t buf;
mp_get_buffer_raise(text, &buf, MP_BUFFER_READ);
if (buf.len > 0) {
display_print(buf.buf, buf.len);
}
return mp_const_none;
mp_buffer_info_t buf;
mp_get_buffer_raise(text, &buf, MP_BUFFER_READ);
if (buf.len > 0) {
display_print(buf.buf, buf.len);
}
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.
/// Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
/// Fills at least minwidth pixels with bgcolor.
/// Returns width of rendered text in pixels.
/// Renders left-aligned text at position (x,y) where x is left position and
/// y is baseline. Font font is used for rendering, fgcolor is used as
/// 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(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x, y - 18, barwidth, 23, bgcolor);
// prefill end
display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x, y - 18, barwidth, 23, bgcolor);
// prefill end
display_text(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_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:
/// '''
/// 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.
/// 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor);
// prefill end
display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w);
/// 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. 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x - barwidth / 2, y - 18, barwidth, 23, bgcolor);
// 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:
/// '''
/// 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.
/// 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor);
// prefill end
display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor);
return mp_obj_new_int(w);
/// 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. 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]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_buffer_info_t text;
mp_get_buffer_raise(args[3], &text, MP_BUFFER_READ);
mp_int_t font = mp_obj_get_int(args[4]);
mp_int_t fgcolor = mp_obj_get_int(args[5]);
mp_int_t bgcolor = mp_obj_get_int(args[6]);
mp_int_t minwidth = (n_args > 7) ? mp_obj_get_int(args[7]) : 0;
// prefill start
int w = display_text_width(text.buf, text.len, font);
int barwidth = MAX(w, minwidth);
display_bar(x - barwidth, y - 18, barwidth, 23, bgcolor);
// 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:
/// '''
/// 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) {
mp_buffer_info_t txt;
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
mp_int_t f = mp_obj_get_int(font);
int w = display_text_width(txt.buf, txt.len, f);
return mp_obj_new_int(w);
STATIC mp_obj_t mod_trezorui_Display_text_width(mp_obj_t self, mp_obj_t text,
mp_obj_t font) {
mp_buffer_info_t txt;
mp_get_buffer_raise(text, &txt, MP_BUFFER_READ);
mp_int_t f = mp_obj_get_int(font);
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:
/// '''
/// Renders data encoded as a QR code centered at position (x,y).
/// Scale determines a zoom factor.
/// '''
STATIC mp_obj_t mod_trezorui_Display_qrcode(size_t n_args, const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t scale = mp_obj_get_int(args[4]);
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);
if (data.len > 0) {
display_qrcode(x, y, data.buf, data.len, scale);
}
return mp_const_none;
STATIC mp_obj_t mod_trezorui_Display_qrcode(size_t n_args,
const mp_obj_t *args) {
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t scale = mp_obj_get_int(args[4]);
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);
if (data.len > 0) {
display_qrcode(x, y, data.buf, data.len, scale);
}
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:
/// '''
/// Sets display orientation to 0, 90, 180 or 270 degrees.
/// Everything needs to be redrawn again when this function is used.
/// 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;
if (n_args > 1) {
deg = mp_obj_get_int(args[1]);
if (deg != 0 && deg != 90 && deg != 180 && deg != 270) {
mp_raise_ValueError("Value must be 0, 90, 180 or 270");
}
deg = display_orientation(deg);
} else {
deg = display_orientation(-1);
/// 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;
if (n_args > 1) {
deg = mp_obj_get_int(args[1]);
if (deg != 0 && deg != 90 && deg != 180 && deg != 270) {
mp_raise_ValueError("Value must be 0, 90, 180 or 270");
}
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:
/// '''
/// Sets backlight intensity to the value specified in val.
/// 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) {
mp_int_t val;
if (n_args > 1) {
val = mp_obj_get_int(args[1]);
if (val < 0 || val > 255) {
mp_raise_ValueError("Value must be between 0 and 255");
}
val = display_backlight(val);
} else {
val = display_backlight(-1);
STATIC mp_obj_t mod_trezorui_Display_backlight(size_t n_args,
const mp_obj_t *args) {
mp_int_t val;
if (n_args > 1) {
val = mp_obj_get_int(args[1]);
if (val < 0 || val > 255) {
mp_raise_ValueError("Value must be between 0 and 255");
}
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]:
/// '''
/// Sets offset (x, y) for all subsequent drawing calls.
/// 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) {
int xy[2], x, y;
if (n_args > 1) {
size_t xy_cnt;
mp_obj_t *xy_obj;
if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple)) {
mp_obj_tuple_get(args[1], &xy_cnt, &xy_obj);
} else {
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);
STATIC mp_obj_t mod_trezorui_Display_offset(size_t n_args,
const mp_obj_t *args) {
int xy[2], x, y;
if (n_args > 1) {
size_t xy_cnt;
mp_obj_t *xy_obj;
if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple)) {
mp_obj_tuple_get(args[1], &xy_cnt, &xy_obj);
} 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));
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(x);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(y);
return MP_OBJ_FROM_PTR(tuple);
xy[0] = mp_obj_get_int(xy_obj[0]);
xy[1] = mp_obj_get_int(xy_obj[1]);
display_offset(xy, &x, &y);
} 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:
/// '''
/// 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) {
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len > 0) {
display_save(pfx.buf);
}
return mp_const_none;
mp_buffer_info_t pfx;
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len > 0) {
display_save(pfx.buf);
}
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[] = {
{ 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_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj) },
{ MP_ROM_QSTR(MP_QSTR_bar_radius), MP_ROM_PTR(&mod_trezorui_Display_bar_radius_obj) },
{ MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&mod_trezorui_Display_image_obj) },
{ MP_ROM_QSTR(MP_QSTR_avatar), MP_ROM_PTR(&mod_trezorui_Display_avatar_obj) },
{ MP_ROM_QSTR(MP_QSTR_icon), MP_ROM_PTR(&mod_trezorui_Display_icon_obj) },
{ MP_ROM_QSTR(MP_QSTR_loader), MP_ROM_PTR(&mod_trezorui_Display_loader_obj) },
{ MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mod_trezorui_Display_print_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&mod_trezorui_Display_text_obj) },
{ MP_ROM_QSTR(MP_QSTR_text_center), MP_ROM_PTR(&mod_trezorui_Display_text_center_obj) },
{ MP_ROM_QSTR(MP_QSTR_text_right), MP_ROM_PTR(&mod_trezorui_Display_text_right_obj) },
{ MP_ROM_QSTR(MP_QSTR_text_width), MP_ROM_PTR(&mod_trezorui_Display_text_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_qrcode), MP_ROM_PTR(&mod_trezorui_Display_qrcode_obj) },
{ MP_ROM_QSTR(MP_QSTR_orientation), MP_ROM_PTR(&mod_trezorui_Display_orientation_obj) },
{ MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&mod_trezorui_Display_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&mod_trezorui_Display_offset_obj) },
{ 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) },
{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_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj)},
{MP_ROM_QSTR(MP_QSTR_bar_radius),
MP_ROM_PTR(&mod_trezorui_Display_bar_radius_obj)},
{MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&mod_trezorui_Display_image_obj)},
{MP_ROM_QSTR(MP_QSTR_avatar), MP_ROM_PTR(&mod_trezorui_Display_avatar_obj)},
{MP_ROM_QSTR(MP_QSTR_icon), MP_ROM_PTR(&mod_trezorui_Display_icon_obj)},
{MP_ROM_QSTR(MP_QSTR_loader), MP_ROM_PTR(&mod_trezorui_Display_loader_obj)},
{MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mod_trezorui_Display_print_obj)},
{MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&mod_trezorui_Display_text_obj)},
{MP_ROM_QSTR(MP_QSTR_text_center),
MP_ROM_PTR(&mod_trezorui_Display_text_center_obj)},
{MP_ROM_QSTR(MP_QSTR_text_right),
MP_ROM_PTR(&mod_trezorui_Display_text_right_obj)},
{MP_ROM_QSTR(MP_QSTR_text_width),
MP_ROM_PTR(&mod_trezorui_Display_text_width_obj)},
{MP_ROM_QSTR(MP_QSTR_qrcode), MP_ROM_PTR(&mod_trezorui_Display_qrcode_obj)},
{MP_ROM_QSTR(MP_QSTR_orientation),
MP_ROM_PTR(&mod_trezorui_Display_orientation_obj)},
{MP_ROM_QSTR(MP_QSTR_backlight),
MP_ROM_PTR(&mod_trezorui_Display_backlight_obj)},
{MP_ROM_QSTR(MP_QSTR_offset), MP_ROM_PTR(&mod_trezorui_Display_offset_obj)},
{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 = {
{ &mp_type_type },
{&mp_type_type},
.name = MP_QSTR_Display,
.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/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "py/runtime.h"
@ -28,15 +28,16 @@
#include "modtrezorui-display.h"
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_Display), MP_ROM_PTR(&mod_trezorui_Display_type) },
{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)},
};
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 = {
.base = { &mp_type_module },
.base = {&mp_type_module},
.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.
/// '''
STATIC mp_obj_t mod_trezorutils_consteq(mp_obj_t sec, mp_obj_t pub) {
mp_buffer_info_t secbuf;
mp_get_buffer_raise(sec, &secbuf, MP_BUFFER_READ);
mp_buffer_info_t pubbuf;
mp_get_buffer_raise(pub, &pubbuf, MP_BUFFER_READ);
size_t diff = secbuf.len - pubbuf.len;
for (size_t i = 0; i < pubbuf.len; i++) {
const uint8_t *s = (uint8_t *)secbuf.buf;
const uint8_t *p = (uint8_t *)pubbuf.buf;
diff |= s[i] - p[i];
}
if (diff == 0) {
return mp_const_true;
} else {
return mp_const_false;
}
mp_buffer_info_t secbuf;
mp_get_buffer_raise(sec, &secbuf, MP_BUFFER_READ);
mp_buffer_info_t pubbuf;
mp_get_buffer_raise(pub, &pubbuf, MP_BUFFER_READ);
size_t diff = secbuf.len - pubbuf.len;
for (size_t i = 0; i < pubbuf.len; i++) {
const uint8_t *s = (uint8_t *)secbuf.buf;
const uint8_t *p = (uint8_t *)pubbuf.buf;
diff |= s[i] - p[i];
}
if (diff == 0) {
return mp_const_true;
} else {
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,
/// 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.
/// '''
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_get_buffer_raise(args[0], &dst, MP_BUFFER_WRITE);
uint32_t dst_ofs = trezor_obj_get_uint(args[1]);
mp_buffer_info_t dst;
mp_get_buffer_raise(args[0], &dst, MP_BUFFER_WRITE);
uint32_t dst_ofs = trezor_obj_get_uint(args[1]);
mp_buffer_info_t src;
mp_get_buffer_raise(args[2], &src, MP_BUFFER_READ);
uint32_t src_ofs = trezor_obj_get_uint(args[3]);
mp_buffer_info_t src;
mp_get_buffer_raise(args[2], &src, MP_BUFFER_READ);
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 src_rem = (src_ofs < src.len) ? src.len - src_ofs : 0;
size_t ncpy = MIN(n, MIN(src_rem, dst_rem));
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 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:
/// '''
/// Halts execution.
/// '''
STATIC mp_obj_t mod_trezorutils_halt(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t msg;
if (n_args > 0 && mp_get_buffer(args[0], &msg, MP_BUFFER_READ)) {
ensure(secfalse, msg.buf);
} else {
ensure(secfalse, "halt");
}
return mp_const_none;
mp_buffer_info_t msg;
if (n_args > 0 && mp_get_buffer(args[0], &msg, MP_BUFFER_READ)) {
ensure(secfalse, msg.buf);
} else {
ensure(secfalse, "halt");
}
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:
/// '''
@ -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) {
#ifndef TREZOR_EMULATOR
__asm__ volatile("msr control, %0" :: "r" (0x1));
__asm__ volatile("isb");
__asm__ volatile("msr control, %0" ::"r"(0x1));
__asm__ volatile("isb");
#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)
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_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_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___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_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_set_mode_unprivileged),
MP_ROM_PTR(&mod_trezorutils_set_mode_unprivileged_obj)},
// various built-in constants
{ 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_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_MODEL), MP_ROM_QSTR(MP_QSTR(TREZOR_MODEL)) },
{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_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_MODEL), MP_ROM_QSTR(MP_QSTR(TREZOR_MODEL))},
#ifdef TREZOR_EMULATOR
{ MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_true },
{MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_true},
#else
{ MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_false },
{MP_ROM_QSTR(MP_QSTR_EMULATOR), mp_const_false},
#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 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_trezorutils_globals,
.base = {&mp_type_module},
.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/>.
*/
#include "py/runtime.h"
#include "py/objint.h"
#include "py/runtime.h"
#ifndef __TREZOROBJ_H__
#define __TREZOROBJ_H__
@ -30,51 +30,49 @@
// 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.
static inline mp_int_t trezor_obj_get_int(mp_obj_t obj) {
if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
return i;
}
else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
mp_int_t i = 0;
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
if (!mpz_as_int_checked(&self->mpz, &i)) {
mp_raise_msg(&mp_type_OverflowError, "value does not fit into signed int type");
}
return i;
}
else {
mp_raise_TypeError("value is not int");
if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
return i;
} else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
mp_int_t i = 0;
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
if (!mpz_as_int_checked(&self->mpz, &i)) {
mp_raise_msg(&mp_type_OverflowError,
"value does not fit into signed int type");
}
return i;
} else {
mp_raise_TypeError("value is not int");
}
}
// 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
// 0).
static inline mp_uint_t trezor_obj_get_uint(mp_obj_t obj) {
if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
mp_uint_t u = i;
return u;
}
else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
mp_uint_t u = 0;
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
if (!mpz_as_uint_checked(&self->mpz, &u)) {
mp_raise_msg(&mp_type_OverflowError, "value does not fit into unsigned int type");
}
return u;
}
else {
mp_raise_TypeError("value is not int");
if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
mp_uint_t u = i;
return u;
} else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) {
mp_uint_t u = 0;
mp_obj_int_t *self = MP_OBJ_TO_PTR(obj);
if (!mpz_as_uint_checked(&self->mpz, &u)) {
mp_raise_msg(&mp_type_OverflowError,
"value does not fit into unsigned int type");
}
return u;
} else {
mp_raise_TypeError("value is not int");
}
}
static inline uint8_t trezor_obj_get_uint8(mp_obj_t obj) {
mp_uint_t u = trezor_obj_get_uint(obj);
if (u > 0xFF) {
mp_raise_msg(&mp_type_OverflowError, "value does not fit into byte type");
}
return u;
mp_uint_t u = trezor_obj_get_uint(obj);
if (u > 0xFF) {
mp_raise_msg(&mp_type_OverflowError, "value does not fit into byte type");
}
return u;
}
#endif

@ -19,9 +19,9 @@
#include <stdint.h>
#include <string.h>
#include "blake2s.h"
#include "common.h"
#include "flash.h"
#include "blake2s.h"
// symbols from bootloader.bin => bootloader.o
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) {
if (len != 32) return secfalse;
// 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)
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)
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)
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)
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)
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;
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;
}
*/
static secbool latest_bootloader(const uint8_t *hash, int len) {
if (len != 32) return secfalse;
// 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;
// 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;
if (len != 32) return secfalse;
// 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;
// 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)
{
// compute current bootloader hash
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
const uint32_t bl_len = 128 * 1024;
const void *bl_data = flash_get_address(FLASH_SECTOR_BOOTLOADER, 0, bl_len);
blake2s(bl_data, bl_len, hash, BLAKE2S_DIGEST_LENGTH);
void check_and_replace_bootloader(void) {
// compute current bootloader hash
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
const uint32_t bl_len = 128 * 1024;
const void *bl_data = flash_get_address(FLASH_SECTOR_BOOTLOADER, 0, bl_len);
blake2s(bl_data, bl_len, hash, BLAKE2S_DIGEST_LENGTH);
// don't whitelist the valid bootloaders for now
// ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader detected");
// don't whitelist the valid bootloaders for now
// ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader
// detected");
// do we have the latest bootloader?
if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) {
return;
}
// do we have the latest bootloader?
if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) {
return;
}
// replace bootloader with the latest one
const uint32_t *data = (const uint32_t *)&_binary_embed_firmware_bootloader_bin_start;
const uint32_t len = (const uint32_t)&_binary_embed_firmware_bootloader_bin_size;
ensure(flash_erase(FLASH_SECTOR_BOOTLOADER), NULL);
ensure(flash_unlock_write(), NULL);
for (int i = 0; i < len / sizeof(uint32_t); i++) {
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t), data[i]), 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);
// replace bootloader with the latest one
const uint32_t *data =
(const uint32_t *)&_binary_embed_firmware_bootloader_bin_start;
const uint32_t len =
(const uint32_t)&_binary_embed_firmware_bootloader_bin_size;
ensure(flash_erase(FLASH_SECTOR_BOOTLOADER), NULL);
ensure(flash_unlock_write(), NULL);
for (int i = 0; i < len / sizeof(uint32_t); i++) {
ensure(flash_write_word(FLASH_SECTOR_BOOTLOADER, i * sizeof(uint32_t),
data[i]),
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 <string.h>
#include "py/nlr.h"
#include "lib/utils/pyexec.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/repl.h"
#include "py/gc.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/pendsv.h"
#include "bl_check.h"
#include "common.h"
#include "display.h"
#include "flash.h"
@ -40,84 +41,82 @@
#include "rng.h"
#include "sdcard.h"
#include "touch.h"
#include "bl_check.h"
int main(void)
{
// reinitialize HAL for Trezor One
int main(void) {
// reinitialize HAL for Trezor One
#if TREZOR_MODEL == 1
HAL_Init();
HAL_Init();
#endif
collect_hw_entropy();
collect_hw_entropy();
#if TREZOR_MODEL == T
check_and_replace_bootloader();
// Enable MPU
mpu_config_firmware();
check_and_replace_bootloader();
// Enable MPU
mpu_config_firmware();
#endif
// Init peripherals
pendsv_init();
// Init peripherals
pendsv_init();
#if TREZOR_MODEL == 1
display_init();
touch_init();
display_init();
touch_init();
#endif
#if TREZOR_MODEL == T
sdcard_init();
touch_init();
touch_power_on();
sdcard_init();
touch_init();
touch_power_on();
display_clear();
display_clear();
#endif
printf("CORE: Preparing stack\n");
// Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit.
mp_stack_set_top(&_estack);
mp_stack_set_limit((char*)&_estack - (char*)&_heap_end - 1024);
// GC init
printf("CORE: Starting GC\n");
gc_init(&_heap_start, &_heap_end);
// Interpreter init
printf("CORE: Starting interpreter\n");
mp_init();
mp_obj_list_init(mp_sys_argv, 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)
// Execute the main script
printf("CORE: Executing main script\n");
pyexec_frozen_module("main.py");
// Clean up
printf("CORE: Main script finished, cleaning up\n");
mp_deinit();
return 0;
printf("CORE: Preparing stack\n");
// Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit.
mp_stack_set_top(&_estack);
mp_stack_set_limit((char *)&_estack - (char *)&_heap_end - 1024);
// GC init
printf("CORE: Starting GC\n");
gc_init(&_heap_start, &_heap_end);
// Interpreter init
printf("CORE: Starting interpreter\n");
mp_init();
mp_obj_list_init(mp_sys_argv, 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)
// Execute the main script
printf("CORE: Executing main script\n");
pyexec_frozen_module("main.py");
// Clean up
printf("CORE: Main script finished, cleaning up\n");
mp_deinit();
return 0;
}
// MicroPython default exception handler
void __attribute__((noreturn)) nlr_jump_fail(void *val) {
ensure(secfalse, "uncaught exception");
ensure(secfalse, "uncaught exception");
}
void PendSV_Handler(void) {
pendsv_isr_handler();
}
void PendSV_Handler(void) { pendsv_isr_handler(); }
// MicroPython builtin stubs
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) {
return mp_const_none;
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

@ -27,21 +27,21 @@
#include "extmod/utime_mphal.h"
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_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_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_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_diff), MP_ROM_PTR(&mp_utime_ticks_diff_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_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_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_add), MP_ROM_PTR(&mp_utime_ticks_add_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);
const mp_obj_module_t mp_module_utime = {
.base = { &mp_type_module },
.base = {&mp_type_module},
.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/
*

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

@ -19,8 +19,6 @@
#include "lib/utils/interrupt_char.h"
static inline mp_uint_t mp_hal_ticks_cpu(void) {
return 0;
}
static inline mp_uint_t mp_hal_ticks_cpu(void) { return 0; }
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/
*

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

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

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

@ -23,9 +23,9 @@
#include "common.h"
#include "display.h"
#include "rng.h"
#include "rand.h"
#include "flash.h"
#include "rand.h"
#include "rng.h"
#include "stm32f4xx_ll_utils.h"
@ -34,144 +34,154 @@ extern void shutdown(void);
#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) {
display_orientation(0);
display_backlight(255);
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
display_printf("\nFATAL ERROR:\n");
if (expr) {
display_printf("expr: %s\n", expr);
}
if (msg) {
display_printf("msg : %s\n", msg);
}
if (file) {
display_printf("file: %s:%d\n", file, line);
}
if (func) {
display_printf("func: %s\n", func);
}
void __attribute__((noreturn))
__fatal_error(const char *expr, const char *msg, const char *file, int line,
const char *func) {
display_orientation(0);
display_backlight(255);
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
display_printf("\nFATAL ERROR:\n");
if (expr) {
display_printf("expr: %s\n", expr);
}
if (msg) {
display_printf("msg : %s\n", msg);
}
if (file) {
display_printf("file: %s:%d\n", file, line);
}
if (func) {
display_printf("func: %s\n", func);
}
#ifdef GITREV
display_printf("rev : %s\n", XSTR(GITREV));
display_printf("rev : %s\n", XSTR(GITREV));
#endif
display_printf("\nPlease contact TREZOR support.\n");
shutdown();
for (;;);
display_printf("\nPlease contact TREZOR support.\n");
shutdown();
for (;;)
;
}
void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4)
{
display_orientation(0);
void __attribute__((noreturn))
error_shutdown(const char *line1, const char *line2, const char *line3,
const char *line4) {
display_orientation(0);
#ifdef TREZOR_FONT_NORMAL_ENABLE
display_clear();
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR);
int y = 32;
if (line1) {
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;
}
display_clear();
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR);
int y = 32;
if (line1) {
display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
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
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
if (line1) {
display_printf("%s\n", line1);
}
if (line2) {
display_printf("%s\n", line2);
}
if (line3) {
display_printf("%s\n", line3);
}
if (line4) {
display_printf("%s\n", line4);
}
display_printf("\nPlease unplug the device.\n");
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
if (line1) {
display_printf("%s\n", line1);
}
if (line2) {
display_printf("%s\n", line2);
}
if (line3) {
display_printf("%s\n", line3);
}
if (line4) {
display_printf("%s\n", line4);
}
display_printf("\nPlease unplug the device.\n");
#endif
display_backlight(255);
shutdown();
for (;;);
display_backlight(255);
shutdown();
for (;;)
;
}
#ifndef NDEBUG
void __assert_func(const char *file, int line, const char *func, const char *expr) {
__fatal_error(expr, "assert failed", file, line, func);
void __assert_func(const char *file, int line, const char *func,
const char *expr) {
__fatal_error(expr, "assert failed", file, line, func);
}
#endif
void hal_delay(uint32_t ms)
{
HAL_Delay(ms);
}
void hal_delay(uint32_t ms) { HAL_Delay(ms); }
void delay_random(void)
{
int wait = rng_get() & 0xff;
volatile int i = 0;
volatile int j = wait;
while (i < wait) {
if (i + j != wait) {
shutdown();
}
++i;
--j;
}
// Double-check loop completion.
if (i != wait || j != 0) {
shutdown();
void delay_random(void) {
int wait = rng_get() & 0xff;
volatile int i = 0;
volatile int j = wait;
while (i < wait) {
if (i + j != wait) {
shutdown();
}
++i;
--j;
}
// Double-check loop completion.
if (i != wait || j != 0) {
shutdown();
}
}
// 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)
void clear_otg_hs_memory(void)
{
// 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 that the peripheral memory is accessible
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
void clear_otg_hs_memory(void) {
// 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
// that the peripheral memory is
// accessible
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;
void __attribute__((noreturn)) __stack_chk_fail(void)
{
ensure(secfalse, "Stack smashing detected");
void __attribute__((noreturn)) __stack_chk_fail(void) {
ensure(secfalse, "Stack smashing detected");
}
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
void collect_hw_entropy(void)
{
// collect entropy from UUID
uint32_t w = LL_GetUID_Word0();
memcpy(HW_ENTROPY_DATA, &w, 4);
w = LL_GetUID_Word1();
memcpy(HW_ENTROPY_DATA + 4, &w, 4);
w = LL_GetUID_Word2();
memcpy(HW_ENTROPY_DATA + 8, &w, 4);
// set entropy in the OTP randomness block
if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t entropy[FLASH_OTP_BLOCK_SIZE];
random_buffer(entropy, FLASH_OTP_BLOCK_SIZE);
ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE), 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);
void collect_hw_entropy(void) {
// collect entropy from UUID
uint32_t w = LL_GetUID_Word0();
memcpy(HW_ENTROPY_DATA, &w, 4);
w = LL_GetUID_Word1();
memcpy(HW_ENTROPY_DATA + 4, &w, 4);
w = LL_GetUID_Word2();
memcpy(HW_ENTROPY_DATA + 8, &w, 4);
// set entropy in the OTP randomness block
if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t entropy[FLASH_OTP_BLOCK_SIZE];
random_buffer(entropy, FLASH_OTP_BLOCK_SIZE);
ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy,
FLASH_OTP_BLOCK_SIZE),
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);
}

@ -27,19 +27,41 @@
#define STR(s) #s
#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
#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
#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
void __attribute__((noreturn)) __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);
void __attribute__((noreturn))
__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);

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

@ -28,51 +28,54 @@
#define FLASH_SECTOR_COUNT 24
#define FLASH_SECTOR_BOARDLOADER_START 0
#define FLASH_SECTOR_BOARDLOADER_START 0
// 1
#define FLASH_SECTOR_BOARDLOADER_END 2
#define FLASH_SECTOR_BOARDLOADER_END 2
// 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
// 8
// 9
// 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
// 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
// 19
// 20
// 21
// 22
#define FLASH_SECTOR_FIRMWARE_EXTRA_END 23
#define FLASH_SECTOR_FIRMWARE_EXTRA_END 23
#define BOOTLOADER_SECTORS_COUNT (1)
#define STORAGE_SECTORS_COUNT (2)
#define FIRMWARE_SECTORS_COUNT (6 + 7)
#define BOOTLOADER_SECTORS_COUNT (1)
#define STORAGE_SECTORS_COUNT (2)
#define FIRMWARE_SECTORS_COUNT (6 + 7)
extern const uint8_t STORAGE_SECTORS[STORAGE_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
#define FLASH_SR_RDERR 0
#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);
@ -81,23 +84,28 @@ secbool __wur flash_lock_write(void);
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));
static inline secbool flash_erase(uint8_t sector) { return flash_erase_sectors(&sector, 1, NULL); }
secbool __wur flash_erase_sectors(const uint8_t *sectors, int len,
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_word(uint8_t sector, uint32_t offset, uint32_t data);
#define FLASH_OTP_NUM_BLOCKS 16
#define FLASH_OTP_BLOCK_SIZE 32
#define FLASH_OTP_NUM_BLOCKS 16
#define FLASH_OTP_BLOCK_SIZE 32
// OTP blocks allocation
#define FLASH_OTP_BLOCK_BATCH 0
#define FLASH_OTP_BLOCK_BOOTLOADER_VERSION 1
#define FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK 2
#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_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen);
#define FLASH_OTP_BLOCK_BATCH 0
#define FLASH_OTP_BLOCK_BOOTLOADER_VERSION 1
#define FLASH_OTP_BLOCK_VENDOR_KEYS_LOCK 2
#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_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_is_locked(uint8_t block);
#endif // TREZORHAL_FLASH_H
#endif // TREZORHAL_FLASH_H

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

@ -23,68 +23,76 @@
#include <stdint.h>
#include "secbool.h"
#define BOARDLOADER_START 0x08000000
#define BOOTLOADER_START 0x08020000
#define FIRMWARE_START 0x08040000
#define BOARDLOADER_START 0x08000000
#define BOOTLOADER_START 0x08020000
#define FIRMWARE_START 0x08040000
#define IMAGE_HEADER_SIZE 0x400
#define IMAGE_SIG_SIZE 65
#define IMAGE_CHUNK_SIZE (128 * 1024)
#define IMAGE_HEADER_SIZE 0x400
#define IMAGE_SIG_SIZE 65
#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 FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF
#define FIRMWARE_IMAGE_MAXSIZE (FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE)
#define FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF
#define FIRMWARE_IMAGE_MAXSIZE (FIRMWARE_SECTORS_COUNT * IMAGE_CHUNK_SIZE)
typedef struct {
uint32_t magic;
uint32_t hdrlen;
uint32_t expiry;
uint32_t codelen;
uint32_t version;
uint32_t fix_version;
// uint8_t reserved[8];
uint8_t hashes[512];
// uint8_t reserved[415];
uint8_t sigmask;
uint8_t sig[64];
uint8_t fingerprint[32];
uint32_t magic;
uint32_t hdrlen;
uint32_t expiry;
uint32_t codelen;
uint32_t version;
uint32_t fix_version;
// uint8_t reserved[8];
uint8_t hashes[512];
// uint8_t reserved[415];
uint8_t sigmask;
uint8_t sig[64];
uint8_t fingerprint[32];
} image_header;
#define MAX_VENDOR_PUBLIC_KEYS 8
#define VTRUST_WAIT 0x000F
#define VTRUST_RED 0x0010
#define VTRUST_CLICK 0x0020
#define VTRUST_STRING 0x0040
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
#define VTRUST_WAIT 0x000F
#define VTRUST_RED 0x0010
#define VTRUST_CLICK 0x0020
#define VTRUST_STRING 0x0040
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
typedef struct {
uint32_t magic;
uint32_t hdrlen;
uint32_t expiry;
uint16_t version;
uint8_t vsig_m;
uint8_t vsig_n;
uint16_t vtrust;
// uint8_t reserved[14];
const uint8_t *vpub[MAX_VENDOR_PUBLIC_KEYS];
uint8_t vstr_len;
const char *vstr;
const uint8_t *vimg;
uint8_t sigmask;
uint8_t sig[64];
uint32_t magic;
uint32_t hdrlen;
uint32_t expiry;
uint16_t version;
uint8_t vsig_m;
uint8_t vsig_n;
uint16_t vtrust;
// uint8_t reserved[14];
const uint8_t *vpub[MAX_VENDOR_PUBLIC_KEYS];
uint8_t vstr_len;
const char *vstr;
const uint8_t *vimg;
uint8_t sigmask;
uint8_t sig[64];
} 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

@ -19,151 +19,165 @@
#include STM32_HAL_H
#include "flash.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
#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_RDP_LEVEL (OB_RDP_LEVEL_2)
#define WANT_WRP_SECTORS (OB_WRP_SECTOR_0 | OB_WRP_SECTOR_1 | OB_WRP_SECTOR_2)
#else
#define WANT_RDP_LEVEL (OB_RDP_LEVEL_0)
#define WANT_WRP_SECTORS (0)
#define WANT_RDP_LEVEL (OB_RDP_LEVEL_0)
#define WANT_WRP_SECTORS (0)
#endif
// BOR LEVEL 3: Reset level threshold is around 2.5 V
#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;
#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.9.10; SPRMOD is 0 meaning PCROP disabled.; DB1M is
// 0 because we use 2MB dual-bank; BFB2 is 0 allowing boot from flash;
#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
#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_BANK1_WRP_VALUE ((uint16_t) ((~WANT_WRP_SECTORS) & 0xFFFU))
#define OPTION_BYTES_BANK2_WRP_VALUE ((uint16_t) 0xFFFU)
// reference RM0090 section 3.7.1 table 16. use 16 bit pointers because the top 48 bits are all reserved.
#define OPTION_BYTES_RDP_USER (*(volatile uint16_t * const) 0x1FFFC000U)
#define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t * const) 0x1FFFC008U)
#define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t * const) 0x1FFEC008U)
uint32_t flash_wait_and_clear_status_flags(void)
{
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;
#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_BANK1_WRP_VALUE ((uint16_t)((~WANT_WRP_SECTORS) & 0xFFFU))
#define OPTION_BYTES_BANK2_WRP_VALUE ((uint16_t)0xFFFU)
// reference RM0090 section 3.7.1 table 16. use 16 bit pointers because the top
// 48 bits are all reserved.
#define OPTION_BYTES_RDP_USER (*(volatile uint16_t* const)0x1FFFC000U)
#define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t* const)0x1FFFC008U)
#define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t* const)0x1FFEC008U)
uint32_t flash_wait_and_clear_status_flags(void) {
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)
{
flash_wait_and_clear_status_flags();
// check values stored in flash interface registers
if ((FLASH->OPTCR & ~3) != FLASH_OPTCR_VALUE) { // ignore bits 0 and 1 because they are control bits
return secfalse;
}
if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) {
return secfalse;
}
// check values stored in flash memory
if ((OPTION_BYTES_RDP_USER & ~3) != 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_BANK2_WRP & 0xFFFU) != OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused
return secfalse;
}
return sectrue;
secbool flash_check_option_bytes(void) {
flash_wait_and_clear_status_flags();
// check values stored in flash interface registers
if ((FLASH->OPTCR & ~3) !=
FLASH_OPTCR_VALUE) { // ignore bits 0 and 1 because they are control bits
return secfalse;
}
if (FLASH->OPTCR1 != FLASH_OPTCR1_nWRP) {
return secfalse;
}
// check values stored in flash memory
if ((OPTION_BYTES_RDP_USER & ~3) !=
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_BANK2_WRP & 0xFFFU) !=
OPTION_BYTES_BANK2_WRP_VALUE) { // bits 12, 13, 14, and 15 are unused
return secfalse;
}
return sectrue;
}
void flash_lock_option_bytes(void)
{
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; // lock the option bytes
void flash_lock_option_bytes(void) {
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; // lock the option bytes
}
void flash_unlock_option_bytes(void)
{
if ((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) == 0) {
return; // already unlocked
}
// reference RM0090 section 3.7.2
// write the special sequence to unlock
FLASH->OPTKEYR = FLASH_OPT_KEY1;
FLASH->OPTKEYR = FLASH_OPT_KEY2;
while (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK); // wait until the flash option control register is unlocked
void flash_unlock_option_bytes(void) {
if ((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) == 0) {
return; // already unlocked
}
// reference RM0090 section 3.7.2
// write the special sequence to unlock
FLASH->OPTKEYR = FLASH_OPT_KEY1;
FLASH->OPTKEYR = FLASH_OPT_KEY2;
while (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK)
; // wait until the flash option control register is unlocked
}
uint32_t flash_set_option_bytes(void)
{
// reference RM0090 section 3.7.2
flash_wait_and_clear_status_flags();
flash_unlock_option_bytes();
flash_wait_and_clear_status_flags();
FLASH->OPTCR1 = 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_OPTSTRT; // begin committing changes to flash
const uint32_t result = flash_wait_and_clear_status_flags(); // wait until changes are committed
flash_lock_option_bytes();
return result;
uint32_t flash_set_option_bytes(void) {
// reference RM0090 section 3.7.2
flash_wait_and_clear_status_flags();
flash_unlock_option_bytes();
flash_wait_and_clear_status_flags();
FLASH->OPTCR1 =
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_OPTSTRT; // begin committing changes to flash
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)
{
if (sectrue == flash_check_option_bytes()) {
return sectrue; // we DID NOT have to change the option bytes
}
secbool flash_configure_option_bytes(void) {
if (sectrue == flash_check_option_bytes()) {
return sectrue; // we DID NOT have to change the option bytes
}
do {
flash_set_option_bytes();
} while(sectrue != flash_check_option_bytes());
do {
flash_set_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)
{
// STM32F4xx HAL library initialization:
// - configure the Flash prefetch, instruction and data caches
// - configure the Systick to generate an interrupt each 1 msec
// - set NVIC Group Priority to 4
// - global MSP (MCU Support Package) initialization
HAL_Init();
// Enable GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
// enable the PVD (programmable voltage detector).
// select the "2.7V" threshold (level 5).
// this detector will be active regardless of the
// flash option byte BOR setting.
__HAL_RCC_PWR_CLK_ENABLE();
PWR_PVDTypeDef pvd_config;
pvd_config.PVDLevel = PWR_PVDLEVEL_5;
pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
HAL_PWR_ConfigPVD(&pvd_config);
HAL_PWR_EnablePVD();
NVIC_EnableIRQ(PVD_IRQn);
void periph_init(void) {
// STM32F4xx HAL library initialization:
// - configure the Flash prefetch, instruction and data caches
// - configure the Systick to generate an interrupt each 1 msec
// - set NVIC Group Priority to 4
// - global MSP (MCU Support Package) initialization
HAL_Init();
// Enable GPIO clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
// enable the PVD (programmable voltage detector).
// select the "2.7V" threshold (level 5).
// this detector will be active regardless of the
// flash option byte BOR setting.
__HAL_RCC_PWR_CLK_ENABLE();
PWR_PVDTypeDef pvd_config;
pvd_config.PVDLevel = PWR_PVDLEVEL_5;
pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
HAL_PWR_ConfigPVD(&pvd_config);
HAL_PWR_EnablePVD();
NVIC_EnableIRQ(PVD_IRQn);
}
secbool reset_flags_check(void)
{
secbool reset_flags_check(void) {
#if PRODUCTION
// this is effective enough that it makes development painful, so only use it for production.
// check the reset flags to assure that we arrive here due to 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)) {
return secfalse;
}
// this is effective enough that it makes development painful, so only use it
// for production. check the reset flags to assure that we arrive here due to
// 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)) {
return secfalse;
}
#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);
secbool reset_flags_check(void);
#endif // __TREZORHAL_LOWLEVEL_H__
#endif // __TREZORHAL_LOWLEVEL_H__

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

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

@ -21,126 +21,151 @@
#include "stm32f4xx_ll_cortex.h"
// 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_SRAM (MPU_RASR_C_Msk | MPU_RASR_S_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_PERIPH (MPU_RASR_B_Msk | MPU_RASR_S_Msk)
#define MPU_SUBREGION_DISABLE(X) ((X) << MPU_RASR_SRD_Pos)
void mpu_config_off(void)
{
// Disable MPU
HAL_MPU_Disable();
void mpu_config_off(void) {
// Disable MPU
HAL_MPU_Disable();
}
void mpu_config_bootloader(void)
{
// Disable MPU
HAL_MPU_Disable();
// Note: later entries overwrite previous ones
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = 0;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS;
// Flash (0x0800C000 - 0x0800FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER1;
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;
// Flash (0x0810C000 - 0x0810FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER2;
MPU->RBAR = FLASH_BASE + 0x10C000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS;
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER3;
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_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;
void mpu_config_bootloader(void) {
// Disable MPU
HAL_MPU_Disable();
// Note: later entries overwrite previous ones
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = 0;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS;
// Flash (0x0800C000 - 0x0800FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER1;
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;
// Flash (0x0810C000 - 0x0810FFFF, 16 KiB, no access)
MPU->RNR = MPU_REGION_NUMBER2;
MPU->RBAR = FLASH_BASE + 0x10C000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_NO_ACCESS;
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end,
// read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER3;
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_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
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER5;
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;
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER5;
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;
#elif STM32F405xx
// no CCMRAM
// no CCMRAM
#else
#error Unsupported MCU
#endif
// Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
// Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
}
void mpu_config_firmware(void)
{
// Disable MPU
HAL_MPU_Disable();
// Note: later entries overwrite previous ones
/*
// Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never)
MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0;
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)
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = FLASH_BASE + 0x20000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO;
// Storage#1 (0x08010000 - 0x0801FFFF, 64 KiB, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER1;
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;
// Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER2;
MPU->RBAR = FLASH_BASE + 0x110000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH | LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS | MPU_RASR_XN_Msk;
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at start = 768 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER3;
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(0x03);
// Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8 at start = 896 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER4;
MPU->RBAR = FLASH_BASE + 0x100000;
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);
// 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;
void mpu_config_firmware(void) {
// Disable MPU
HAL_MPU_Disable();
// Note: later entries overwrite previous ones
/*
// Boardloader (0x08000000 - 0x0800FFFF, 64 KiB, read-only, execute never)
MPU->RBAR = FLASH_BASE | MPU_REGION_NUMBER0;
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)
MPU->RNR = MPU_REGION_NUMBER0;
MPU->RBAR = FLASH_BASE + 0x20000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO;
// Storage#1 (0x08010000 - 0x0801FFFF, 64 KiB, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER1;
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;
// Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER2;
MPU->RBAR = FLASH_BASE + 0x110000;
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
MPU_RASR_XN_Msk;
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
// start = 768 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER3;
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(0x03);
// Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8
// at start = 896 KiB, read-only)
MPU->RNR = MPU_REGION_NUMBER4;
MPU->RBAR = FLASH_BASE + 0x100000;
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);
// 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
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER7;
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;
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
MPU->RNR = MPU_REGION_NUMBER7;
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;
#elif STM32F405xx
// no CCMRAM
// no CCMRAM
#else
#error Unsupported MCU
#endif
// Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
// Enable MPU
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
}

@ -21,36 +21,38 @@
#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)
{
// enable TRNG peripheral clock
// use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet
// "Delay after an RCC peripheral clock enabling"
__HAL_RCC_RNG_CLK_ENABLE();
RNG->CR = RNG_CR_RNGEN; // enable TRNG
void rng_init(void) {
// enable TRNG peripheral clock
// use the HAL version due to section 2.1.6 of STM32F42xx Errata sheet
// "Delay after an RCC peripheral clock enabling"
__HAL_RCC_RNG_CLK_ENABLE();
RNG->CR = RNG_CR_RNGEN; // enable TRNG
}
uint32_t rng_read(const uint32_t previous, const uint32_t compare_previous)
{
uint32_t temp = previous;
do {
while ((RNG->SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) != RNG_SR_DRDY); // wait until TRNG is ready
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
return temp;
uint32_t rng_read(const uint32_t previous, const uint32_t compare_previous) {
uint32_t temp = previous;
do {
while ((RNG->SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) != RNG_SR_DRDY)
; // wait until TRNG is ready
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
return temp;
}
uint32_t rng_get(void)
{
// reason for keeping history: RM0090 section 24.3.1 FIPS continuous random number generator test
static uint32_t previous = 0, current = 0;
if (previous == current) {
previous = rng_read(previous, 0);
} else {
previous = current;
}
current = rng_read(previous, 1);
return current;
uint32_t rng_get(void) {
// reason for keeping history: RM0090 section 24.3.1 FIPS continuous random
// number generator test
static uint32_t previous = 0, current = 0;
if (previous == current) {
previous = rng_read(previous, 0);
} else {
previous = current;
}
current = rng_read(previous, 1);
return current;
}

@ -22,20 +22,22 @@
#include "sbu.h"
void sbu_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// SBU1/PA2 SBU2/PA3
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// SBU1/PA2 SBU2/PA3
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
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_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
}
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_3, sbu2 == sectrue ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2,
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 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_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_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_12, GPIO_PIN_RESET); // SD_CLK/PC12
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // SD_CMD/PD2
GPIO_InitTypeDef GPIO_InitStructure;
// configure the SD card circuitry on/off pin
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
// configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
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;
HAL_GPIO_Init(GPIOC, &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;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_13;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
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_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_11, GPIO_PIN_RESET); // SD_DAT3/PC11
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
GPIO_InitTypeDef GPIO_InitStructure;
// configure the SD card circuitry on/off pin
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
// configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
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;
HAL_GPIO_Init(GPIOC, &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;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_13;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
}
static inline void sdcard_active_pin_state(void) {
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
GPIO_InitTypeDef GPIO_InitStructure;
// configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_SDIO;
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
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
GPIO_InitTypeDef GPIO_InitStructure;
// configure SD GPIO
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_SDIO;
GPIO_InitStructure.Pin =
GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void sdcard_init(void) {
sdcard_default_pin_state();
}
void sdcard_init(void) { sdcard_default_pin_state(); }
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
// enable SDIO clock
__HAL_RCC_SDIO_CLK_ENABLE();
// GPIO have already been initialised by sdcard_init
// enable SDIO clock
__HAL_RCC_SDIO_CLK_ENABLE();
// GPIO have already been initialised by sdcard_init
}
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
__HAL_RCC_SDIO_CLK_DISABLE();
}
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { __HAL_RCC_SDIO_CLK_DISABLE(); }
secbool sdcard_power_on(void) {
if (sectrue != sdcard_is_present()) {
return secfalse;
}
if (sd_handle.Instance) {
return sectrue;
if (sectrue != sdcard_is_present()) {
return secfalse;
}
if (sd_handle.Instance) {
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);
}
// 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;
}
HAL_Delay(50);
}
// configure the SD bus width for wide operation
if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
HAL_SD_DeInit(&sd_handle);
goto error;
}
// configure the SD bus width for wide operation
if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) {
HAL_SD_DeInit(&sd_handle);
goto error;
}
return sectrue;
return sectrue;
error:
sdcard_power_off();
return secfalse;
sdcard_power_off();
return secfalse;
}
void sdcard_power_off(void) {
if (sd_handle.Instance) {
HAL_SD_DeInit(&sd_handle);
sd_handle.Instance = NULL;
}
// turn off SD card circuitry
HAL_Delay(50);
sdcard_default_pin_state();
HAL_Delay(100);
if (sd_handle.Instance) {
HAL_SD_DeInit(&sd_handle);
sd_handle.Instance = NULL;
}
// turn off SD card circuitry
HAL_Delay(50);
sdcard_default_pin_state();
HAL_Delay(100);
}
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) {
if (sd_handle.Instance == NULL) {
return 0;
}
HAL_SD_CardInfoTypeDef cardinfo;
HAL_SD_GetCardInfo(&sd_handle, &cardinfo);
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
if (sd_handle.Instance == NULL) {
return 0;
}
HAL_SD_CardInfoTypeDef cardinfo;
HAL_SD_GetCardInfo(&sd_handle, &cardinfo);
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
}
static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) {
// Wait for HAL driver to be ready (eg for DMA to finish)
uint32_t start = HAL_GetTick();
while (sd->State == HAL_SD_STATE_BUSY) {
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd,
uint32_t timeout) {
// Wait for HAL driver to be ready (eg for DMA to finish)
uint32_t start = HAL_GetTick();
while (sd->State == HAL_SD_STATE_BUSY) {
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}
// Wait for SD card to complete the operation
for (;;) {
HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
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;
}
}
// Wait for SD card to complete the operation
for (;;) {
HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
if (state == HAL_SD_CARD_TRANSFER) {
return HAL_OK;
}
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) {
// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return secfalse;
}
secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
uint32_t num_blocks) {
// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return secfalse;
}
// check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) {
return secfalse;
}
// check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) {
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);
if (err == HAL_OK) {
err = sdcard_wait_finished(&sd_handle, 60000);
}
err = HAL_SD_ReadBlocks(&sd_handle, (uint8_t *)dest, block_num, num_blocks,
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) {
// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return secfalse;
}
secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
uint32_t num_blocks) {
// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return secfalse;
}
// check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) {
return secfalse;
}
// check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) {
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);
if (err == HAL_OK) {
err = sdcard_wait_finished(&sd_handle, 60000);
}
err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t *)src, block_num, num_blocks,
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);
secbool __wur sdcard_is_present(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_write_blocks(const uint32_t *src, uint32_t block_num, uint32_t num_blocks);
secbool __wur sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
uint32_t num_blocks);
secbool __wur sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
uint32_t num_blocks);
#endif

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

@ -21,7 +21,8 @@
#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};
#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;
#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)
{
// set flash wait states for an increasing HCLK frequency -- reference RM0090 section 3.5.1
FLASH->ACR = FLASH_ACR_LATENCY_5WS;
// wait until the new wait state config takes effect -- per section 3.5.1 guidance
while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS);
// configure main PLL; assumes HSE is 8 MHz; this should evaluate to 0x27402a04 -- reference RM0090 section 7.3.2
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
| RCC_PLLCFGR_PLLSRC_HSE // PLLSRC = HSE
| (0U << RCC_PLLCFGR_PLLP_Pos) // P = 2 (two bits, 00 means PLLP = 2)
| (CORE_CLOCK_MHZ << RCC_PLLCFGR_PLLN_Pos) // N = CORE_CLOCK_MHZ
| (4U << RCC_PLLCFGR_PLLM_Pos); // M = 4
// enable spread spectrum clock for main PLL
RCC->SSCGR = RCC_SSCGR_SSCGEN | (44 << RCC_SSCGR_INCSTEP_Pos) | (250 << RCC_SSCGR_MODPER_Pos);
// enable clock security system, HSE clock, and main PLL
RCC->CR |= RCC_CR_CSSON | RCC_CR_HSEON | RCC_CR_PLLON;
// wait until PLL and HSE ready
while((RCC->CR & (RCC_CR_PLLRDY | RCC_CR_HSERDY)) != (RCC_CR_PLLRDY | RCC_CR_HSERDY));
// APB2=2, APB1=4, AHB=1, system clock = main PLL
const uint32_t cfgr = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLL;
RCC->CFGR = cfgr;
// 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));
void SystemInit(void) {
// set flash wait states for an increasing HCLK frequency -- reference RM0090
// section 3.5.1
FLASH->ACR = FLASH_ACR_LATENCY_5WS;
// wait until the new wait state config takes effect -- per section 3.5.1
// guidance
while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS)
;
// configure main PLL; assumes HSE is 8 MHz; this should evaluate to
// 0x27402a04 -- reference RM0090 section 7.3.2
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
| RCC_PLLCFGR_PLLSRC_HSE // PLLSRC = HSE
| (0U << RCC_PLLCFGR_PLLP_Pos) // P = 2 (two bits, 00 means PLLP = 2)
| (CORE_CLOCK_MHZ << RCC_PLLCFGR_PLLN_Pos) // N = CORE_CLOCK_MHZ
| (4U << RCC_PLLCFGR_PLLM_Pos); // M = 4
// enable spread spectrum clock for main PLL
RCC->SSCGR = RCC_SSCGR_SSCGEN | (44 << RCC_SSCGR_INCSTEP_Pos) |
(250 << RCC_SSCGR_MODPER_Pos);
// enable clock security system, HSE clock, and main PLL
RCC->CR |= RCC_CR_CSSON | RCC_CR_HSEON | RCC_CR_PLLON;
// wait until PLL and HSE ready
while ((RCC->CR & (RCC_CR_PLLRDY | RCC_CR_HSERDY)) !=
(RCC_CR_PLLRDY | RCC_CR_HSERDY))
;
// APB2=2, APB1=4, AHB=1, system clock = main PLL
const uint32_t cfgr = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 |
RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLL;
RCC->CFGR = cfgr;
// 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;
void SysTick_Handler(void)
{
// this is a millisecond tick counter that wraps after approximately
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
uwTick++;
void SysTick_Handler(void) {
// this is a millisecond tick counter that wraps after approximately
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
uwTick++;
}
// from util.s
extern void shutdown(void);
void PVD_IRQHandler(void)
{
TIM1->CCR1 = 0; // turn off display backlight
shutdown();
void PVD_IRQHandler(void) {
TIM1->CCR1 = 0; // turn off display backlight
shutdown();
}

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

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

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

@ -22,9 +22,9 @@
#include <stdint.h>
#define TOUCH_START (1U << 24)
#define TOUCH_MOVE (1U << 25)
#define TOUCH_END (1U << 26)
#define TOUCH_START (1U << 24)
#define TOUCH_MOVE (1U << 25)
#define TOUCH_END (1U << 26)
void touch_init(void);
void touch_power_on(void);
@ -33,8 +33,14 @@ void touch_sensitivity(uint8_t value);
uint32_t touch_read(void);
uint32_t touch_click(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_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); }
static inline uint16_t touch_unpack_x(uint32_t evt) {
return (evt >> 12) & 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

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

@ -3,13 +3,14 @@
#include "common.h"
#include "secbool.h"
#define TOUCH_ADDRESS (0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit
#define TOUCH_PACKET_SIZE 7U
#define EVENT_PRESS_DOWN 0x00U
#define EVENT_CONTACT 0x80U
#define EVENT_LIFT_UP 0x40U
#define EVENT_NO_EVENT 0xC0U
#define GESTURE_NO_GESTURE 0x00U
#define TOUCH_ADDRESS \
(0x38U << 1) // the HAL requires the 7-bit address to be shifted by one bit
#define TOUCH_PACKET_SIZE 7U
#define EVENT_PRESS_DOWN 0x00U
#define EVENT_CONTACT 0x80U
#define EVENT_LIFT_UP 0x40U
#define EVENT_NO_EVENT 0xC0U
#define GESTURE_NO_GESTURE 0x00U
#define X_POS_MSB (touch_data[3] & 0x0FU)
#define X_POS_LSB (touch_data[4])
#define Y_POS_MSB (touch_data[5] & 0x0FU)
@ -18,180 +19,202 @@
static I2C_HandleTypeDef i2c_handle;
static void touch_default_pin_state(void) {
// 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_6, GPIO_PIN_RESET); // CTP_I2C_SCL/PB6
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // CTP_I2C_SDA/PB7
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(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET); // CTP_REST/PC5 (active low) i.e.- CTPM held in reset until released
// set above pins to OUTPUT / NOPULL
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_6 | GPIO_PIN_7;
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)
// 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_6, GPIO_PIN_RESET); // CTP_I2C_SCL/PB6
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // CTP_I2C_SDA/PB7
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(GPIOC, GPIO_PIN_5,
GPIO_PIN_RESET); // CTP_REST/PC5 (active low) i.e.- CTPM
// held in reset until released
// set above pins to OUTPUT / NOPULL
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_6 | GPIO_PIN_7;
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) {
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
GPIO_InitTypeDef GPIO_InitStructure;
// configure CTP I2C SCL and SDA GPIO lines (PB6 & PB7)
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
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.Alternate = GPIO_AF4_I2C1;
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
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
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
GPIO_InitTypeDef GPIO_InitStructure;
// configure CTP I2C SCL and SDA GPIO lines (PB6 & PB7)
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
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.Alternate = GPIO_AF4_I2C1;
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
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) {
touch_default_pin_state();
}
void touch_init(void) { touch_default_pin_state(); }
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) {
// enable I2C clock
__HAL_RCC_I2C1_CLK_ENABLE();
// GPIO have already been initialised by touch_init
// enable I2C clock
__HAL_RCC_I2C1_CLK_ENABLE();
// GPIO have already been initialised by touch_init
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) {
__HAL_RCC_I2C1_CLK_DISABLE();
__HAL_RCC_I2C1_CLK_DISABLE();
}
void touch_power_on(void) {
if (i2c_handle.Instance) {
return;
}
// turn on CTP circuitry
touch_active_pin_state();
HAL_Delay(50);
// I2C device interface configuration
i2c_handle.Instance = I2C1;
i2c_handle.Init.ClockSpeed = 400000;
i2c_handle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
i2c_handle.Init.OwnAddress1 = 0xFE; // master
i2c_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
i2c_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
i2c_handle.Init.OwnAddress2 = 0;
i2c_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_OK != HAL_I2C_Init(&i2c_handle)) {
ensure(secfalse, NULL);
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.
uint8_t touch_panel_config[] = {0xA4, 0x00};
ensure(sectrue * (HAL_OK == HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, touch_panel_config, sizeof(touch_panel_config), 10)), NULL);
touch_sensitivity(0x06);
if (i2c_handle.Instance) {
return;
}
// turn on CTP circuitry
touch_active_pin_state();
HAL_Delay(50);
// I2C device interface configuration
i2c_handle.Instance = I2C1;
i2c_handle.Init.ClockSpeed = 400000;
i2c_handle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
i2c_handle.Init.OwnAddress1 = 0xFE; // master
i2c_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
i2c_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
i2c_handle.Init.OwnAddress2 = 0;
i2c_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_OK != HAL_I2C_Init(&i2c_handle)) {
ensure(secfalse, NULL);
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.
uint8_t touch_panel_config[] = {0xA4, 0x00};
ensure(
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) {
if (i2c_handle.Instance) {
HAL_I2C_DeInit(&i2c_handle);
i2c_handle.Instance = NULL;
}
// turn off CTP circuitry
HAL_Delay(50);
touch_default_pin_state();
if (i2c_handle.Instance) {
HAL_I2C_DeInit(&i2c_handle);
i2c_handle.Instance = NULL;
}
// turn off CTP circuitry
HAL_Delay(50);
touch_default_pin_state();
}
void touch_sensitivity(uint8_t value) {
// set panel threshold (TH_GROUP) - default value is 0x12
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);
// set panel threshold (TH_GROUP) - default value is 0x12
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);
}
uint32_t touch_is_detected(void)
{
// check the interrupt line coming in from the CTPM.
// the line goes low when a touch event is actively detected.
// reference section 1.2 of "Application Note for FT6x06 CTPM".
// we configure the touch controller to use "interrupt polling mode".
return GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
uint32_t touch_is_detected(void) {
// check the interrupt line coming in from the CTPM.
// the line goes low when a touch event is actively detected.
// reference section 1.2 of "Application Note for FT6x06 CTPM".
// we configure the touch controller to use "interrupt polling mode".
return GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
}
uint32_t touch_read(void)
{
static uint8_t touch_data[TOUCH_PACKET_SIZE], previous_touch_data[TOUCH_PACKET_SIZE];
static uint32_t xy;
static int touching;
int last_packet = 0;
if (!touch_is_detected()) {
// only poll when the touch interrupt is active.
// 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.
if (touching) {
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
uint32_t touch_read(void) {
static uint8_t touch_data[TOUCH_PACKET_SIZE],
previous_touch_data[TOUCH_PACKET_SIZE];
static uint32_t xy;
static int touching;
int last_packet = 0;
if (!touch_is_detected()) {
// only poll when the touch interrupt is active.
// 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.
if (touching) {
last_packet = 1;
} 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)
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;
}
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 {
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) {
// interrupt line is inactive, we didn't read valid touch data, and as far as
// we know, we never sent a TOUCH_END event.
touching = 0;
return TOUCH_END | xy;
}
if (last_packet) {
// interrupt line is inactive, we didn't read valid touch data, and as far
// as we know, we never sent a TOUCH_END event.
touching = 0;
return TOUCH_END | xy;
}
return 0;
return 0;
}

@ -19,35 +19,41 @@
#include STM32_HAL_H
#include "common.h"
#include "usb.h"
#include "common.h"
#include "usbd_core.h"
#define USB_MAX_CONFIG_DESC_SIZE 256
#define USB_MAX_STR_SIZE 62
#define USB_MAX_STR_DESC_SIZE (USB_MAX_STR_SIZE * 2 + 2)
#define USB_MAX_CONFIG_DESC_SIZE 256
#define USB_MAX_STR_SIZE 62
#define USB_MAX_STR_DESC_SIZE (USB_MAX_STR_SIZE * 2 + 2)
#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)
#define USB_PHY_ID USB_PHY_HS_ID
#define USB_PHY_ID USB_PHY_HS_ID
#else
#error Unable to determine proper USB_PHY_ID to use
#endif
#define USB_WINUSB_VENDOR_CODE '!' // arbitrary, but must be equivalent to the last character in extra string
#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!
#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 USB_WINUSB_VENDOR_CODE \
'!' // arbitrary, but must be equivalent to the last character in extra
// string
#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!
#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))
static usb_device_descriptor_t usb_dev_desc;
// Config descriptor
static uint8_t usb_config_buf[USB_MAX_CONFIG_DESC_SIZE] __attribute__((aligned(4)));
static usb_config_descriptor_t *usb_config_desc = (usb_config_descriptor_t *)(usb_config_buf);
static uint8_t usb_config_buf[USB_MAX_CONFIG_DESC_SIZE]
__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;
// String descriptor
@ -64,114 +70,127 @@ static secbool usb21_enabled = secfalse;
static secbool usb21_landing = secfalse;
static secbool __wur check_desc_str(const char *s) {
if (NULL == s) return secfalse;
if (strlen(s) > USB_MAX_STR_SIZE) return secfalse;
return sectrue;
if (NULL == s) return secfalse;
if (strlen(s) > USB_MAX_STR_SIZE) return secfalse;
return sectrue;
}
void usb_init(const usb_dev_info_t *dev_info) {
// enable/disable USB 2.1 features
usb21_enabled = dev_info->usb21_enabled;
usb21_landing = dev_info->usb21_landing;
// Device descriptor
usb_dev_desc.bLength = sizeof(usb_device_descriptor_t);
usb_dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE;
usb_dev_desc.bcdUSB = (sectrue == usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0
usb_dev_desc.bDeviceClass = dev_info->device_class;
usb_dev_desc.bDeviceSubClass = dev_info->device_subclass;
usb_dev_desc.bDeviceProtocol = dev_info->device_protocol;
usb_dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE;
usb_dev_desc.idVendor = dev_info->vendor_id;
usb_dev_desc.idProduct = dev_info->product_id;
usb_dev_desc.bcdDevice = dev_info->release_num;
usb_dev_desc.iManufacturer = USBD_IDX_MFC_STR; // Index of manufacturer string
usb_dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string
usb_dev_desc.iSerialNumber = USBD_IDX_SERIAL_STR; // Index of serial number string
usb_dev_desc.bNumConfigurations = 1;
// String table
ensure(check_desc_str(dev_info->manufacturer), NULL);
ensure(check_desc_str(dev_info->product), NULL);
ensure(check_desc_str(dev_info->serial_number), NULL);
ensure(check_desc_str(dev_info->interface), NULL);
usb_str_table.manufacturer = dev_info->manufacturer;
usb_str_table.product = dev_info->product;
usb_str_table.serial_number = dev_info->serial_number;
usb_str_table.interface = dev_info->interface;
// Configuration descriptor
usb_config_desc->bLength = sizeof(usb_config_descriptor_t);
usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION;
usb_config_desc->wTotalLength = sizeof(usb_config_descriptor_t); // will be updated later via usb_desc_add_iface()
usb_config_desc->bNumInterfaces = 0; // will be updated later via usb_desc_add_iface()
usb_config_desc->bConfigurationValue = 0x01;
usb_config_desc->iConfiguration = 0;
usb_config_desc->bmAttributes = 0x80; // 0x80 = bus powered; 0xC0 = self powered
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);
// enable/disable USB 2.1 features
usb21_enabled = dev_info->usb21_enabled;
usb21_landing = dev_info->usb21_landing;
// Device descriptor
usb_dev_desc.bLength = sizeof(usb_device_descriptor_t);
usb_dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE;
usb_dev_desc.bcdUSB =
(sectrue == usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0
usb_dev_desc.bDeviceClass = dev_info->device_class;
usb_dev_desc.bDeviceSubClass = dev_info->device_subclass;
usb_dev_desc.bDeviceProtocol = dev_info->device_protocol;
usb_dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE;
usb_dev_desc.idVendor = dev_info->vendor_id;
usb_dev_desc.idProduct = dev_info->product_id;
usb_dev_desc.bcdDevice = dev_info->release_num;
usb_dev_desc.iManufacturer =
USBD_IDX_MFC_STR; // Index of manufacturer string
usb_dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string
usb_dev_desc.iSerialNumber =
USBD_IDX_SERIAL_STR; // Index of serial number string
usb_dev_desc.bNumConfigurations = 1;
// String table
ensure(check_desc_str(dev_info->manufacturer), NULL);
ensure(check_desc_str(dev_info->product), NULL);
ensure(check_desc_str(dev_info->serial_number), NULL);
ensure(check_desc_str(dev_info->interface), NULL);
usb_str_table.manufacturer = dev_info->manufacturer;
usb_str_table.product = dev_info->product;
usb_str_table.serial_number = dev_info->serial_number;
usb_str_table.interface = dev_info->interface;
// Configuration descriptor
usb_config_desc->bLength = sizeof(usb_config_descriptor_t);
usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION;
usb_config_desc->wTotalLength =
sizeof(usb_config_descriptor_t); // will be updated later via
// usb_desc_add_iface()
usb_config_desc->bNumInterfaces =
0; // will be updated later via usb_desc_add_iface()
usb_config_desc->bConfigurationValue = 0x01;
usb_config_desc->iConfiguration = 0;
usb_config_desc->bmAttributes =
0x80; // 0x80 = bus powered; 0xC0 = self powered
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) {
USBD_DeInit(&usb_dev_handle);
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
usb_ifaces[i].type = USB_IFACE_TYPE_DISABLED;
}
USBD_DeInit(&usb_dev_handle);
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
usb_ifaces[i].type = USB_IFACE_TYPE_DISABLED;
}
}
void usb_start(void) {
USBD_Start(&usb_dev_handle);
}
void usb_start(void) { USBD_Start(&usb_dev_handle); }
void usb_stop(void) {
USBD_Stop(&usb_dev_handle);
}
void usb_stop(void) { USBD_Stop(&usb_dev_handle); }
/*
* Utility functions for USB interfaces
*/
static usb_iface_t *usb_get_iface(uint8_t iface_num) {
if (iface_num < USBD_MAX_NUM_INTERFACES) {
return &usb_ifaces[iface_num];
} else {
return NULL; // Invalid interface number
}
if (iface_num < USBD_MAX_NUM_INTERFACES) {
return &usb_ifaces[iface_num];
} else {
return NULL; // Invalid interface number
}
}
static void *usb_desc_alloc_iface(size_t desc_len) {
if (usb_config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) {
return usb_next_iface_desc;
} else {
return NULL; // Not enough space in the descriptor
}
if (usb_config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) {
return usb_next_iface_desc;
} else {
return NULL; // Not enough space in the descriptor
}
}
static void usb_desc_add_iface(size_t desc_len) {
usb_config_desc->bNumInterfaces++;
usb_config_desc->wTotalLength += desc_len;
usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength);
usb_config_desc->bNumInterfaces++;
usb_config_desc->wTotalLength += desc_len;
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) {
PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
return USBD_OK;
PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
return USBD_OK;
}
static uint8_t usb_ep_clear_nak(USBD_HandleTypeDef *dev, uint8_t ep_num) {
PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
return USBD_OK;
PCD_HandleTypeDef *hpcd = dev->pData;
USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
USBx_OUTEP(ep_num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
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)
*/
static uint8_t *usb_get_dev_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
*length = sizeof(usb_dev_desc);
return (uint8_t *)(&usb_dev_desc);
static uint8_t *usb_get_dev_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
*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 const usb_langid_descriptor_t usb_langid_str_desc = {
.bLength = USB_LEN_LANGID_STR_DESC,
.bDescriptorType = USB_DESC_TYPE_STRING,
.wData = USB_LANGID_ENGLISH_US,
};
*length = sizeof(usb_langid_str_desc);
return UNCONST(&usb_langid_str_desc);
static uint8_t *usb_get_langid_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
static const usb_langid_descriptor_t usb_langid_str_desc = {
.bLength = USB_LEN_LANGID_STR_DESC,
.bDescriptorType = USB_DESC_TYPE_STRING,
.wData = USB_LANGID_ENGLISH_US,
};
*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) {
USBD_GetString((uint8_t *)usb_str_table.manufacturer, usb_str_buf, length);
return usb_str_buf;
static uint8_t *usb_get_manufacturer_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
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) {
USBD_GetString((uint8_t *)usb_str_table.product, usb_str_buf, length);
return usb_str_buf;
static uint8_t *usb_get_product_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
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) {
USBD_GetString((uint8_t *)usb_str_table.serial_number, usb_str_buf, length);
return usb_str_buf;
static uint8_t *usb_get_serial_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
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) {
USBD_GetString((uint8_t *)"", usb_str_buf, length);
return usb_str_buf;
static uint8_t *usb_get_configuration_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
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) {
USBD_GetString((uint8_t *)usb_str_table.interface, usb_str_buf, length);
return usb_str_buf;
static uint8_t *usb_get_interface_str_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
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) {
if (sectrue == usb21_enabled) {
static uint8_t bos[] = {
// usb_bos_descriptor {
0x05, // uint8_t bLength
USB_DESC_TYPE_BOS, // uint8_t bDescriptorType
0x1d, 0x0, // uint16_t wTotalLength
0x01, // uint8_t bNumDeviceCaps
// }
// usb_device_capability_descriptor {
0x18, // uint8_t bLength
USB_DESC_TYPE_DEVICE_CAPABILITY, // uint8_t bDescriptorType
USB_DEVICE_CAPABILITY_PLATFORM, // uint8_t bDevCapabilityType
0x00, // uint8_t bReserved
0x38, 0xb6, 0x08, 0x34, 0xa9, 0x09, 0xa0, 0x47, 0x8b, 0xfd, 0xa0, 0x76, 0x88, 0x15, 0xb6, 0x65, // uint128_t platformCompatibilityUUID
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);
} else {
*length = 0;
return NULL;
}
static uint8_t *usb_get_bos_descriptor(USBD_SpeedTypeDef speed,
uint16_t *length) {
if (sectrue == usb21_enabled) {
static uint8_t bos[] = {
// usb_bos_descriptor {
0x05, // uint8_t bLength
USB_DESC_TYPE_BOS, // uint8_t bDescriptorType
0x1d, 0x0, // uint16_t wTotalLength
0x01, // uint8_t bNumDeviceCaps
// }
// usb_device_capability_descriptor {
0x18, // uint8_t bLength
USB_DESC_TYPE_DEVICE_CAPABILITY, // uint8_t bDescriptorType
USB_DEVICE_CAPABILITY_PLATFORM, // uint8_t bDevCapabilityType
0x00, // uint8_t bReserved
0x38, 0xb6, 0x08, 0x34, 0xa9, 0x09, 0xa0, 0x47, 0x8b, 0xfd, 0xa0, 0x76,
0x88, 0x15, 0xb6, 0x65, // uint128_t platformCompatibilityUUID
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);
} else {
*length = 0;
return NULL;
}
}
static const USBD_DescriptorsTypeDef usb_descriptors = {
.GetDeviceDescriptor = usb_get_dev_descriptor,
.GetLangIDStrDescriptor = usb_get_langid_str_descriptor,
.GetManufacturerStrDescriptor = usb_get_manufacturer_str_descriptor,
.GetProductStrDescriptor = usb_get_product_str_descriptor,
.GetSerialStrDescriptor = usb_get_serial_str_descriptor,
.GetDeviceDescriptor = usb_get_dev_descriptor,
.GetLangIDStrDescriptor = usb_get_langid_str_descriptor,
.GetManufacturerStrDescriptor = usb_get_manufacturer_str_descriptor,
.GetProductStrDescriptor = usb_get_product_str_descriptor,
.GetSerialStrDescriptor = usb_get_serial_str_descriptor,
.GetConfigurationStrDescriptor = usb_get_configuration_str_descriptor,
.GetInterfaceStrDescriptor = usb_get_interface_str_descriptor,
.GetBOSDescriptor = usb_get_bos_descriptor,
.GetInterfaceStrDescriptor = usb_get_interface_str_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) {
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_init(dev, &usb_ifaces[i].hid, cfg_idx);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_init(dev, &usb_ifaces[i].vcp, cfg_idx);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_init(dev, &usb_ifaces[i].webusb, cfg_idx);
break;
default:
break;
}
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_init(dev, &usb_ifaces[i].hid, cfg_idx);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_init(dev, &usb_ifaces[i].vcp, cfg_idx);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_init(dev, &usb_ifaces[i].webusb, cfg_idx);
break;
default:
break;
}
return USBD_OK;
}
return USBD_OK;
}
static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) {
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_deinit(dev, &usb_ifaces[i].hid, cfg_idx);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_deinit(dev, &usb_ifaces[i].vcp, cfg_idx);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_deinit(dev, &usb_ifaces[i].webusb, cfg_idx);
break;
default:
break;
}
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_deinit(dev, &usb_ifaces[i].hid, cfg_idx);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_deinit(dev, &usb_ifaces[i].vcp, cfg_idx);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_deinit(dev, &usb_ifaces[i].webusb, cfg_idx);
break;
default:
break;
}
return USBD_OK;
}
return USBD_OK;
}
#define USB_WEBUSB_REQ_GET_URL 0x02
#define USB_WEBUSB_DESCRIPTOR_TYPE_URL 0x03
#define USB_WEBUSB_URL_SCHEME_HTTP 0
#define USB_WEBUSB_URL_SCHEME_HTTPS 1
static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_SetupReqTypedef *req) {
delay_random();
if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) &&
((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) &&
((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 (sectrue == usb21_enabled && req->bRequest == USB_WEBUSB_VENDOR_CODE) {
if (req->wIndex == USB_WEBUSB_REQ_GET_URL && req->wValue == USB_WEBUSB_LANDING_PAGE) {
static const char webusb_url[] = {
3 + 15, // uint8_t bLength
USB_WEBUSB_DESCRIPTOR_TYPE_URL, // uint8_t bDescriptorType
USB_WEBUSB_URL_SCHEME_HTTPS, // uint8_t bScheme
't', 'r', 'e', 'z', 'o', 'r', '.', 'i', 'o', '/', 's', 't', 'a', 'r', 't', // char URL[]
};
USBD_CtlSendData(dev, UNCONST(webusb_url), MIN_8bits(req->wLength, sizeof(webusb_url)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
}
}
else
if (sectrue == usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) {
if (req->wIndex == USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR) {
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;
}
}
}
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;
}
}
#define USB_WEBUSB_REQ_GET_URL 0x02
#define USB_WEBUSB_DESCRIPTOR_TYPE_URL 0x03
#define USB_WEBUSB_URL_SCHEME_HTTP 0
#define USB_WEBUSB_URL_SCHEME_HTTPS 1
static uint8_t usb_class_setup(USBD_HandleTypeDef *dev,
USBD_SetupReqTypedef *req) {
delay_random();
if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) &&
((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) &&
((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 (sectrue == usb21_enabled && req->bRequest == USB_WEBUSB_VENDOR_CODE) {
if (req->wIndex == USB_WEBUSB_REQ_GET_URL &&
req->wValue == USB_WEBUSB_LANDING_PAGE) {
static const char webusb_url[] = {
3 + 15, // uint8_t bLength
USB_WEBUSB_DESCRIPTOR_TYPE_URL, // uint8_t bDescriptorType
USB_WEBUSB_URL_SCHEME_HTTPS, // uint8_t bScheme
't',
'r',
'e',
'z',
'o',
'r',
'.',
'i',
'o',
'/',
's',
't',
'a',
'r',
't', // char URL[]
};
USBD_CtlSendData(dev, UNCONST(webusb_url),
MIN_8bits(req->wLength, sizeof(webusb_url)));
return USBD_OK;
} else {
USBD_CtlError(dev, req);
return USBD_FAIL;
}
} 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;
} else if (sectrue == usb21_enabled &&
req->bRequest == USB_WINUSB_VENDOR_CODE) {
if (req->wIndex ==
USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR) {
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);
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;
}
}
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;
}
}
}
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) {
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_data_in(dev, &usb_ifaces[i].hid, ep_num);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_in(dev, &usb_ifaces[i].vcp, ep_num);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_in(dev, &usb_ifaces[i].webusb, ep_num);
break;
default:
break;
}
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_data_in(dev, &usb_ifaces[i].hid, ep_num);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_in(dev, &usb_ifaces[i].vcp, ep_num);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_in(dev, &usb_ifaces[i].webusb, ep_num);
break;
default:
break;
}
return USBD_OK;
}
return USBD_OK;
}
static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) {
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_data_out(dev, &usb_ifaces[i].hid, ep_num);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_out(dev, &usb_ifaces[i].vcp, ep_num);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_out(dev, &usb_ifaces[i].webusb, ep_num);
break;
default:
break;
}
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_HID:
usb_hid_class_data_out(dev, &usb_ifaces[i].hid, ep_num);
break;
case USB_IFACE_TYPE_VCP:
usb_vcp_class_data_out(dev, &usb_ifaces[i].vcp, ep_num);
break;
case USB_IFACE_TYPE_WEBUSB:
usb_webusb_class_data_out(dev, &usb_ifaces[i].webusb, ep_num);
break;
default:
break;
}
return USBD_OK;
}
return USBD_OK;
}
static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) {
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_VCP:
usb_vcp_class_sof(dev, &usb_ifaces[i].vcp);
break;
default:
break;
}
delay_random();
for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) {
switch (usb_ifaces[i].type) {
case USB_IFACE_TYPE_VCP:
usb_vcp_class_sof(dev, &usb_ifaces[i].vcp);
break;
default:
break;
}
return USBD_OK;
}
return USBD_OK;
}
static uint8_t *usb_class_get_cfg_desc(uint16_t *length) {
*length = usb_config_desc->wTotalLength;
return usb_config_buf;
*length = usb_config_desc->wTotalLength;
return usb_config_buf;
}
static uint8_t *usb_class_get_usrstr_desc(USBD_HandleTypeDef *dev, uint8_t index, uint16_t *length) {
if (sectrue == usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) {
static const uint8_t winusb_string_descriptor[] = {
0x12, // bLength
USB_DESC_TYPE_STRING, // bDescriptorType
USB_WINUSB_EXTRA_STRING // wData
};
*length = sizeof(winusb_string_descriptor);
return UNCONST(winusb_string_descriptor);
} else {
*length = 0;
return NULL;
}
static uint8_t *usb_class_get_usrstr_desc(USBD_HandleTypeDef *dev,
uint8_t index, uint16_t *length) {
if (sectrue == usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) {
static const uint8_t winusb_string_descriptor[] = {
0x12, // bLength
USB_DESC_TYPE_STRING, // bDescriptorType
USB_WINUSB_EXTRA_STRING // wData
};
*length = sizeof(winusb_string_descriptor);
return UNCONST(winusb_string_descriptor);
} else {
*length = 0;
return NULL;
}
}
static const USBD_ClassTypeDef usb_class = {
.Init = usb_class_init,
.DeInit = usb_class_deinit,
.Setup = usb_class_setup,
.EP0_TxSent = NULL,
.EP0_RxReady = NULL,
.DataIn = usb_class_data_in,
.DataOut = usb_class_data_out,
.SOF = usb_class_sof,
.IsoINIncomplete = NULL,
.IsoOUTIncomplete = NULL,
.GetHSConfigDescriptor = usb_class_get_cfg_desc,
.GetFSConfigDescriptor = usb_class_get_cfg_desc,
.Init = usb_class_init,
.DeInit = usb_class_deinit,
.Setup = usb_class_setup,
.EP0_TxSent = NULL,
.EP0_RxReady = NULL,
.DataIn = usb_class_data_in,
.DataOut = usb_class_data_out,
.SOF = usb_class_sof,
.IsoINIncomplete = NULL,
.IsoOUTIncomplete = NULL,
.GetHSConfigDescriptor = usb_class_get_cfg_desc,
.GetFSConfigDescriptor = usb_class_get_cfg_desc,
.GetOtherSpeedConfigDescriptor = usb_class_get_cfg_desc,
.GetDeviceQualifierDescriptor = NULL,
.GetUsrStrDescriptor = usb_class_get_usrstr_desc,
.GetDeviceQualifierDescriptor = NULL,
.GetUsrStrDescriptor = usb_class_get_usrstr_desc,
};

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

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