From 91c3fde7bb0a7baac32422002d1687a50131cb53 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Tue, 14 Jan 2025 12:05:12 +0100 Subject: [PATCH] T2W1: add model --- common/defs/support.json | 118 ++ core/embed/io/nrf/stm32f4/nrf.c | 763 ++++++++++ core/embed/models/T2W1/boards/t2w1.h | 91 ++ .../T2W1/bootloaders/bootloader_T2W1.bin | Bin 0 -> 115200 bytes core/embed/models/T2W1/config.mk | 3 + core/embed/models/T2W1/memory.ld | 68 + core/embed/models/T2W1/model_T2W1.h | 128 ++ .../vendorheader/vendor_dev_DO_NOT_SIGN.json | 22 + .../vendorheader/vendor_dev_DO_NOT_SIGN.toif | 1 + .../T2W1/vendorheader/vendor_prodtest.json | 21 + .../T2W1/vendorheader/vendor_prodtest.toif | 1 + .../T2W1/vendorheader/vendor_satoshilabs.json | 22 + .../T2W1/vendorheader/vendor_satoshilabs.toif | Bin 0 -> 4222 bytes .../T2W1/vendorheader/vendor_unsafe.json | 22 + .../T2W1/vendorheader/vendor_unsafe.toif | Bin 0 -> 2162 bytes ...endorheader_dev_DO_NOT_SIGN_signed_dev.bin | Bin 0 -> 4608 bytes .../vendorheader_dev_DO_NOT_SIGN_unsigned.bin | Bin 0 -> 4608 bytes .../vendorheader_prodtest_unsigned.bin | Bin 0 -> 4608 bytes .../vendorheader_satoshilabs_unsigned.bin | Bin 0 -> 4608 bytes .../vendorheader_unsafe_signed_dev.bin | Bin 0 -> 4608 bytes .../vendorheader_unsafe_unsigned.bin | Bin 0 -> 4608 bytes core/embed/models/T2W1/versions.h | 3 + core/site_scons/models/T2W1/__init__.py | 27 + core/site_scons/models/T2W1/t2w1.py | 129 ++ core/src/apps/common/coininfo.py | 1337 +++++++++++++++++ core/src/apps/ethereum/networks.py | 55 + core/src/apps/ethereum/tokens.py | 148 ++ python/src/trezorlib/firmware/models.py | 35 + python/src/trezorlib/models.py | 11 +- 29 files changed, 3004 insertions(+), 1 deletion(-) create mode 100644 core/embed/io/nrf/stm32f4/nrf.c create mode 100644 core/embed/models/T2W1/boards/t2w1.h create mode 100644 core/embed/models/T2W1/bootloaders/bootloader_T2W1.bin create mode 100644 core/embed/models/T2W1/config.mk create mode 100644 core/embed/models/T2W1/memory.ld create mode 100644 core/embed/models/T2W1/model_T2W1.h create mode 100644 core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.json create mode 120000 core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.toif create mode 100644 core/embed/models/T2W1/vendorheader/vendor_prodtest.json create mode 120000 core/embed/models/T2W1/vendorheader/vendor_prodtest.toif create mode 100644 core/embed/models/T2W1/vendorheader/vendor_satoshilabs.json create mode 100644 core/embed/models/T2W1/vendorheader/vendor_satoshilabs.toif create mode 100644 core/embed/models/T2W1/vendorheader/vendor_unsafe.json create mode 100644 core/embed/models/T2W1/vendorheader/vendor_unsafe.toif create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_prodtest_unsigned.bin create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_satoshilabs_unsigned.bin create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_unsafe_signed_dev.bin create mode 100644 core/embed/models/T2W1/vendorheader/vendorheader_unsafe_unsigned.bin create mode 100644 core/embed/models/T2W1/versions.h create mode 100644 core/site_scons/models/T2W1/__init__.py create mode 100644 core/site_scons/models/T2W1/t2w1.py diff --git a/common/defs/support.json b/common/defs/support.json index 348122827c..f6f0aa5752 100644 --- a/common/defs/support.json +++ b/common/defs/support.json @@ -706,5 +706,123 @@ "nem:PAC:HRT": "not for T3W1 (#2793)", "nem:XEM": "not for T3W1 (#2793)" } + }, + "T2W1": { + "supported": { + "bitcoin:ACM": "2.6.1", + "bitcoin:AXE": "2.6.1", + "bitcoin:BCH": "2.6.1", + "bitcoin:BTC": "2.6.1", + "bitcoin:BTCP": "2.6.1", + "bitcoin:BTX": "2.6.1", + "bitcoin:CPU": "2.6.1", + "bitcoin:CRW": "2.6.1", + "bitcoin:DOGE": "2.6.1", + "bitcoin:ELEMENTS": "2.6.1", + "bitcoin:FIRO": "2.6.1", + "bitcoin:FJC": "2.6.1", + "bitcoin:FLO": "2.6.1", + "bitcoin:FTC": "2.6.1", + "bitcoin:GRS": "2.6.1", + "bitcoin:KMD": "2.6.1", + "bitcoin:KOTO": "2.6.1", + "bitcoin:LTC": "2.6.1", + "bitcoin:MONA": "2.6.1", + "bitcoin:PPC": "2.6.1", + "bitcoin:QTUM": "2.6.1", + "bitcoin:REGTEST": "2.6.1", + "bitcoin:RITO": "2.6.1", + "bitcoin:RVN": "2.6.1", + "bitcoin:SMART": "2.6.1", + "bitcoin:SYS": "2.6.1", + "bitcoin:TAZ": "2.6.1", + "bitcoin:TBCH": "2.6.1", + "bitcoin:TEST": "2.6.1", + "bitcoin:UNO": "2.6.1", + "bitcoin:VIA": "2.6.1", + "bitcoin:VIPS": "2.6.1", + "bitcoin:XEC": "2.8.6", + "bitcoin:XPM": "2.6.1", + "bitcoin:XRC": "2.6.1", + "bitcoin:XSN": "2.6.1", + "bitcoin:XVG": "2.6.1", + "bitcoin:ZCR": "2.6.1", + "bitcoin:ZEC": "2.6.1", + "bitcoin:tFIRO": "2.6.1", + "bitcoin:tGRS": "2.6.1", + "bitcoin:tLTC": "2.6.1", + "bitcoin:tPPC": "2.6.1", + "bitcoin:tQTUM": "2.6.1", + "bitcoin:tRVN": "2.6.1", + "bitcoin:tSMART": "2.6.1", + "erc20:bnb:ATOM": "2.6.1", + "erc20:eth:AAVE": "2.6.1", + "erc20:eth:APE": "2.6.1", + "erc20:eth:AXS": "2.6.1", + "erc20:eth:BUSD": "2.6.1", + "erc20:eth:CHZ": "2.6.1", + "erc20:eth:CRO": "2.6.1", + "erc20:eth:DAI": "2.6.1", + "erc20:eth:FRAX": "2.6.1", + "erc20:eth:LEO": "2.6.1", + "erc20:eth:LINK": "2.6.1", + "erc20:eth:MANA": "2.6.1", + "erc20:eth:MATIC": "2.6.1", + "erc20:eth:OKB": "2.6.1", + "erc20:eth:QNT": "2.6.1", + "erc20:eth:SAND": "2.6.1", + "erc20:eth:SHIB": "2.6.1", + "erc20:eth:STETH": "2.6.1", + "erc20:eth:UNI": "2.6.1", + "erc20:eth:USDC": "2.6.1", + "erc20:eth:USDT": "2.6.1", + "erc20:eth:WBTC": "2.6.1", + "erc20:eth:XCN": "2.6.1", + "erc20:matic:WAVAX": "2.6.1", + "eth:ARB:42161": "2.6.1", + "eth:BASE:8453": "2.6.1", + "eth:BSC:56": "2.6.1", + "eth:ETC:61": "2.6.1", + "eth:ETH:1": "2.6.1", + "eth:OP:10": "2.6.1", + "eth:POL:137": "2.6.1", + "eth:tHOL:17000": "2.6.1", + "eth:tSEP:11155111": "2.6.1", + "misc:ADA": "2.6.1", + "misc:BNB": "2.6.1", + "misc:DSOL": "2.6.4", + "misc:MAID": "2.6.1", + "misc:OMNI": "2.6.1", + "misc:SOL": "2.6.4", + "misc:USDT": "2.6.1", + "misc:XLM": "2.6.1", + "misc:XMR": "2.6.1", + "misc:XRP": "2.6.1", + "misc:XTZ": "2.6.1", + "misc:tADA": "2.6.1", + "misc:tXRP": "2.6.1" + }, + "unsupported": { + "bitcoin:BTG": "not for T3W1 (#2793)", + "bitcoin:DASH": "not for T3W1 (#2793)", + "bitcoin:DCR": "not for T3W1 (#2793)", + "bitcoin:DGB": "not for T3W1 (#2793)", + "bitcoin:NMC": "not for T3W1 (#2793)", + "bitcoin:PART": "incompatible fork", + "bitcoin:TBTG": "not for T3W1 (#2793)", + "bitcoin:TDCR": "not for T3W1 (#2793)", + "bitcoin:TRC": "address_type collides with Bitcoin", + "bitcoin:VTC": "not for T3W1 (#2793)", + "bitcoin:tDASH": "not for T3W1 (#2793)", + "bitcoin:tPART": "incompatible fork", + "misc:EOS": "not for T3W1 (#2793)", + "misc:LSK": "Incompatible mainnet hard-fork", + "nem:BREEZE": "not for T3W1 (#2793)", + "nem:DIM": "not for T3W1 (#2793)", + "nem:DIMTOK": "not for T3W1 (#2793)", + "nem:PAC:CHS": "not for T3W1 (#2793)", + "nem:PAC:HRT": "not for T3W1 (#2793)", + "nem:XEM": "not for T3W1 (#2793)" + } } } diff --git a/core/embed/io/nrf/stm32f4/nrf.c b/core/embed/io/nrf/stm32f4/nrf.c new file mode 100644 index 0000000000..b642fcd956 --- /dev/null +++ b/core/embed/io/nrf/stm32f4/nrf.c @@ -0,0 +1,763 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef KERNEL_MODE + +#include +#include + +#include +#include +#include +#include +#include + +#include "../crc8.h" +#include "../nrf_internal.h" + +#define MAX_SPI_DATA_SIZE (244) + +typedef struct { + uint8_t service_id; + uint8_t data[MAX_SPI_DATA_SIZE]; + uint8_t crc; +} spi_packet_t; + +typedef struct { + uint8_t service_id; + uint8_t msg_len; + uint8_t data[NRF_MAX_TX_DATA_SIZE + 1]; + // uint8_t crc; part of data, as it has variable position +} uart_packet_t; + +#define UART_OVERHEAD_SIZE (sizeof(uart_packet_t) - NRF_MAX_TX_DATA_SIZE) +#define UART_HEADER_SIZE (UART_OVERHEAD_SIZE - 1) + +#define TX_QUEUE_SIZE (8) + +#define START_BYTE (0xA0) + +typedef struct { + uart_packet_t packet; + nrf_tx_callback_t callback; + void *context; +} nrf_tx_request_t; + +typedef struct { + UART_HandleTypeDef urt; + DMA_HandleTypeDef urt_tx_dma; + + uint8_t tx_buffers[TX_QUEUE_SIZE][sizeof(nrf_tx_request_t)]; + tsqueue_entry_t tx_queue_entries[TX_QUEUE_SIZE]; + tsqueue_t tx_queue; + nrf_tx_request_t tx_request; + int32_t tx_request_id; + + uart_packet_t rx_buffer; + uint8_t rx_len; + uint8_t rx_byte; + uint16_t rx_idx; + + SPI_HandleTypeDef spi; + DMA_HandleTypeDef spi_dma; + spi_packet_t long_rx_buffer; + + bool comm_running; + bool initialized; + + nrf_rx_callback_t service_listeners[NRF_SERVICE_CNT]; + +} nrf_driver_t; + +__attribute__((section(".buf"))) static nrf_driver_t g_nrf_driver = {0}; + +static void nrf_start(void) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return; + } + + HAL_SPI_Receive_DMA(&drv->spi, (uint8_t *)&drv->long_rx_buffer, + sizeof(spi_packet_t)); + + tsqueue_reset(&drv->tx_queue); + HAL_UART_Receive_IT(&drv->urt, &drv->rx_byte, 1); + + drv->comm_running = true; + + nrf_signal_running(); +} + +static void nrf_abort_urt_comm(nrf_driver_t *drv) { + HAL_UART_AbortReceive(&drv->urt); + HAL_UART_AbortTransmit(&drv->urt); + + if (drv->tx_request.callback != NULL) { + drv->tx_request.callback(NRF_STATUS_ERROR, drv->tx_request.context); + } + + drv->rx_idx = 0; + drv->rx_len = 0; + drv->tx_request_id = -1; + + while (tsqueue_dequeue(&drv->tx_queue, (uint8_t *)&drv->tx_request, + sizeof(nrf_tx_request_t), NULL, NULL)) { + if (drv->tx_request.callback != NULL) { + drv->tx_request.callback(NRF_STATUS_ERROR, drv->tx_request.context); + } + } + + memset(&drv->tx_request, 0, sizeof(nrf_tx_request_t)); + + tsqueue_reset(&drv->tx_queue); +} + +static void nrf_stop(void) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return; + } + + nrf_signal_off(); + irq_key_t key = irq_lock(); + drv->comm_running = false; + HAL_SPI_DMAStop(&drv->spi); + nrf_abort_urt_comm(drv); + irq_unlock(key); +} + +void nrf_init(void) { + nrf_driver_t *drv = &g_nrf_driver; + + if (drv->initialized) { + return; + } + + __HAL_RCC_USART1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + __HAL_RCC_SPI2_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + memset(drv, 0, sizeof(*drv)); + tsqueue_init(&drv->tx_queue, drv->tx_queue_entries, + (uint8_t *)drv->tx_buffers, sizeof(nrf_tx_request_t), + TX_QUEUE_SIZE); + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // synchronization signals + NRF_OUT_RESET_CLK_ENA(); + HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_SET); + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = NRF_OUT_RESET_PIN; + HAL_GPIO_Init(NRF_OUT_RESET_PORT, &GPIO_InitStructure); + + NRF_IN_GPIO0_CLK_ENA(); + GPIO_InitStructure.Mode = GPIO_MODE_INPUT; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = NRF_IN_GPIO0_PIN; + HAL_GPIO_Init(NRF_IN_GPIO0_PORT, &GPIO_InitStructure); + + NRF_IN_FW_RUNNING_CLK_ENA(); + GPIO_InitStructure.Mode = GPIO_MODE_INPUT; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = NRF_IN_FW_RUNNING_PIN; + HAL_GPIO_Init(NRF_IN_FW_RUNNING_PORT, &GPIO_InitStructure); + + NRF_OUT_STAY_IN_BLD_CLK_ENA(); + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = NRF_OUT_STAY_IN_BLD_PIN; + HAL_GPIO_Init(NRF_OUT_STAY_IN_BLD_PORT, &GPIO_InitStructure); + + NRF_OUT_FW_RUNNING_CLK_ENA(); + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = NRF_OUT_FW_RUNNING_PIN; + HAL_GPIO_Init(NRF_OUT_FW_RUNNING_PORT, &GPIO_InitStructure); + + // UART PINS + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF7_USART1; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Pin = GPIO_PIN_9; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_12; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + + drv->urt.Init.Mode = UART_MODE_TX_RX; + drv->urt.Init.BaudRate = 1000000; + drv->urt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; + drv->urt.Init.OverSampling = UART_OVERSAMPLING_16; + drv->urt.Init.Parity = UART_PARITY_NONE; + drv->urt.Init.StopBits = UART_STOPBITS_1; + drv->urt.Init.WordLength = UART_WORDLENGTH_8B; + drv->urt.Instance = USART1; + drv->urt.hdmatx = &drv->urt_tx_dma; + + drv->urt_tx_dma.Instance = DMA2_Stream7; + drv->urt_tx_dma.State = HAL_DMA_STATE_RESET; + drv->urt_tx_dma.Init.Channel = DMA_CHANNEL_4; + drv->urt_tx_dma.Init.Direction = DMA_MEMORY_TO_PERIPH; + drv->urt_tx_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + drv->urt_tx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; + drv->urt_tx_dma.Init.MemBurst = DMA_MBURST_SINGLE; + drv->urt_tx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + drv->urt_tx_dma.Init.MemInc = DMA_MINC_ENABLE; + drv->urt_tx_dma.Init.Mode = DMA_NORMAL; + drv->urt_tx_dma.Init.PeriphBurst = DMA_PBURST_SINGLE; + drv->urt_tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + drv->urt_tx_dma.Init.PeriphInc = DMA_PINC_DISABLE; + drv->urt_tx_dma.Init.Priority = DMA_PRIORITY_HIGH; + + drv->urt_tx_dma.Parent = &drv->urt; + HAL_DMA_Init(&drv->urt_tx_dma); + + HAL_UART_Init(&drv->urt); + + NVIC_SetPriority(DMA2_Stream7_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(DMA2_Stream7_IRQn); + NVIC_SetPriority(USART1_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(USART1_IRQn); + + // SPI pins + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF5_SPI2; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM; + GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_3; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_9; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + + drv->spi_dma.Instance = DMA1_Stream3; + drv->spi_dma.State = HAL_DMA_STATE_RESET; + drv->spi_dma.Init.Channel = DMA_CHANNEL_0; + drv->spi_dma.Init.Direction = DMA_PERIPH_TO_MEMORY; + drv->spi_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + drv->spi_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; + drv->spi_dma.Init.MemBurst = DMA_MBURST_SINGLE; + drv->spi_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + drv->spi_dma.Init.MemInc = DMA_MINC_ENABLE; + drv->spi_dma.Init.Mode = DMA_NORMAL; + drv->spi_dma.Init.PeriphBurst = DMA_PBURST_SINGLE; + drv->spi_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + drv->spi_dma.Init.PeriphInc = DMA_PINC_DISABLE; + drv->spi_dma.Init.Priority = DMA_PRIORITY_HIGH; + + HAL_DMA_Init(&drv->spi_dma); + + drv->spi.Instance = SPI2; + drv->spi.Init.Mode = SPI_MODE_SLAVE; + drv->spi.Init.Direction = SPI_DIRECTION_2LINES_RXONLY; + drv->spi.Init.DataSize = SPI_DATASIZE_8BIT; + drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW; + drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE; + drv->spi.Init.NSS = SPI_NSS_HARD_INPUT; + drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB; + drv->spi.Init.TIMode = SPI_TIMODE_DISABLE; + drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + drv->spi.Init.CRCPolynomial = 0; + drv->spi.hdmarx = &drv->spi_dma; + + drv->spi_dma.Parent = &drv->spi; + + HAL_SPI_Init(&drv->spi); + + NVIC_SetPriority(DMA1_Stream3_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(DMA1_Stream3_IRQn); + NVIC_SetPriority(SPI2_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(SPI2_IRQn); + + drv->tx_request_id = -1; + drv->initialized = true; + + nrf_start(); +} + +void nrf_deinit(void) { + nrf_driver_t *drv = &g_nrf_driver; + + nrf_stop(); + + NVIC_DisableIRQ(DMA1_Stream3_IRQn); + NVIC_DisableIRQ(DMA2_Stream7_IRQn); + NVIC_DisableIRQ(SPI2_IRQn); + + __HAL_RCC_SPI2_FORCE_RESET(); + __HAL_RCC_SPI2_RELEASE_RESET(); + + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + + drv->initialized = false; +} + +bool nrf_register_listener(nrf_service_id_t service, + nrf_rx_callback_t callback) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return false; + } + + if (service >= NRF_SERVICE_CNT) { + return false; + } + + if (drv->service_listeners[service] != NULL) { + return false; + } + + irq_key_t key = irq_lock(); + drv->service_listeners[service] = callback; + irq_unlock(key); + + return true; +} + +void nrf_unregister_listener(nrf_service_id_t service) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return; + } + + if (service >= NRF_SERVICE_CNT) { + return; + } + + irq_key_t key = irq_lock(); + drv->service_listeners[service] = NULL; + irq_unlock(key); +} + +static void nrf_process_msg(nrf_driver_t *drv, const uint8_t *data, + uint32_t len, nrf_service_id_t service) { + if (drv->service_listeners[service] != NULL) { + drv->service_listeners[service](data, len); + } +} + +/// DFU communication +/// ---------------------------------------------------------- + +void nrf_dfu_comm_send(const uint8_t *data, uint32_t len) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return; + } + + HAL_UART_Transmit(&drv->urt, (uint8_t *)data, len, 30); +} + +uint32_t nrf_dfu_comm_receive(uint8_t *data, uint32_t len) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return 0; + } + + if (__HAL_UART_GET_FLAG(&drv->urt, UART_FLAG_RXNE)) { + HAL_StatusTypeDef result = HAL_UART_Receive(&drv->urt, data, len, 30); + + if (result == HAL_OK) { + return len; + } + + if (drv->urt.RxXferCount == len) { + return 0; + } + + return len - drv->urt.RxXferCount - 1; + } + + return 0; +} + +/// UART communication +/// --------------------------------------------------------- + +int32_t nrf_send_msg(nrf_service_id_t service, const uint8_t *data, + uint32_t len, nrf_tx_callback_t callback, void *context) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return -1; + } + + if (len > NRF_MAX_TX_DATA_SIZE) { + return -1; + } + + if (service > NRF_SERVICE_CNT) { + return -1; + } + + if (!nrf_is_running()) { + return -1; + } + + int32_t id = 0; + + nrf_tx_request_t tx_request = {0}; + + tx_request.callback = callback; + tx_request.context = context; + tx_request.packet.service_id = 0xA0 | (uint8_t)service; + tx_request.packet.msg_len = len + UART_OVERHEAD_SIZE; + memcpy(&tx_request.packet.data, data, len); + tx_request.packet.data[len] = + crc8((uint8_t *)&tx_request.packet, len + UART_OVERHEAD_SIZE - 1, 0x07, + 0x00, false); + + if (!tsqueue_enqueue(&drv->tx_queue, (uint8_t *)&tx_request, + sizeof(nrf_tx_request_t), &id)) { + return -1; + } + + irq_key_t key = irq_lock(); + if (drv->tx_request_id <= 0) { + int32_t tx_id = 0; + if (tsqueue_dequeue(&drv->tx_queue, (uint8_t *)&drv->tx_request, + sizeof(nrf_tx_request_t), NULL, &tx_id)) { + HAL_UART_Transmit_DMA(&drv->urt, (uint8_t *)&drv->tx_request.packet, + drv->tx_request.packet.msg_len); + drv->tx_request_id = tx_id; + } + } + irq_unlock(key); + + return id; +} + +bool nrf_abort_msg(int32_t id) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return false; + } + + bool aborted = tsqueue_abort(&drv->tx_queue, id, NULL, 0, NULL); + + if (aborted) { + return true; + } + + irq_key_t key = irq_lock(); + if (drv->tx_request_id == id) { + drv->tx_request_id = -1; + irq_unlock(key); + return true; + } + + irq_unlock(key); + return false; +} + +static bool nrf_is_valid_startbyte(uint8_t val) { + if ((val & 0xF0) != 0xA0) { + return false; + } + + if ((val & 0x0F) >= NRF_SERVICE_CNT) { + return false; + } + + return true; +} + +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *urt) { + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized && urt == &drv->urt) { + if (drv->rx_idx == 0) { + // received first byte: START BYTE + if (nrf_is_valid_startbyte(drv->rx_byte)) { + drv->rx_buffer.service_id = drv->rx_byte; + drv->rx_idx++; + } else { + // bad message, flush the line + drv->rx_idx = 0; + } + } else if (drv->rx_idx == 1) { + // received second byte: LEN + + drv->rx_buffer.msg_len = drv->rx_byte; + drv->rx_len = drv->rx_byte; + + if (drv->rx_len > sizeof(uart_packet_t)) { + drv->rx_len = 0; + drv->rx_idx = 0; + } else { + drv->rx_idx++; + } + } else if (drv->rx_idx >= UART_HEADER_SIZE && + drv->rx_idx < (drv->rx_len - 1)) { + // receive the rest of the message + + drv->rx_buffer.data[drv->rx_idx - UART_HEADER_SIZE] = drv->rx_byte; + drv->rx_idx++; + + if (drv->rx_idx >= NRF_MAX_TX_DATA_SIZE) { + // message is too long, flush the line + drv->rx_idx = 0; + drv->rx_len = 0; + } + + } else if (drv->rx_idx == (drv->rx_len - 1)) { + // received last byte: CRC + + uint8_t crc = + crc8((uint8_t *)&drv->rx_buffer, drv->rx_len - 1, 0x07, 0x00, false); + + if (drv->rx_byte == crc) { + uart_packet_t *packet = &drv->rx_buffer; + nrf_process_msg(drv, drv->rx_buffer.data, + drv->rx_len - UART_OVERHEAD_SIZE, + packet->service_id & 0x0F); + } + + drv->rx_idx = 0; + drv->rx_len = 0; + + } else { + // bad message, flush the line + drv->rx_idx = 0; + drv->rx_len = 0; + } + } + + // receive the rest of the message, or new message in any case. + HAL_UART_Receive_IT(&drv->urt, &drv->rx_byte, 1); +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *urt) { + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized && urt == &drv->urt) { + nrf_abort_urt_comm(drv); + + HAL_UART_Receive_IT(&drv->urt, &drv->rx_byte, 1); + } +} + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *urt) { + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized && urt == &drv->urt) { + if (drv->tx_request.callback != NULL) { + drv->tx_request.callback(NRF_STATUS_OK, drv->tx_request.context); + } + drv->tx_request_id = -1; + memset(&drv->tx_request, 0, sizeof(nrf_tx_request_t)); + + bool msg = + tsqueue_dequeue(&drv->tx_queue, (uint8_t *)&drv->tx_request, + sizeof(nrf_tx_request_t), NULL, &drv->tx_request_id); + if (msg) { + HAL_UART_Transmit_DMA(&drv->urt, (uint8_t *)&drv->tx_request.packet, + drv->tx_request.packet.msg_len); + } + } +} + +void USART1_IRQHandler(void) { + IRQ_LOG_ENTER(); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized) { + HAL_UART_IRQHandler(&drv->urt); + } + + mpu_restore(mpu_mode); + + IRQ_LOG_EXIT(); +} + +void DMA2_Stream7_IRQHandler(void) { + IRQ_LOG_ENTER(); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized) { + HAL_DMA_IRQHandler(&drv->urt_tx_dma); + } + + mpu_restore(mpu_mode); + + IRQ_LOG_EXIT(); +} + +/// SPI communication +/// ---------------------------------------------------------- + +void DMA1_Stream3_IRQHandler(void) { + IRQ_LOG_ENTER(); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized) { + HAL_DMA_IRQHandler(&drv->spi_dma); + } + + mpu_restore(mpu_mode); + + IRQ_LOG_EXIT(); +} + +void SPI2_IRQHandler(void) { + IRQ_LOG_ENTER(); + + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + nrf_driver_t *drv = &g_nrf_driver; + if (drv->initialized) { + HAL_SPI_IRQHandler(&drv->spi); + } + + mpu_restore(mpu_mode); + + IRQ_LOG_EXIT(); +} + +void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { + nrf_driver_t *drv = &g_nrf_driver; + + if (!drv->initialized) { + return; + } + + if (hspi != &drv->spi) { + return; + } + + spi_packet_t *packet = &drv->long_rx_buffer; + + uint8_t crc = crc8((uint8_t *)&drv->long_rx_buffer, sizeof(spi_packet_t) - 1, + 0x07, 0x00, false); + + if ((packet->service_id & 0xF0) != START_BYTE || packet->crc != crc) { + HAL_SPI_Abort(&drv->spi); + HAL_SPI_Receive_DMA(&drv->spi, (uint8_t *)&drv->long_rx_buffer, + sizeof(spi_packet_t)); + return; + } + + nrf_process_msg(drv, drv->long_rx_buffer.data, sizeof(packet->data), + packet->service_id & 0x0F); + + HAL_SPI_Receive_DMA(&drv->spi, (uint8_t *)&drv->long_rx_buffer, + sizeof(spi_packet_t)); +} + +/// GPIO communication +/// --------------------------------------------------------- + +bool nrf_reboot_to_bootloader(void) { + HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_RESET); + + HAL_GPIO_WritePin(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN, + GPIO_PIN_SET); + + systick_delay_ms(50); + + HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_SET); + + systick_delay_ms(1000); + + return true; +} + +bool nrf_reboot(void) { + HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_SET); + HAL_GPIO_WritePin(NRF_OUT_STAY_IN_BLD_PORT, NRF_OUT_STAY_IN_BLD_PIN, + GPIO_PIN_RESET); + systick_delay_ms(50); + HAL_GPIO_WritePin(NRF_OUT_RESET_PORT, NRF_OUT_RESET_PIN, GPIO_PIN_RESET); + return true; +} + +void nrf_signal_running(void) { + HAL_GPIO_WritePin(NRF_OUT_FW_RUNNING_PORT, NRF_OUT_FW_RUNNING_PIN, + GPIO_PIN_SET); +} + +void nrf_signal_off(void) { + HAL_GPIO_WritePin(NRF_OUT_FW_RUNNING_PORT, NRF_OUT_FW_RUNNING_PIN, + GPIO_PIN_RESET); +} + +bool nrf_firmware_running(void) { + return HAL_GPIO_ReadPin(NRF_IN_FW_RUNNING_PORT, NRF_IN_FW_RUNNING_PIN) != 0; +} + +bool nrf_is_running(void) { + nrf_driver_t *drv = &g_nrf_driver; + if (!drv->initialized) { + return false; + } + + if (!nrf_firmware_running()) { + return false; + } + + return drv->comm_running; +} + +void nrf_set_dfu_mode(void) { + nrf_driver_t *drv = &g_nrf_driver; + + if (!drv->initialized) { + return; + } + + // TODO + // if (nrf_reboot_to_bootloader()) { + // drv->mode_current = BLE_MODE_DFU; + // } else { + // drv->status_valid = false; + // } +} + +bool nrf_is_dfu_mode(void) { + nrf_driver_t *drv = &g_nrf_driver; + + if (!drv->initialized) { + return false; + } + + return true; + // TODO +} + +#endif diff --git a/core/embed/models/T2W1/boards/t2w1.h b/core/embed/models/T2W1/boards/t2w1.h new file mode 100644 index 0000000000..d178d61a42 --- /dev/null +++ b/core/embed/models/T2W1/boards/t2w1.h @@ -0,0 +1,91 @@ +#ifndef _TREZOR_T2W1_H +#define _TREZOR_T2W1_H + +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 + +#define DISPLAY_I8080_16BIT_DW 1 +#define DISPLAY_PANEL_LHS200KB_IF21 1 + +#define TPS61043_FREQ 50000 +#define TPS61043_TIM TIM1 +#define TPS61043_TIM_CLK_EN __HAL_RCC_TIM1_CLK_ENABLE +#define TPS61043_TIM_CLK_DIS __HAL_RCC_TIM1_CLK_DISABLE +#define TPS61043_TIM_FORCE_RESET __HAL_RCC_TIM1_FORCE_RESET +#define TPS61043_TIM_RELEASE_RESET __HAL_RCC_TIM1_RELEASE_RESET +#define TPS61043_TIM_AF GPIO_AF1_TIM1 +#define TPS61043_TIM_OCMODE TIM_OCMODE_PWM2 +#define TPS61043_TIM_CHANNEL TIM_CHANNEL_1 +#define TPS61043_TIM_CCR CCR1 +#define TPS61043_PIN GPIO_PIN_7 +#define TPS61043_PORT GPIOA +#define TPS61043_PORT_CLK_EN __HAL_RCC_GPIOA_CLK_ENABLE + +#define I2C_COUNT 1 +#define I2C_INSTANCE_0 I2C2 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C2_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C2 +#define I2C_INSTANCE_0_SDA_PORT GPIOB +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_11 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOB +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_10 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR_I2C2RST +#define I2C_INSTANCE_0_EV_IRQHandler I2C2_EV_IRQHandler +#define I2C_INSTANCE_0_ER_IRQHandler I2C2_ER_IRQHandler +#define I2C_INSTANCE_0_EV_IRQn I2C2_EV_IRQn +#define I2C_INSTANCE_0_ER_IRQn I2C2_ER_IRQn +#define I2C_INSTANCE_0_GUARD_TIME 0 + +#define TOUCH_SENSITIVITY 0x06 +#define TOUCH_I2C_INSTANCE 0 +#define TOUCH_RST_PORT GPIOC +#define TOUCH_RST_PIN GPIO_PIN_5 +#define TOUCH_INT_PORT GPIOC +#define TOUCH_INT_PIN GPIO_PIN_4 +#define TOUCH_ON_PORT GPIOB +#define TOUCH_ON_PIN GPIO_PIN_8 +#define TOUCH_PANEL_LHS200KB_IF21 1 + +#define SD_DETECT_PORT GPIOB +#define SD_DETECT_PIN GPIO_PIN_0 +#define SD_ENABLE_PORT GPIOE +#define SD_ENABLE_PIN GPIO_PIN_1 + +#define SBU_1_PIN GPIO_PIN_2 +#define SBU_1_PORT GPIOA +#define SBU_1_CLK_ENA __HAL_RCC_GPIOA_CLK_ENABLE +#define SBU_2_PIN GPIO_PIN_3 +#define SBU_2_PORT GPIOA +#define SBU_2_CLK_ENA __HAL_RCC_GPIOA_CLK_ENABLE + +#define GPIO_1_PORT GPIOC +#define GPIO_1_PIN GPIO_PIN_1 +#define GPIO_2_PORT GPIOC +#define GPIO_2_PIN GPIO_PIN_6 +#define GPIO_3_PORT GPIOC +#define GPIO_3_PIN GPIO_PIN_7 + +#define BTN_POWER_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE +#define BTN_POWER_PORT GPIOE +#define BTN_POWER_PIN GPIO_PIN_0 + +#define NRF_IN_GPIO0_PIN GPIO_PIN_1 +#define NRF_IN_GPIO0_PORT GPIOC +#define NRF_IN_GPIO0_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define NRF_IN_FW_RUNNING_PIN GPIO_PIN_6 +#define NRF_IN_FW_RUNNING_PORT GPIOC +#define NRF_IN_FW_RUNNING_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define NRF_OUT_RESET_PIN GPIO_PIN_1 +#define NRF_OUT_RESET_PORT GPIOA +#define NRF_OUT_RESET_CLK_ENA __HAL_RCC_GPIOA_CLK_ENABLE +#define NRF_OUT_STAY_IN_BLD_PIN GPIO_PIN_12 +#define NRF_OUT_STAY_IN_BLD_PORT GPIOB +#define NRF_OUT_STAY_IN_BLD_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE +#define NRF_OUT_FW_RUNNING_PIN GPIO_PIN_7 +#define NRF_OUT_FW_RUNNING_PORT GPIOC +#define NRF_OUT_FW_RUNNING_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE + +#endif //_TREZOR_T3W1_H diff --git a/core/embed/models/T2W1/bootloaders/bootloader_T2W1.bin b/core/embed/models/T2W1/bootloaders/bootloader_T2W1.bin new file mode 100644 index 0000000000000000000000000000000000000000..4302d3451cf3c2474fd81594ade5563ffa024518 GIT binary patch literal 115200 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 z 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 literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/config.mk b/core/embed/models/T2W1/config.mk new file mode 100644 index 0000000000..a93e37f112 --- /dev/null +++ b/core/embed/models/T2W1/config.mk @@ -0,0 +1,3 @@ +MCU = STM32F4 +OPENOCD_TARGET = target/stm32f4x.cfg +LAYOUT_FEATURE = layout_bolt diff --git a/core/embed/models/T2W1/memory.ld b/core/embed/models/T2W1/memory.ld new file mode 100644 index 0000000000..1614fb601e --- /dev/null +++ b/core/embed/models/T2W1/memory.ld @@ -0,0 +1,68 @@ +/* Auto-generated file, do not edit.*/ + +NORCOW_SECTOR_SIZE = 0x10000; +FLASH_START = 0x8000000; +BOARDLOADER_START = 0x8000000; +BOARDLOADER_MAXSIZE = 0xc000; +BOARDLOADER_SECTOR_START = 0x0; +BOARDLOADER_SECTOR_END = 0x2; +BOARDCAPS_START = 0x800bf00; +BOARDCAPS_MAXSIZE = 0x100; +UNUSED_1_START = 0x800c000; +UNUSED_1_MAXSIZE = 0x4000; +UNUSED_1_SECTOR_START = 0x3; +UNUSED_1_SECTOR_END = 0x3; +STORAGE_1_START = 0x8010000; +STORAGE_1_MAXSIZE = 0x10000; +STORAGE_1_SECTOR_START = 0x4; +STORAGE_1_SECTOR_END = 0x4; +BOOTLOADER_START = 0x8020000; +BOOTLOADER_MAXSIZE = 0x20000; +BOOTLOADER_SECTOR_START = 0x5; +BOOTLOADER_SECTOR_END = 0x5; +FIRMWARE_START = 0x8040000; +FIRMWARE_MAXSIZE = 0x1a0000; +FIRMWARE_P1_START = 0x8040000; +FIRMWARE_P1_MAXSIZE = 0xc0000; +FIRMWARE_P1_SECTOR_START = 0x6; +FIRMWARE_P1_SECTOR_END = 0xb; +KERNEL_START = 0x8040000; +KERNEL_MAXSIZE = 0x80000; +ASSETS_START = 0x8100000; +ASSETS_MAXSIZE = 0xc000; +ASSETS_SECTOR_START = 0xc; +ASSETS_SECTOR_END = 0xe; +UNUSED_2_START = 0x810c000; +UNUSED_2_MAXSIZE = 0x4000; +UNUSED_2_SECTOR_START = 0xf; +UNUSED_2_SECTOR_END = 0xf; +STORAGE_2_START = 0x8110000; +STORAGE_2_MAXSIZE = 0x10000; +STORAGE_2_SECTOR_START = 0x10; +STORAGE_2_SECTOR_END = 0x10; +FIRMWARE_P2_START = 0x8120000; +FIRMWARE_P2_MAXSIZE = 0xe0000; +FIRMWARE_P2_SECTOR_START = 0x11; +FIRMWARE_P2_SECTOR_END = 0x17; +S_MAIN_STACK_START = 0x10000000; +S_MAIN_STACK_SIZE = 0x4000; +S_FB1_RAM_START = 0x10004000; +S_FB1_RAM_SIZE = 0x0; +S_MAIN_RAM_START = 0x10004000; +S_MAIN_RAM_SIZE = 0xbf00; +K_MAIN_STACK_START = 0x10000000; +K_MAIN_STACK_SIZE = 0x2000; +K_AUX2_RAM_START = 0x10002000; +K_AUX2_RAM_SIZE = 0xa000; +K_FB1_RAM_START = 0x1000c000; +K_FB1_RAM_SIZE = 0x0; +K_MAIN_RAM_START = 0x1000c000; +K_MAIN_RAM_SIZE = 0x3f00; +BOOTARGS_START = 0x1000ff00; +BOOTARGS_SIZE = 0x100; +DMABUF_RAM_START = 0x20000000; +DMABUF_RAM_SIZE = 0x800; +AUX1_RAM_START = 0x20000800; +AUX1_RAM_SIZE = 0x2f800; +CODE_ALIGNMENT = 0x200; +COREAPP_ALIGNMENT = 0x200; diff --git a/core/embed/models/T2W1/model_T2W1.h b/core/embed/models/T2W1/model_T2W1.h new file mode 100644 index 0000000000..d8f2f295f0 --- /dev/null +++ b/core/embed/models/T2W1/model_T2W1.h @@ -0,0 +1,128 @@ +#ifndef MODELS_MODEL_T2T1_H_ +#define MODELS_MODEL_T2T1_H_ + +// #include "bootloaders/bootloader_hashes.h" + +#define MODEL_NAME "T2W1" +#define MODEL_FULL_NAME "Trezor Model T2W1" +#define MODEL_INTERNAL_NAME "T2W1" +#define MODEL_INTERNAL_NAME_TOKEN T2W1 +#define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T2W1 +#define MODEL_USB_MANUFACTURER "SatoshiLabs" +#define MODEL_USB_PRODUCT "TREZOR" +#define MODEL_HOMESCREEN_MAXSIZE 16384 + +/*** PRODUCTION KEYS ***/ +#define MODEL_BOARDLOADER_KEYS \ + (const uint8_t *)"\x0e\xb9\x85\x6b\xe9\xba\x7e\x97\x2c\x7f\x34\xea\xc1\xed\x9b\x6f\xd0\xef\xd1\x72\xec\x00\xfa\xf0\xc5\x89\x75\x9d\xa4\xdd\xfb\xa0", \ + (const uint8_t *)"\xac\x8a\xb4\x0b\x32\xc9\x86\x55\x79\x8f\xd5\xda\x5e\x19\x2b\xe2\x7a\x22\x30\x6e\xa0\x5c\x6d\x27\x7c\xdf\xf4\xa3\xf4\x12\x5c\xd8", \ + (const uint8_t *)"\xce\x0f\xcd\x12\x54\x3e\xf5\x93\x6c\xf2\x80\x49\x82\x13\x67\x07\x86\x3d\x17\x29\x5f\xac\xed\x72\xaf\x17\x1d\x6e\x65\x13\xff\x06", + +#define MODEL_BOOTLOADER_KEYS \ + (const uint8_t *)"\xc2\xc8\x7a\x49\xc5\xa3\x46\x09\x77\xfb\xb2\xec\x9d\xfe\x60\xf0\x6b\xd6\x94\xdb\x82\x44\xbd\x49\x81\xfe\x3b\x7a\x26\x30\x7f\x3f", \ + (const uint8_t *)"\x80\xd0\x36\xb0\x87\x39\xb8\x46\xf4\xcb\x77\x59\x30\x78\xde\xb2\x5d\xc9\x48\x7a\xed\xcf\x52\xe3\x0b\x4f\xb7\xcd\x70\x24\x17\x8a", \ + (const uint8_t *)"\xb8\x30\x7a\x71\xf5\x52\xc6\x0a\x4c\xbb\x31\x7f\xf4\x8b\x82\xcd\xbf\x6b\x6b\xb5\xf0\x4c\x92\x0f\xec\x7b\xad\xf0\x17\x88\x37\x51", + +#define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_BLAKE2S + +#define DISPLAY_JUMP_BEHAVIOR DISPLAY_RETAIN_CONTENT + +// SHARED WITH MAKEFILE +// common + +#define NORCOW_SECTOR_SIZE (1 * 64 * 1024) // 64 kB +#define FLASH_START 0x08000000 + +// FLASH layout +#define BOARDLOADER_START 0x08000000 +#define BOARDLOADER_MAXSIZE (3 * 16 * 1024) // 48 kB +#define BOARDLOADER_SECTOR_START 0 +#define BOARDLOADER_SECTOR_END 2 + +#define BOARDCAPS_START 0x0800BF00 +#define BOARDCAPS_MAXSIZE 0x100 + +#define UNUSED_1_START 0x0800C000 +#define UNUSED_1_MAXSIZE (1 * 16 * 1024) // 16 kB +#define UNUSED_1_SECTOR_START 3 +#define UNUSED_1_SECTOR_END 3 + +#define STORAGE_1_START 0x08010000 +#define STORAGE_1_MAXSIZE (1 * 64 * 1024) // 64 kB +#define STORAGE_1_SECTOR_START 4 +#define STORAGE_1_SECTOR_END 4 + +#define BOOTLOADER_START 0x08020000 +#define BOOTLOADER_MAXSIZE (1 * 128 * 1024) // 128 kB +#define BOOTLOADER_SECTOR_START 5 +#define BOOTLOADER_SECTOR_END 5 + +#define FIRMWARE_START 0x08040000 +#define FIRMWARE_MAXSIZE (13 * 128 * 1024) // 1664 kB +#define FIRMWARE_P1_START 0x08040000 +#define FIRMWARE_P1_MAXSIZE (6 * 128 * 1024) +#define FIRMWARE_P1_SECTOR_START 6 +#define FIRMWARE_P1_SECTOR_END 11 +// part of firmware P1 +#define KERNEL_START 0x08040000 +#define KERNEL_MAXSIZE (4 * 128 * 1024) + +#define ASSETS_START 0x08100000 +#define ASSETS_MAXSIZE (3 * 16 * 1024) // 48 kB +#define ASSETS_SECTOR_START 12 +#define ASSETS_SECTOR_END 14 + +#define UNUSED_2_START 0x0810C000 +#define UNUSED_2_MAXSIZE (1 * 16 * 1024) // 16 kB +#define UNUSED_2_SECTOR_START 15 +#define UNUSED_2_SECTOR_END 15 + +#define STORAGE_2_START 0x08110000 +#define STORAGE_2_MAXSIZE (1 * 64 * 1024) // 64 kB +#define STORAGE_2_SECTOR_START 16 +#define STORAGE_2_SECTOR_END 16 + +#define FIRMWARE_P2_START 0x08120000 +#define FIRMWARE_P2_MAXSIZE (7 * 128 * 1024) +#define FIRMWARE_P2_SECTOR_START 17 +#define FIRMWARE_P2_SECTOR_END 23 + +// Ram layout - shared boardloader, bootloader, prodtest +#define S_MAIN_STACK_START 0x10000000 +#define S_MAIN_STACK_SIZE (16 * 1024) + +#define S_FB1_RAM_START 0x10004000 +#define S_FB1_RAM_SIZE (0) + +#define S_MAIN_RAM_START 0x10004000 +#define S_MAIN_RAM_SIZE (48 * 1024 - 0x100) + +// RAM layout - kernel +#define K_MAIN_STACK_START 0x10000000 +#define K_MAIN_STACK_SIZE (8 * 1024) + +#define K_AUX2_RAM_START 0x10002000 +#define K_AUX2_RAM_SIZE (40 * 1024) + +#define K_FB1_RAM_START 0x1000C000 +#define K_FB1_RAM_SIZE (0) + +#define K_MAIN_RAM_START 0x1000C000 +#define K_MAIN_RAM_SIZE (16 * 1024 - 0x100) + +// RAM layout - common +#define BOOTARGS_START 0x1000FF00 +#define BOOTARGS_SIZE 0x100 + +#define DMABUF_RAM_START 0x20000000 +#define DMABUF_RAM_SIZE (2 * 1024) + +#define AUX1_RAM_START (0x20000800) +#define AUX1_RAM_SIZE (190 * 1024) + +// misc +#define CODE_ALIGNMENT 0x200 +#define COREAPP_ALIGNMENT 0x200 + +#endif diff --git a/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 0000000000..c791aab382 --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,22 @@ +{ + "header_len": 4608, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "T2W1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "_reserved": 0, + "_dont_provide_secret": false, + "allow_run_with_secret": false, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.toif new file mode 120000 index 0000000000..3dc5d9734f --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_dev_DO_NOT_SIGN.toif @@ -0,0 +1 @@ +./vendor_satoshilabs.toif \ No newline at end of file diff --git a/core/embed/models/T2W1/vendorheader/vendor_prodtest.json b/core/embed/models/T2W1/vendorheader/vendor_prodtest.json new file mode 100644 index 0000000000..fe8a356749 --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_prodtest.json @@ -0,0 +1,21 @@ +{ + "header_len": 4608, + "text": "UNSAFE, FACTORY TEST ONLY", + "hw_model": "T2W1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "_reserved": 0, + "_dont_provide_secret": false, + "allow_run_with_secret": false, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "c17d221529b70da08aa42ccb1b2cef773736a7d48434209f6eb16b1b474716d2", + "6622ee8403464acfc2fe1e20311937b115e60771f3ee6e70f22bf2921977e534" + ] +} diff --git a/core/embed/models/T2W1/vendorheader/vendor_prodtest.toif b/core/embed/models/T2W1/vendorheader/vendor_prodtest.toif new file mode 120000 index 0000000000..22ac5e8400 --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_prodtest.toif @@ -0,0 +1 @@ +vendor_unsafe.toif \ No newline at end of file diff --git a/core/embed/models/T2W1/vendorheader/vendor_satoshilabs.json b/core/embed/models/T2W1/vendorheader/vendor_satoshilabs.json new file mode 100644 index 0000000000..32d01bbebc --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_satoshilabs.json @@ -0,0 +1,22 @@ +{ + "header_len": 4608, + "text": "SatoshiLabs", + "hw_model": "T2W1", + "expiry": 0, + "version": [0, 1], + "sig_m": 2, + "trust": { + "_reserved": 0, + "_dont_provide_secret": false, + "allow_run_with_secret": false, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "47fbdc84d8abef44fe6abde8f87b6ead821b7082ec63b9f7cc33dc53bf6c708d", + "9af22a52ab47a93091403612b3d6731a2dfef8a33383048ed7556a20e8b03c81", + "2218c25f8ba70c82eba8ed6a321df209c0a7643d014f33bf9317846f62923830" + ] +} diff --git a/core/embed/models/T2W1/vendorheader/vendor_satoshilabs.toif b/core/embed/models/T2W1/vendorheader/vendor_satoshilabs.toif new file mode 100644 index 0000000000000000000000000000000000000000..231990e5a2eebbbd752b62b3a91db6e981b835ad GIT binary patch literal 4222 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 U@-XiBXA}NhKiALob3NDkf0mleR{#J2 literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/vendorheader/vendor_unsafe.json b/core/embed/models/T2W1/vendorheader/vendor_unsafe.json new file mode 100644 index 0000000000..89d987f8a1 --- /dev/null +++ b/core/embed/models/T2W1/vendorheader/vendor_unsafe.json @@ -0,0 +1,22 @@ +{ + "header_len": 4608, + "text": "UNSAFE, DO NOT USE!", + "hw_model": "T2W1", + "expiry": 0, + "version": [0, 1], + "sig_m": 2, + "trust": { + "_reserved": 0, + "_dont_provide_secret": false, + "allow_run_with_secret": false, + "show_vendor_string": true, + "require_user_click": true, + "red_background": true, + "delay": 1 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/models/T2W1/vendorheader/vendor_unsafe.toif b/core/embed/models/T2W1/vendorheader/vendor_unsafe.toif new file mode 100644 index 0000000000000000000000000000000000000000..8c25f0ddd9f77e9e0259da329d46af4621bbb0db GIT binary patch literal 2162 zcmV-&2#xntPf1320C)gq2mk=>k}G&3OAv(-2m}Ig1p+Yw5fOnvL|{fBA`plb2*e0P zL`1}j2uuV5frvmLMj#Lo5fKQ)7(_%w1OkCTj6keFAn5Mu$4z$k+uhJbU|tE6k15$x zr_Nue5+re~V;$>Q$2!(amFa?>vvZbWW%`vlTeQG?(oyq&%26YE#Rp%E`-Y@pCe=G1 z$Wyra608|JzKD1*p6e{316yuoC8l(c-DCRF56&O&LxMV;pFctHy#1$}N z!JDUb)W5ABxSm;`Ja8NRzp3)ExakLux$nso+t!g{J&EMTK5u~ixli*`)bNV*^`&q@}VNnI%`-Gk!2L{d@ej``8LV3=0tfD+Er5t7MwVfj+C z$T##>%JeX3O_JfdKS!mQU&RHrk%X(649(AgV)|Y2IkattrMn9C-XO%%tx2*{ z_u?pPXQxXFd?xB8~T2QQO`GEBhU@)~I)(6Q$7nh^WqQyk zqP$lgcufL`i<)#p=UoEk^@4fPm~c#E=_#EPhG}GYxU?-gLiRcoh9{LO!aG+TPrL@{ zB3Ck!0~#K!fjU*H;c><@%n{x+cvERm%*z!wLgQV~CNiPQO^-Sil()^ishFgIY~NOk zkP@~?5xF3cWzYIQ7{;4oUUl+xCUr;OgcSc7zH2BeKAiR#c@#QNGHj?lXg3*qNgQ!l0KQ)(N zynek6g+i{y4aD0;G@B~L{Hfg_+w;%6piLx;q3}<8!sdu#F@U1ZTUY+o{zDVKV1D(k zC6;cVgvmRS{?+=Vj^xpkhA*`aIEY#Y5&?L1e`hj?-X-V`9d+-+W0H;}w!0wi5=7S= zieQS^4US}5g0BRU#AztHX*A)dJreGd9MU=5b62~nOyBCx zl^cp~pLCI%EUDeDt6cAEsy0iIaO&!feujso+h$E9r`sL+EjmZKzKO70C5TC$VI*Hw zd$I!t2~W9*Bs^Cw`d&{~V(B($f`nORx_GI4=&E%jt24R1BMn%(RUWRd=&H)Ggiitg z+afb0-I6j$TzCyqLh=G>ZP^Z%?h}i~Su|U`V_3r2g|;Xl>1Jj4p4=B#RbJ(HEJ?#x z&q^%emNw~uBjKt>$c{{M3iUtgb(My&b8b+K<6$G=M>JjR4uVxd+v+ofJ)?>wms5*3 z$t?l90yktQ=WMP`anvB>8*&Mj-4g!&1H1au&^Nyp*sZNXzoImf-kD6&zt^n4Pes`2 znk0wes*wzv*CkVAvwttTg6!i53)@A13onGuizj>u#?Lp4O!($oO_pi+EA zw5H8kaqIWq*IN4jiSRunkiEWsRUXBx|1_qo?EicjlbN=QB}CyNNpr|Gk4Y4>GTLru zzbB1JY2(FFl}LCK6tuX(M-AoXM?Jwe(}1bzVTwK(};KzWI-IOJ4-ZT8Z=RUcXn{T%~LE>E#zR6UR{hu#4 z8;X9cXA}g*Fo&QO& zL37$`GsX$G*<9lp$ufO^A7?U2<4D`0BdOCoaPyyko|vQmqNXB#!~=Sb(Aui~=34t? zEf8SUlTWd_>PrBLadd^X@n;%r?8leQOvOnon4efpIw(VZBi&!sMH7Dg=BoKZeZ@0; z35Qo1e#^7cesQ_&D++8sd74vS@tet;Ef;ae>@P=KR|}dT+o}Wh7o)vn+i72`0`)IL z3$nd~_O&ipPksg3tW51e`&wl>;qhjjs{&8b{b*myBqyvE+myRvKn;@cTq#x*@gjB9 o18>j-2~y{*%BKRP{i1f5)l?(d6-#&wNP4Ve9qU-fI@U+k|Kc$>ZU6uP literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/T2W1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 0000000000000000000000000000000000000000..1a04ecaab3d589551fbd607e13d5982c3ddbdf3f GIT binary patch literal 4608 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 literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/vendorheader/vendorheader_prodtest_unsigned.bin b/core/embed/models/T2W1/vendorheader/vendorheader_prodtest_unsigned.bin new file mode 100644 index 0000000000000000000000000000000000000000..c45817eef15b32f273dbf64bbcec39c77b7fac7d GIT binary patch literal 4608 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 XvqOPHfkS~qfkS~qfkT1+SAqWk7=d3s literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/vendorheader/vendorheader_satoshilabs_unsigned.bin b/core/embed/models/T2W1/vendorheader/vendorheader_satoshilabs_unsigned.bin new file mode 100644 index 0000000000000000000000000000000000000000..2212dcb3d04529b0b47a9bf5ecb433dfff8b60a6 GIT binary patch literal 4608 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 LbF>b7(Aj?hM)8tn literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/vendorheader/vendorheader_unsafe_unsigned.bin b/core/embed/models/T2W1/vendorheader/vendorheader_unsafe_unsigned.bin new file mode 100644 index 0000000000000000000000000000000000000000..30dba7fbc61af61969fe065f66cd84e83dfcaca9 GIT binary patch literal 4608 zcmeI!_fr%25&&=rcme_^gmQ>LXaNlzXM%DfND+icVx)v15a}gHkx)Ym(jrA820_Xx z9!5DrK#(3nQ@YX#AQ3n~Ly;blCgeHu-kbM7yy5%Hes_P_na}LZuAPmeJ)b1szaKw9 zfXuUlV$S_1{}E=>QiH-^(8l1yuRu=u>oxgnr4vzwttOi={8``dO6!r;R#HJl9d$w0 z`VUs|Idn|5@3FUEWEQx83yfM!6L1k)X=aev@<18?{nqzP=G5)WjBx5AnagXJyP={t zx&}mFw>7zHt_3nffv%(MKxkWYWjhr7DuIu{=Pks?w?cssRIE-WO9%-9@W%k>01^`M z#%8WpK`JLxq=njq%*@Q%(u5F#fcO++&{fb$2?+_IwqJf!e^iX`8PknH3#&_=$nb6U zz>{$FbI-AXfEEYs9QWvu3zhxVvjy_H%#54@5~H~ zYjT)i`899WvoXz$*?)j#%1t3l_@Xt7yeouPpWTM-jkgUjR^vt6avUN2aq-9BNFx%R zs<>rVK!#$lJd$PPFeTkN6i^wv-!GRPWPKXEqS`)$jSjvfF; z-N3LVDXttmTh-FIq-BDsK%Wv%4@ZnzGC*JN_x*fWsH#MwqO8|x+V?jXZ8$A12f zWZ$p^r8~lH*QT;d@2h>!*WY}Rlo^JR#fu!5_G8r#lS)1s2u(qssICSI)WIyXJoF}i zzmp{PbdKgyZuC#`2XhaCVz|LQ?L(3gHx+siD@ zq2BSIwolKHtg)1+2W5Em?-~8lk?(#hY%>%bW-*;4EwXm;?drTD6M}ul)K;nw<>Q97 zCJg6!CM`oDSS803X&d0!buwHAe?GGn*ko}5SE9Q!_y>qdW^8rWId-X$mtyh=iRTaHBEEV8{$tC-1_!x1utxJUMyHRXBt@J!V}9C zX>0&z#t$Pi5<2!pThW)({YPqv|3jC>? znhQGmwZKopsQMH&1B~|GEtI|c;sxJ?q?=w0LUGIjEljNhR^O;9=D5KcAkEe#h`C}j?jX? z#q?j(n#sPf7_T}*yV^xY1dD7LErn%~%0mKg+?#V#ow3lxE{i9iP1sAYB*W)vYL9Kx z^}4nB8vuHq8uR{TNc;%slYFpn_N3(Dfk4CF@PJ;k%y?<3X>*}2Whxgj)I3ISMwyQ< z=BeGCp*j@aQiA+vEizZ$zU8-)n( zs$TXw;=gQ9jXCb|Qr8XDG8&tRXvKCqPxmE#nHM9MnOl>tZZ@L~59vDp04`Mtoe1=4 z*0>MH&9z%+SrUMs5*iy9a}C@E5ez|}L>iU2!Jsy6xR(s45P+U0nD4T%E@7pCzc~xc zu+N8m5!@cm(q-tBV1;GkueWF>NXf}Z>i$!(?@jZU>$CH3*BY42Vu4NFc9{nSI(nZP z#$)8uh;$tG^=MAoo4s9cN(A>ADrjpx}mXgN3LKF7npa{~CtXsKHm{zj2`wk{j_-TB(G_|9b=3n$EpJP?~E@J;r4qX!%3QUci0xpLxlW8$~! zUmZ}yV-s}5ipjpCm;TI#_mdI;YUse%<(--aU55Rr!QEJlvhIAwUTQ-nY((JpfS|C= zJiVs~Ks_i7&tciAevq~zh+0Pdcl}$ic>lY1j($f1M*>FzM*>FzM*>Fz|L+3-0)2XQ A#Q*>R literal 0 HcmV?d00001 diff --git a/core/embed/models/T2W1/versions.h b/core/embed/models/T2W1/versions.h new file mode 100644 index 0000000000..546ca6a16b --- /dev/null +++ b/core/embed/models/T2W1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 2 +#define FIRMWARE_MONOTONIC_VERSION 2 diff --git a/core/site_scons/models/T2W1/__init__.py b/core/site_scons/models/T2W1/__init__.py new file mode 100644 index 0000000000..c99f655eab --- /dev/null +++ b/core/site_scons/models/T2W1/__init__.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Optional + +from .t2w1 import configure + + +def configure_board( + revision: Optional[int | str], + features_wanted: list[str], + env: dict, # type: ignore + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +): + defines += (("MODEL_HEADER", '"T2W1/model_T2W1.h"'),) + defines += (("VERSIONS_HEADER", '"T2W1/versions.h"'),) + + return configure(env, features_wanted, defines, sources, paths) + + +def get_model_ui() -> str: + return "bolt" + + +def get_model_ui_conf() -> list[str]: + return [] diff --git a/core/site_scons/models/T2W1/t2w1.py b/core/site_scons/models/T2W1/t2w1.py new file mode 100644 index 0000000000..af86980c55 --- /dev/null +++ b/core/site_scons/models/T2W1/t2w1.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +from .. import get_hw_model_as_number +from ..stm32f4_common import stm32f4_common_files + + +def configure( + env: dict, + features_wanted: list[str], + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +) -> list[str]: + features_available: list[str] = [] + board = "T2W1/boards/t2w1.h" + hw_model = get_hw_model_as_number("T2W1") + hw_revision = 0 + + features_available.append("display_rgb565") + defines += [ + "DISPLAY_RGB565", + ("USE_RGB_COLORS", "1"), + ("DISPLAY_RESX", "240"), + ("DISPLAY_RESY", "320"), + ] + + mcu = "STM32F427xx" + + stm32f4_common_files(env, defines, sources, paths) + + env.get("ENV")[ + "CPU_ASFLAGS" + ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16" + env.get("ENV")[ + "CPU_CCFLAGS" + ] = "-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 " + env.get("ENV")["RUST_TARGET"] = "thumbv7em-none-eabihf" + + defines += [ + mcu, + ("TREZOR_BOARD", f'"{board}"'), + ("HW_MODEL", str(hw_model)), + ("HW_REVISION", str(hw_revision)), + ("HSE_VALUE", "8000000"), + ("USE_HSE", "1"), + ] + + sources += ["embed/io/display/st-7789/display_nofb.c"] + sources += ["embed/io/display/st-7789/display_driver.c"] + sources += ["embed/io/display/st-7789/display_io.c"] + sources += ["embed/io/display/st-7789/display_panel.c"] + sources += ["embed/io/display/st-7789/panels/lhs200kb-if21.c"] + paths += ["embed/io/display/inc"] + + features_available.append("backlight") + defines += [("USE_BACKLIGHT", "1")] + sources += ["embed/io/backlight/stm32/tps61043.c"] + paths += ["embed/io/backlight/inc"] + + if "input" in features_wanted: + sources += ["embed/io/i2c_bus/stm32f4/i2c_bus.c"] + sources += ["embed/io/touch/ft6x36/ft6x36.c"] + sources += ["embed/io/touch/ft6x36/panels/lhs200kb-if21.c"] + paths += ["embed/io/i2c_bus/inc"] + paths += ["embed/io/touch/inc"] + features_available.append("touch") + defines += [("USE_TOUCH", "1")] + defines += [("USE_BUTTON", "1")] + sources += ["embed/io/button/stm32/button.c"] + paths += ["embed/io/button/inc"] + features_available.append("button") + defines += [("USE_I2C", "1")] + + if "sd_card" in features_wanted: + sources += ["embed/io/sdcard/stm32f4/sdcard.c"] + sources += ["embed/upymod/modtrezorio/ff.c"] + sources += ["embed/upymod/modtrezorio/ffunicode.c"] + sources += [ + "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c" + ] + paths += ["embed/io/sdcard/inc"] + features_available.append("sd_card") + defines += [("USE_SD_CARD", "1")] + + if "sbu" in features_wanted: + sources += ["embed/io/sbu/stm32/sbu.c"] + paths += ["embed/io/sbu/inc"] + features_available.append("sbu") + defines += [("USE_SBU", "1")] + + if "ble" in features_wanted: + sources += ["embed/io/ble/stm32/ble.c"] + paths += ["embed/io/ble/inc"] + features_available.append("ble") + defines += [("USE_BLE", "1")] + sources += ["embed/io/nrf/stm32f4/nrf.c"] + sources += ["embed/io/nrf/crc8.c"] + paths += ["embed/io/nrf/inc"] + sources += [ + "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c", + ] + + if "usb" in features_wanted: + sources += [ + "embed/io/usb/stm32/usb_class_hid.c", + "embed/io/usb/stm32/usb_class_vcp.c", + "embed/io/usb/stm32/usb_class_webusb.c", + "embed/io/usb/stm32/usb.c", + "embed/io/usb/stm32/usbd_conf.c", + "embed/io/usb/stm32/usbd_core.c", + "embed/io/usb/stm32/usbd_ctlreq.c", + "embed/io/usb/stm32/usbd_ioreq.c", + "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", + ] + features_available.append("usb") + paths += ["embed/io/usb/inc"] + defines += [("USE_USB", "1")] + + if "dma2d" in features_wanted: + defines += ["USE_DMA2D"] + sources += ["embed/gfx/bitblt/stm32/dma2d_bitblt.c"] + sources += [ + "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c" + ] + features_available.append("dma2d") + + defines += [("USE_PVD", "1")] + + return features_available diff --git a/core/src/apps/common/coininfo.py b/core/src/apps/common/coininfo.py index 602f2ada3f..f8ec8d9acc 100644 --- a/core/src/apps/common/coininfo.py +++ b/core/src/apps/common/coininfo.py @@ -7040,4 +7040,1341 @@ def by_name(name: str) -> CoinInfo: None, # confidential_assets ) raise ValueError # Unknown coin name + if utils.INTERNAL_MODEL == "T2W1": + if name == "Bitcoin": + return CoinInfo( + name, # coin_name + "BTC", # coin_shortcut + 8, # decimals + 0, # address_type + 5, # address_type_p2sh + 2000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "bc", # bech32_prefix + None, # cashaddr_prefix + 0, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Regtest": + return CoinInfo( + name, # coin_name + "REGTEST", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "bcrt", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Testnet": + return CoinInfo( + name, # coin_name + "TEST", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x024289ef, # xpub_magic_multisig_segwit_p2sh + 0x02575483, # xpub_magic_multisig_segwit_native + "tb", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if not utils.BITCOIN_ONLY: + if name == "Actinium": + return CoinInfo( + name, # coin_name + "ACM", # coin_shortcut + 8, # decimals + 53, # address_type + 55, # address_type_p2sh + 320000000000, # maxfee_kb + "Actinium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "acm", # bech32_prefix + None, # cashaddr_prefix + 228, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Axe": + return CoinInfo( + name, # coin_name + "AXE", # coin_shortcut + 8, # decimals + 55, # address_type + 16, # address_type_p2sh + 21000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x02fe52cc, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 4242, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash": + return CoinInfo( + name, # coin_name + "BCH", # coin_shortcut + 8, # decimals + 0, # address_type + 5, # address_type_p2sh + 14000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bitcoincash", # cashaddr_prefix + 145, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bcash Testnet": + return CoinInfo( + name, # coin_name + "TBCH", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "bchtest", # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bprivate": + return CoinInfo( + name, # coin_name + "BTCP", # coin_shortcut + 8, # decimals + 4901, # address_type + 5039, # address_type_p2sh + 32000000000, # maxfee_kb + "BitcoinPrivate Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 183, # slip44 + False, # segwit + False, # taproot + 42, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Bitcore": + return CoinInfo( + name, # coin_name + "BTX", # coin_shortcut + 8, # decimals + 3, # address_type + 125, # address_type_p2sh + 14000000000, # maxfee_kb + "BitCore Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "btx", # bech32_prefix + None, # cashaddr_prefix + 160, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "CPUchain": + return CoinInfo( + name, # coin_name + "CPU", # coin_shortcut + 8, # decimals + 28, # address_type + 30, # address_type_p2sh + 8700000000000, # maxfee_kb + "CPUchain Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "cpu", # bech32_prefix + None, # cashaddr_prefix + 363, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Crown": + return CoinInfo( + name, # coin_name + "CRW", # coin_shortcut + 8, # decimals + 95495, # address_type + 95473, # address_type_p2sh + 52000000000, # maxfee_kb + "Crown Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 72, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Dogecoin": + return CoinInfo( + name, # coin_name + "DOGE", # coin_shortcut + 8, # decimals + 30, # address_type + 22, # address_type_p2sh + 1200000000000, # maxfee_kb + "Dogecoin Signed Message:\n", # signed_message_header + 0x02facafd, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 3, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Elements": + return CoinInfo( + name, # coin_name + "ELEMENTS", # coin_shortcut + 8, # decimals + 235, # address_type + 75, # address_type_p2sh + 10000000, # maxfee_kb + "Bitcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "ert", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + {'address_prefix': 4, 'blech32_prefix': 'el'}, # confidential_assets + ) + if name == "Feathercoin": + return CoinInfo( + name, # coin_name + "FTC", # coin_shortcut + 8, # decimals + 14, # address_type + 5, # address_type_p2sh + 390000000000, # maxfee_kb + "Feathercoin Signed Message:\n", # signed_message_header + 0x0488bc26, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488bc26, # xpub_magic_multisig_segwit_p2sh + 0x0488bc26, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 8, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo": + return CoinInfo( + name, # coin_name + "FIRO", # coin_shortcut + 8, # decimals + 82, # address_type + 7, # address_type_p2sh + 640000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 136, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Firo Testnet": + return CoinInfo( + name, # coin_name + "tFIRO", # coin_shortcut + 8, # decimals + 65, # address_type + 178, # address_type_p2sh + 1000000, # maxfee_kb + "Zcoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Florincoin": + return CoinInfo( + name, # coin_name + "FLO", # coin_shortcut + 8, # decimals + 35, # address_type + 94, # address_type_p2sh + 78000000000, # maxfee_kb + "Florincoin Signed Message:\n", # signed_message_header + 0x00174921, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x00174921, # xpub_magic_multisig_segwit_p2sh + 0x00174921, # xpub_magic_multisig_segwit_native + "flo", # bech32_prefix + None, # cashaddr_prefix + 216, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Fujicoin": + return CoinInfo( + name, # coin_name + "FJC", # coin_shortcut + 8, # decimals + 36, # address_type + 16, # address_type_p2sh + 35000000000000, # maxfee_kb + "FujiCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0295b43f, # xpub_magic_multisig_segwit_p2sh + 0x02aa7ed3, # xpub_magic_multisig_segwit_native + "fc", # bech32_prefix + None, # cashaddr_prefix + 75, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin": + return CoinInfo( + name, # coin_name + "GRS", # coin_shortcut + 8, # decimals + 36, # address_type + 5, # address_type_p2sh + 16000000000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "grs", # bech32_prefix + None, # cashaddr_prefix + 17, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Groestlcoin Testnet": + return CoinInfo( + name, # coin_name + "tGRS", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 100000, # maxfee_kb + "GroestlCoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tgrs", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + True, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-groestl', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Komodo": + return CoinInfo( + name, # coin_name + "KMD", # coin_shortcut + 8, # decimals + 60, # address_type + 85, # address_type_p2sh + 4800000000, # maxfee_kb + "Komodo Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 141, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + True, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Koto": + return CoinInfo( + name, # coin_name + "KOTO", # coin_shortcut + 8, # decimals + 6198, # address_type + 6203, # address_type_p2sh + 1000000, # maxfee_kb + "Koto Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 510, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Litecoin": + return CoinInfo( + name, # coin_name + "LTC", # coin_shortcut + 8, # decimals + 48, # address_type + 50, # address_type_p2sh + 67000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x019da462, # xpub_magic + 0x01b26ef6, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x019da462, # xpub_magic_multisig_segwit_p2sh + 0x019da462, # xpub_magic_multisig_segwit_native + "ltc", # bech32_prefix + None, # cashaddr_prefix + 2, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Litecoin Testnet": + return CoinInfo( + name, # coin_name + "tLTC", # coin_shortcut + 8, # decimals + 111, # address_type + 58, # address_type_p2sh + 40000000, # maxfee_kb + "Litecoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tltc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Monacoin": + return CoinInfo( + name, # coin_name + "MONA", # coin_shortcut + 8, # decimals + 50, # address_type + 55, # address_type_p2sh + 2100000000, # maxfee_kb + "Monacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "mona", # bech32_prefix + None, # cashaddr_prefix + 22, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin": + return CoinInfo( + name, # coin_name + "PPC", # coin_shortcut + 6, # decimals + 55, # address_type + 117, # address_type_p2sh + 13000000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "pc", # bech32_prefix + None, # cashaddr_prefix + 6, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Peercoin Testnet": + return CoinInfo( + name, # coin_name + "tPPC", # coin_shortcut + 6, # decimals + 111, # address_type + 196, # address_type_p2sh + 2000000, # maxfee_kb + "Peercoin Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tpc", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Primecoin": + return CoinInfo( + name, # coin_name + "XPM", # coin_shortcut + 8, # decimals + 23, # address_type + 83, # address_type_p2sh + 89000000000, # maxfee_kb + "Primecoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 24, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum": + return CoinInfo( + name, # coin_name + "QTUM", # coin_shortcut + 8, # decimals + 58, # address_type + 50, # address_type_p2sh + 1000000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "qc", # bech32_prefix + None, # cashaddr_prefix + 2301, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Qtum Testnet": + return CoinInfo( + name, # coin_name + "tQTUM", # coin_shortcut + 8, # decimals + 120, # address_type + 110, # address_type_p2sh + 40000000, # maxfee_kb + "Qtum Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + 0x044a5262, # xpub_magic_segwit_p2sh + 0x045f1cf6, # xpub_magic_segwit_native + 0x043587cf, # xpub_magic_multisig_segwit_p2sh + 0x043587cf, # xpub_magic_multisig_segwit_native + "tq", # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin": + return CoinInfo( + name, # coin_name + "RVN", # coin_shortcut + 8, # decimals + 60, # address_type + 122, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 175, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ravencoin Testnet": + return CoinInfo( + name, # coin_name + "tRVN", # coin_shortcut + 8, # decimals + 111, # address_type + 196, # address_type_p2sh + 170000000000, # maxfee_kb + "Raven Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Ritocoin": + return CoinInfo( + name, # coin_name + "RITO", # coin_shortcut + 8, # decimals + 25, # address_type + 105, # address_type_p2sh + 39000000000000, # maxfee_kb + "Rito Signed Message:\n", # signed_message_header + 0x0534e7ca, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 19169, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash": + return CoinInfo( + name, # coin_name + "SMART", # coin_shortcut + 8, # decimals + 63, # address_type + 18, # address_type_p2sh + 780000000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 224, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "SmartCash Testnet": + return CoinInfo( + name, # coin_name + "tSMART", # coin_shortcut + 8, # decimals + 65, # address_type + 21, # address_type_p2sh + 1000000, # maxfee_kb + "SmartCash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1-smart', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Stakenet": + return CoinInfo( + name, # coin_name + "XSN", # coin_shortcut + 8, # decimals + 76, # address_type + 16, # address_type_p2sh + 11000000000, # maxfee_kb + "DarkCoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "xc", # bech32_prefix + None, # cashaddr_prefix + 199, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Syscoin": + return CoinInfo( + name, # coin_name + "SYS", # coin_shortcut + 8, # decimals + 63, # address_type + 5, # address_type_p2sh + 42000000000, # maxfee_kb + "Syscoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "sys", # bech32_prefix + None, # cashaddr_prefix + 57, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Unobtanium": + return CoinInfo( + name, # coin_name + "UNO", # coin_shortcut + 8, # decimals + 130, # address_type + 30, # address_type_p2sh + 53000000, # maxfee_kb + "Unobtanium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 92, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "VIPSTARCOIN": + return CoinInfo( + name, # coin_name + "VIPS", # coin_shortcut + 8, # decimals + 70, # address_type + 50, # address_type_p2sh + 140000000000000, # maxfee_kb + "VIPSTARCOIN Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "vips", # bech32_prefix + None, # cashaddr_prefix + 1919, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Verge": + return CoinInfo( + name, # coin_name + "XVG", # coin_shortcut + 6, # decimals + 30, # address_type + 33, # address_type_p2sh + 550000000000, # maxfee_kb + "Name: Dogecoin Dark\n", # signed_message_header + 0x022d2533, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 77, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + True, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Viacoin": + return CoinInfo( + name, # coin_name + "VIA", # coin_shortcut + 8, # decimals + 71, # address_type + 33, # address_type_p2sh + 14000000000, # maxfee_kb + "Viacoin Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + 0x049d7cb2, # xpub_magic_segwit_p2sh + 0x04b24746, # xpub_magic_segwit_native + 0x0488b21e, # xpub_magic_multisig_segwit_p2sh + 0x0488b21e, # xpub_magic_multisig_segwit_native + "via", # bech32_prefix + None, # cashaddr_prefix + 14, # slip44 + True, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "ZCore": + return CoinInfo( + name, # coin_name + "ZCR", # coin_shortcut + 8, # decimals + 142, # address_type + 145, # address_type_p2sh + 170000000000, # maxfee_kb + "DarkNet Signed Message:\n", # signed_message_header + 0x04b24746, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 428, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Zcash": + return CoinInfo( + name, # coin_name + "ZEC", # coin_shortcut + 8, # decimals + 7352, # address_type + 7357, # address_type_p2sh + 51000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 133, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Zcash Testnet": + return CoinInfo( + name, # coin_name + "TAZ", # coin_shortcut + 8, # decimals + 7461, # address_type + 7354, # address_type_p2sh + 10000000, # maxfee_kb + "Zcash Signed Message:\n", # signed_message_header + 0x043587cf, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 1, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + True, # extra_data + False, # timestamp + True, # overwintered + None, # confidential_assets + ) + if name == "Ecash": + return CoinInfo( + name, # coin_name + "XEC", # coin_shortcut + 2, # decimals + 0, # address_type + 5, # address_type_p2sh + 14000000, # maxfee_kb + "eCash Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + "ecash", # cashaddr_prefix + 899, # slip44 + False, # segwit + False, # taproot + 0, # fork_id + True, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + if name == "Brhodium": + return CoinInfo( + name, # coin_name + "XRC", # coin_shortcut + 8, # decimals + 61, # address_type + 123, # address_type_p2sh + 1000000000, # maxfee_kb + "BitCoin Rhodium Signed Message:\n", # signed_message_header + 0x0488b21e, # xpub_magic + None, # xpub_magic_segwit_p2sh + None, # xpub_magic_segwit_native + None, # xpub_magic_multisig_segwit_p2sh + None, # xpub_magic_multisig_segwit_native + None, # bech32_prefix + None, # cashaddr_prefix + 10291, # slip44 + False, # segwit + False, # taproot + None, # fork_id + False, # force_bip143 + False, # decred + False, # negative_fee + 'secp256k1', # curve_name + False, # extra_data + False, # timestamp + False, # overwintered + None, # confidential_assets + ) + raise ValueError # Unknown coin name raise ValueError # Unknown model diff --git a/core/src/apps/ethereum/networks.py b/core/src/apps/ethereum/networks.py index 9c00d1a86f..57d6824e57 100644 --- a/core/src/apps/ethereum/networks.py +++ b/core/src/apps/ethereum/networks.py @@ -334,3 +334,58 @@ def _networks_iterator() -> Iterator[NetworkInfoTuple]: "tSEP", # symbol "Sepolia", # name ) + if utils.INTERNAL_MODEL == "T2W1": + yield ( + 1, # chain_id + 60, # slip44 + "ETH", # symbol + "Ethereum", # name + ) + yield ( + 10, # chain_id + 614, # slip44 + "ETH", # symbol + "Optimism", # name + ) + yield ( + 56, # chain_id + 714, # slip44 + "BNB", # symbol + "BNB Smart Chain", # name + ) + yield ( + 61, # chain_id + 61, # slip44 + "ETC", # symbol + "Ethereum Classic", # name + ) + yield ( + 137, # chain_id + 966, # slip44 + "POL", # symbol + "Polygon", # name + ) + yield ( + 8453, # chain_id + 8453, # slip44 + "ETH", # symbol + "Base", # name + ) + yield ( + 17000, # chain_id + 1, # slip44 + "tHOL", # symbol + "Holesky", # name + ) + yield ( + 42161, # chain_id + 9001, # slip44 + "ETH", # symbol + "Arbitrum One", # name + ) + yield ( + 11155111, # chain_id + 1, # slip44 + "tSEP", # symbol + "Sepolia", # name + ) diff --git a/core/src/apps/ethereum/tokens.py b/core/src/apps/ethereum/tokens.py index c83e548899..3174074219 100644 --- a/core/src/apps/ethereum/tokens.py +++ b/core/src/apps/ethereum/tokens.py @@ -782,3 +782,151 @@ def _token_iterator(chain_id: int) -> Iterator[tuple[bytes, str, int, str]]: 18, "Wrapped AVAX", ) + if utils.INTERNAL_MODEL == "T2W1": + if chain_id == 1: # eth + yield ( # address, symbol, decimals, name + b"\x7f\xc6\x65\x00\xc8\x4a\x76\xad\x7e\x9c\x93\x43\x7b\xfc\x5a\xc3\x3e\x2d\xda\xe9", + "AAVE", + 18, + "Aave", + ) + yield ( # address, symbol, decimals, name + b"\x4d\x22\x44\x52\x80\x1a\xce\xd8\xb2\xf0\xae\xbe\x15\x53\x79\xbb\x5d\x59\x43\x81", + "APE", + 18, + "ApeCoin", + ) + yield ( # address, symbol, decimals, name + b"\xbb\x0e\x17\xef\x65\xf8\x2a\xb0\x18\xd8\xed\xd7\x76\xe8\xdd\x94\x03\x27\xb2\x8b", + "AXS", + 18, + "Axie Infinity", + ) + yield ( # address, symbol, decimals, name + b"\x4f\xab\xb1\x45\xd6\x46\x52\xa9\x48\xd7\x25\x33\x02\x3f\x6e\x7a\x62\x3c\x7c\x53", + "BUSD", + 18, + "Binance USD", + ) + yield ( # address, symbol, decimals, name + b"\x35\x06\x42\x4f\x91\xfd\x33\x08\x44\x66\xf4\x02\xd5\xd9\x7f\x05\xf8\xe3\xb4\xaf", + "CHZ", + 18, + "Chiliz", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb7\x3e\x1f\xf0\xb8\x09\x14\xab\x6f\xe0\x44\x4e\x65\x84\x8c\x4c\x34\x45\x0b", + "CRO", + 8, + "Cronos", + ) + yield ( # address, symbol, decimals, name + b"\x6b\x17\x54\x74\xe8\x90\x94\xc4\x4d\xa9\x8b\x95\x4e\xed\xea\xc4\x95\x27\x1d\x0f", + "DAI", + 18, + "Dai", + ) + yield ( # address, symbol, decimals, name + b"\x85\x3d\x95\x5a\xce\xf8\x22\xdb\x05\x8e\xb8\x50\x59\x11\xed\x77\xf1\x75\xb9\x9e", + "FRAX", + 18, + "Frax", + ) + yield ( # address, symbol, decimals, name + b"\x2a\xf5\xd2\xad\x76\x74\x11\x91\xd1\x5d\xfe\x7b\xf6\xac\x92\xd4\xbd\x91\x2c\xa3", + "LEO", + 18, + "LEO Token", + ) + yield ( # address, symbol, decimals, name + b"\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", + "LINK", + 18, + "Chainlink", + ) + yield ( # address, symbol, decimals, name + b"\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", + "MANA", + 18, + "Decentraland", + ) + yield ( # address, symbol, decimals, name + b"\x7d\x1a\xfa\x7b\x71\x8f\xb8\x93\xdb\x30\xa3\xab\xc0\xcf\xc6\x08\xaa\xcf\xeb\xb0", + "MATIC", + 18, + "Polygon", + ) + yield ( # address, symbol, decimals, name + b"\x75\x23\x1f\x58\xb4\x32\x40\xc9\x71\x8d\xd5\x8b\x49\x67\xc5\x11\x43\x42\xa8\x6c", + "OKB", + 18, + "OKB", + ) + yield ( # address, symbol, decimals, name + b"\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", + "QNT", + 18, + "Quant", + ) + yield ( # address, symbol, decimals, name + b"\x38\x45\xba\xda\xde\x8e\x6d\xff\x04\x98\x20\x68\x0d\x1f\x14\xbd\x39\x03\xa5\xd0", + "SAND", + 18, + "The Sandbox", + ) + yield ( # address, symbol, decimals, name + b"\x95\xad\x61\xb0\xa1\x50\xd7\x92\x19\xdc\xf6\x4e\x1e\x6c\xc0\x1f\x0b\x64\xc4\xce", + "SHIB", + 18, + "Shiba Inu", + ) + yield ( # address, symbol, decimals, name + b"\xae\x7a\xb9\x65\x20\xde\x3a\x18\xe5\xe1\x11\xb5\xea\xab\x09\x53\x12\xd7\xfe\x84", + "STETH", + 18, + "Lido Staked Ether", + ) + yield ( # address, symbol, decimals, name + b"\x1f\x98\x40\xa8\x5d\x5a\xf5\xbf\x1d\x17\x62\xf9\x25\xbd\xad\xdc\x42\x01\xf9\x84", + "UNI", + 18, + "Uniswap", + ) + yield ( # address, symbol, decimals, name + b"\xa0\xb8\x69\x91\xc6\x21\x8b\x36\xc1\xd1\x9d\x4a\x2e\x9e\xb0\xce\x36\x06\xeb\x48", + "USDC", + 6, + "USD Coin", + ) + yield ( # address, symbol, decimals, name + b"\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", + "USDT", + 6, + "Tether", + ) + yield ( # address, symbol, decimals, name + b"\x22\x60\xfa\xc5\xe5\x54\x2a\x77\x3a\xa4\x4f\xbc\xfe\xdf\x7c\x19\x3b\xc2\xc5\x99", + "WBTC", + 8, + "Wrapped Bitcoin", + ) + yield ( # address, symbol, decimals, name + b"\xa2\xcd\x3d\x43\xc7\x75\x97\x8a\x96\xbd\xbf\x12\xd7\x33\xd5\xa1\xed\x94\xfb\x18", + "XCN", + 18, + "Chain", + ) + if chain_id == 56: # bnb + yield ( # address, symbol, decimals, name + b"\x0e\xb3\xa7\x05\xfc\x54\x72\x50\x37\xcc\x9e\x00\x8b\xde\xde\x69\x7f\x62\xf3\x35", + "ATOM", + 18, + "Cosmos Hub", + ) + if chain_id == 137: # matic + yield ( # address, symbol, decimals, name + b"\x2c\x89\xbb\xc9\x2b\xd8\x6f\x80\x75\xd1\xde\xcc\x58\xc7\xf4\xe0\x10\x7f\x28\x6b", + "WAVAX", + 18, + "Wrapped AVAX", + ) diff --git a/python/src/trezorlib/firmware/models.py b/python/src/trezorlib/firmware/models.py index a8fa08a988..080dd07203 100644 --- a/python/src/trezorlib/firmware/models.py +++ b/python/src/trezorlib/firmware/models.py @@ -33,6 +33,7 @@ class Model(Enum): T1B1 = b"T1B1" T2B1 = b"T2B1" T2T1 = b"T2T1" + T2W1 = b"T2W1" T3B1 = b"T3B1" T3T1 = b"T3T1" T3W1 = b"T3W1" @@ -178,6 +179,31 @@ T2T1 = ModelKeys( firmware_sigs_needed=-1, ) + +T2W1 = ModelKeys( + production=True, + boardloader_keys=[ + bytes.fromhex(key) + for key in ( + "0eb9856be9ba7e972c7f34eac1ed9b6fd0efd172ec00faf0c589759da4ddfba0", + "ac8ab40b32c98655798fd5da5e192be27a22306ea05c6d277cdff4a3f4125cd8", + "ce0fcd12543ef5936cf2804982136707863d17295faced72af171d6e6513ff06", + ) + ], + boardloader_sigs_needed=2, + bootloader_keys=[ + bytes.fromhex(key) + for key in ( + "c2c87a49c5a3460977fbb2ec9dfe60f06bd694db8244bd4981fe3b7a26307f3f", + "80d036b08739b846f4cb77593078deb25dc9487aedcf52e30b4fb7cd7024178a", + "b8307a71f552c60a4cbb317ff48b82cdbf6b6bb5f04c920fec7badf017883751", + ) + ], + bootloader_sigs_needed=2, + firmware_keys=(), + firmware_sigs_needed=-1, +) + TREZOR_CORE_DEV = ModelKeys( production=False, boardloader_keys=[ @@ -310,6 +336,12 @@ T2T1_HASH_PARAMS = FirmwareHashParameters( padding_byte=None, ) +T2W1_HASH_PARAMS = FirmwareHashParameters( + hash_function=hashlib.blake2s, + chunk_size=1024 * 128, + padding_byte=None, +) + T3T1_HASH_PARAMS = FirmwareHashParameters( hash_function=hashlib.sha256, chunk_size=1024 * 128, @@ -337,6 +369,7 @@ D002_HASH_PARAMS = FirmwareHashParameters( MODEL_MAP = { Model.T1B1: LEGACY_V3, Model.T2T1: T2T1, + Model.T2W1: T2W1, Model.T2B1: T2B1, Model.T3T1: T3T1, Model.T3B1: T3B1, @@ -348,6 +381,7 @@ MODEL_MAP = { MODEL_MAP_DEV = { Model.T1B1: LEGACY_V3_DEV, Model.T2T1: TREZOR_CORE_DEV, + Model.T2W1: TREZOR_CORE_DEV, Model.T2B1: TREZOR_CORE_DEV, Model.T3T1: TREZOR_CORE_DEV, Model.T3B1: TREZOR_CORE_DEV, @@ -359,6 +393,7 @@ MODEL_MAP_DEV = { MODEL_HASH_PARAMS_MAP = { Model.T1B1: LEGACY_HASH_PARAMS, Model.T2T1: T2T1_HASH_PARAMS, + Model.T2W1: T2W1_HASH_PARAMS, Model.T2B1: T2T1_HASH_PARAMS, Model.T3T1: T3T1_HASH_PARAMS, Model.T3B1: T3B1_HASH_PARAMS, diff --git a/python/src/trezorlib/models.py b/python/src/trezorlib/models.py index e7a4d9ea75..a5f3236c75 100644 --- a/python/src/trezorlib/models.py +++ b/python/src/trezorlib/models.py @@ -63,6 +63,15 @@ T2T1 = TrezorModel( default_mapping=mapping.DEFAULT_MAPPING, ) +T2W1 = TrezorModel( + name="T2W1", + internal_name="T2W1", + minimum_version=(2, 1, 0), + vendors=VENDORS, + usb_ids=((0x1209, 0x53C1), (0x1209, 0x53C0)), + default_mapping=mapping.DEFAULT_MAPPING, +) + T2B1 = TrezorModel( name="Safe 3", internal_name="T2B1", @@ -127,7 +136,7 @@ TREZOR_SAFE5 = T3T1 TREZOR_DISC1 = DISC1 TREZOR_DISC2 = DISC2 -TREZORS = frozenset({T1B1, T2T1, T2B1, T3T1, T3B1, T3W1, DISC1, DISC2}) +TREZORS = frozenset({T1B1, T2T1, T2W1, T2B1, T3T1, T3B1, T3W1, DISC1, DISC2}) def by_name(name: str | None) -> TrezorModel | None: