cryptnox-sdk-esp32 1.0.0
ESP32 SDK for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
35
36#include <string.h>
37#include "freertos/FreeRTOS.h"
38#include "freertos/task.h"
39#include "freertos/event_groups.h"
40#include "driver/spi_master.h"
41#include "esp_log.h"
42#include "esp_wifi.h"
43#include "esp_netif.h"
44#include "esp_event.h"
45#include "nvs_flash.h"
46#include "pn532.h"
47#include "CryptnoxWallet.h"
48#include "Pn532NfcTransport.h"
49#include "ESP32Logger.h"
51#include "ESP32Platform.h"
52#include "config.h"
53
54/* ── SPI wiring — ESP32-S3 dev kit + Keyestudio PN532 breakout ──── */
55#define SPI_MOSI 11
56#define SPI_MISO 13
57#define SPI_SCLK 12
58#define SPI_MAX_TRANSFER_SZ 4096
59#define SPI_PIN_UNUSED (-1)
60#define NFC_CS 10
61
62static const char *const TAG = "sign";
63static const uint32_t LOOP_DELAY_MS = 1000U;
64static const uint32_t WIFI_TIMEOUT_MS = 10000U;
65static const int WIFI_MAX_RETRY = 5;
66
67#define WIFI_CONNECTED_BIT BIT0
68#define WIFI_FAIL_BIT BIT1
69
70static EventGroupHandle_t s_wifi_event_group;
71static int s_retry_num = 0;
72
85static void wifi_event_handler(void *arg, esp_event_base_t event_base,
86 int32_t event_id, void *event_data)
87{
88 (void)arg;
89 (void)event_data;
90 if ((event_base == WIFI_EVENT) && (event_id == WIFI_EVENT_STA_START)) {
91 esp_wifi_connect();
92 } else if ((event_base == WIFI_EVENT) &&
93 (event_id == WIFI_EVENT_STA_DISCONNECTED)) {
95 esp_wifi_connect();
97 } else {
98 xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
99 }
100 } else if ((event_base == IP_EVENT) && (event_id == IP_EVENT_STA_GOT_IP)) {
101 s_retry_num = 0;
102 xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
103 } else {
104 /* other events ignored */
105 }
106}
107
120static void wifi_start(void)
121{
122 s_wifi_event_group = xEventGroupCreate();
123 s_retry_num = 0;
124 ESP_ERROR_CHECK(esp_netif_init());
125 ESP_ERROR_CHECK(esp_event_loop_create_default());
126 (void)esp_netif_create_default_wifi_sta();
127 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
128 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
129 esp_event_handler_instance_t h_any;
130 esp_event_handler_instance_t h_ip;
131 ESP_ERROR_CHECK(esp_event_handler_instance_register(
132 WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &h_any));
133 ESP_ERROR_CHECK(esp_event_handler_instance_register(
134 IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &h_ip));
135 wifi_config_t wifi_cfg;
136 (void)memset(&wifi_cfg, 0, sizeof(wifi_cfg));
137 (void)strncpy((char *)wifi_cfg.sta.ssid, WIFI_SSID,
138 sizeof(wifi_cfg.sta.ssid) - 1U);
139 (void)strncpy((char *)wifi_cfg.sta.password, WIFI_PASSWORD,
140 sizeof(wifi_cfg.sta.password) - 1U);
141 wifi_cfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
142 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
143 ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg));
144 ESP_ERROR_CHECK(esp_wifi_start());
145 EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
147 pdFALSE, pdFALSE,
148 pdMS_TO_TICKS(WIFI_TIMEOUT_MS));
149 if ((bits & WIFI_CONNECTED_BIT) != 0U) {
150 ESP_LOGI(TAG, "WiFi connected");
151 } else {
152 ESP_LOGW(TAG, "WiFi connect failed — TRNG entropy may be reduced");
153 }
154 (void)esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, h_ip);
155 (void)esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, h_any);
156 vEventGroupDelete(s_wifi_event_group);
157}
158
169static void run_sign_loop(CryptnoxWallet &wallet)
170{
171 /* Replace with the SHA-256 (or Keccak-256) digest of the real transaction. */
172 static const uint8_t TEST_HASH[CW_HASH_SIZE] = {
173 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
174 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
175 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
176 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
177 };
178 /* Replace with the PIN set on the card (4–9 ASCII digits). */
179 static const uint8_t DEMO_PIN[CW_MAX_PIN_LENGTH] = {
180 '0', '0', '0', '0', '0', '0', '0', '0', '0'
181 };
182
183 bool keep_running = true;
184 while (keep_running) {
185 CW_SecureSession session{};
186 bool connected = wallet.connect(session);
187
188 if (!connected) {
189 ESP_LOGW(TAG, "Card not detected");
190 }
191
192 if (connected) {
193 CW_SignRequest req(session,
194 CW_SIGN_CURR_K1,
195 CW_SIGN_SIG_ECDSA_LOW_S,
196 CW_SIGN_WITH_PIN);
197 req.hash = TEST_HASH;
198 req.hashLength = static_cast<uint8_t>(CW_HASH_SIZE);
199 (void)CW_Utils::safe_memcpy(req.pin, sizeof(req.pin),
200 DEMO_PIN, CW_MAX_PIN_LENGTH);
201
202 CW_SignResult result = wallet.sign(req);
203
204 if (result.errorCode == CW_OK) {
205 ESP_LOGI(TAG, "Sign OK - r:");
206 ESP_LOG_BUFFER_HEX_LEVEL(TAG, &result.signature[CW_SIG_R_OFFSET],
207 CW_HASH_SIZE, ESP_LOG_INFO);
208 ESP_LOGI(TAG, "s:");
209 ESP_LOG_BUFFER_HEX_LEVEL(TAG, &result.signature[CW_SIG_S_OFFSET],
210 CW_HASH_SIZE, ESP_LOG_INFO);
211 } else if (result.errorCode == CW_SIGN_PIN_INCORRECT) {
212 /* CRITICAL: do NOT retry — each wrong PIN decrements the card's
213 * retry counter. Reaching 0 permanently blocks the PIN.
214 * Fix DEMO_PIN before flashing again. */
215 ESP_LOGE(TAG, "Wrong PIN — halting to protect retry counter");
216 keep_running = false;
217 } else {
218 ESP_LOGE(TAG, "Sign failed: 0x%02X",
219 static_cast<unsigned int>(result.errorCode));
220 }
221 }
222
223 wallet.disconnect(session);
224
225 if (keep_running) {
226 vTaskDelay(pdMS_TO_TICKS(LOOP_DELAY_MS));
227 }
228 }
229
230 while (true) {
231 vTaskDelay(pdMS_TO_TICKS(LOOP_DELAY_MS));
232 }
233}
234
241extern "C" void app_main(void)
242{
243 esp_err_t nvs_ret = nvs_flash_init();
244 if ((nvs_ret == ESP_ERR_NVS_NO_FREE_PAGES) ||
245 (nvs_ret == ESP_ERR_NVS_NEW_VERSION_FOUND)) {
246 ESP_ERROR_CHECK(nvs_flash_erase());
247 nvs_ret = nvs_flash_init();
248 }
249 ESP_ERROR_CHECK(nvs_ret);
250 wifi_start();
251
252 spi_bus_config_t buscfg = {};
253 buscfg.mosi_io_num = SPI_MOSI;
254 buscfg.miso_io_num = SPI_MISO;
255 buscfg.sclk_io_num = SPI_SCLK;
256 buscfg.quadwp_io_num = SPI_PIN_UNUSED;
257 buscfg.quadhd_io_num = SPI_PIN_UNUSED;
258 buscfg.max_transfer_sz = SPI_MAX_TRANSFER_SZ;
259 ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
260
261 pn532_t nfc = {};
262 pn532_config_t nfc_cfg = {};
263 nfc_cfg.spi_host = SPI2_HOST;
264 nfc_cfg.pin_cs = NFC_CS;
265 nfc_cfg.skip_bus_init = true;
266 esp_err_t nfc_ret = pn532_init(&nfc, &nfc_cfg);
267
268 if (nfc_ret == ESP_OK) {
269 ESP32Logger logger;
270 (void)logger.begin(115200UL);
271
272 ESP32CryptoProvider cryptoProvider;
273 ESP32Platform platform;
274 Pn532NfcTransport nfcTransport(&nfc, logger);
275 CryptnoxWallet wallet(nfcTransport, logger, cryptoProvider, platform);
276
277 if (wallet.begin()) {
278 run_sign_loop(wallet);
279 } else {
280 ESP_LOGE(TAG, "Wallet init failed");
281 }
282 } else {
283 ESP_LOGE(TAG, "PN532 init failed");
284 }
285}
#define WIFI_SSID
#define WIFI_PASSWORD
#define NFC_CS
Definition main.cpp:59
void app_main(void)
ESP-IDF application entry point.
Definition main.cpp:284
static EventGroupHandle_t s_wifi_event_group
Definition main.cpp:80
#define SPI_MAX_TRANSFER_SZ
Definition main.cpp:57
#define WIFI_FAIL_BIT
Definition main.cpp:78
#define SPI_MOSI
Definition main.cpp:54
#define SPI_PIN_UNUSED
Definition main.cpp:58
static const uint32_t LOOP_DELAY_MS
Definition main.cpp:73
#define SPI_MISO
Definition main.cpp:55
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
FreeRTOS event handler driving the Wi-Fi station state machine.
Definition main.cpp:95
#define WIFI_CONNECTED_BIT
Definition main.cpp:77
static int s_retry_num
Definition main.cpp:81
#define SPI_SCLK
Definition main.cpp:56
static void wifi_start(void)
Initialise Wi-Fi station mode and block until connected or timeout.
Definition main.cpp:130
CW_Logger implementation that writes to ESP32 UART0 via printf.
CW_Platform implementation for ESP32 using FreeRTOS.
CW_NfcTransport adapter wrapping the ESP-IDF PN532 NFC driver.
static void run_sign_loop(CryptnoxWallet &wallet)
Main application loop: connect, sign a test hash, and disconnect.
Definition main.cpp:169
CW_CryptoProvider backed by mbedTLS and the ESP32 hardware TRNG.
CW_Logger backed by ESP32 UART0.
Definition ESP32Logger.h:48
bool begin(unsigned long baudRate=115200UL) override
Initialise UART0 at the given baud rate.
CW_Platform backed by FreeRTOS vTaskDelay.
CW_NfcTransport implementation backed by the ESP-IDF PN532 driver.
CW_CryptoProvider implementation for ESP32 using mbedTLS and the hardware TRNG.
static const char *const TAG
#define WIFI_TIMEOUT_MS
Definition eth_rpc.cpp:28
#define WIFI_MAX_RETRY
Definition eth_rpc.cpp:27
esp_err_t pn532_init(pn532_t *dev, const pn532_config_t *config)
Initialise the PN532 and bring it to a ready state.
Definition pn532.c:657
Low-level PN532 NFC controller driver for ESP-IDF (SPI and I²C).
Compile-time configuration passed to pn532_init.
Definition pn532.h:111
spi_host_device_t spi_host
Definition pn532.h:115
bool skip_bus_init
Definition pn532.h:120
Opaque-like runtime state for a single PN532 instance.
Definition pn532.h:141