|
cryptnox-sdk-esp32 1.0.0
ESP32 SDK for Cryptnox Hardware Wallet
|
Directories | |
| main | |
Files | |
| config.template.h | |
End-to-end demonstration of the Cryptnox Hardware Wallet on an ESP32-S3: connect to a Wi-Fi access point, fetch the nonce and fee parameters over JSON-RPC, build and Keccak-256-hash the unsigned EIP-1559 transaction, sign it on the card (BIP-44 m/44'/60'/0'/0/0, secp256k1, canonical low-S), recover yParity, broadcast the signed transaction, and print the on-chain tx hash.
The private key never leaves the card. The ESP32 only ever holds the Account derived from the card's public key, the unsigned tx hash, and the resulting (r, s).
| Component | Details |
|---|---|
| Hardware Wallet | Cryptnox Hardware Wallet, initialised and seeded |
| Wallet funding | The address derived from m/44'/60'/0'/0/0 on the card needs Sepolia ETH (for gas) and Sepolia USDC. Faucets: Sepolia ETH · Circle USDC |
| NFC reader | PN532 over SPI or I²C — selected by SPI_ENABLED / I2C_ENABLED at the top of main.cpp; see hardware setup |
| Board | ESP32-S3-DevKitC-1 (or any ESP32 family — Wi-Fi required) |
| Toolchain | ESP-IDF v5.5 |
| RPC endpoint | A Sepolia JSON-RPC endpoint — PublicNode (no signup, default) or Infura |
Create main/config.h by copying the template:
Fill in at minimum: WIFI_SSID, WIFI_PASSWORD, CARD_PIN, ADDR_FROM (the address derived from m/44'/60'/0'/0/0 on the card), ADDR_TO (recipient), AMOUNT_USDC (token base units — 1 USDC = 1 000 000).
Build, flash and monitor:
Paste the final [tx] hash into Sepolia Etherscan to watch confirmation.
The ESP-IDF HTTP client uses the bundled certificate bundle (set via CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y in sdkconfig.defaults) so the RPC connection is validated against the same root store ESP-IDF applications use by default. No per-provider PEM is required as long as the endpoint chains to one of the included roots.
EIP-1559 signatures carry a 1-bit yParity instead of EIP-155's v. The card returns only r and s, so the firmware calls the ecrecover precompile at address 0x01 with v = 27 (yParity = 0). If the recovered address matches ADDR_FROM the firmware keeps yParity = 0; otherwise it retries with v = 28 (yParity = 1). One of the two will match when the card's key and ADDR_FROM are consistent.
All fields live in main/config.h (gitignored). Start from config.template.h and fill in:
| Field | Required | Example |
|---|---|---|
| WIFI_SSID | yes | "MyHomeNetwork" |
| WIFI_PASSWORD | yes | "password" |
PublicNode (free, no signup, default):
Infura (free tier, requires API key):
| Field | Example |
|---|---|
| CARD_PIN | "000000000" (must match cryptnox init) |
| ADDR_FROM | "<40 lowercase hex chars>" — your card's Ethereum address (no 0x prefix) |
ADDR_FROM must equal the address derived from m/44'/60'/0'/0/0 on the card. If they disagree, the yParity recovery loop cannot find a matching value and the firmware halts.
| Field | Default | Notes |
|---|---|---|
| ADDR_TO | "Cd7E5...c06e" | Recipient address (hex, no 0x) |
| ADDR_USDC | "1c7D4...7238" | USDC contract on Sepolia |
| CHAIN_ID_SEPOLIA | 11155111 | Hardcoded — no path to broadcast on mainnet by accident |
| AMOUNT_USDC | 1000000UL | 1 USDC (6 decimals) |
| MAX_PRIORITY_FEE | 2000000000ULL | 2 Gwei |
| MAX_FEE | 4000000000ULL | 4 Gwei |
| GAS_LIMIT_ERC20 | 60000ULL | Standard ERC-20 transfer |
After idf.py build:
| Section | Size |
|---|---|
| Flash (.text + .rodata) | ~900 KB |
| RAM at runtime | ~80 KB |
The bulk of the flash is the IDF Wi-Fi stack, mbedTLS, and the bundled CA store (~250 KB). The Cryptnox SDK itself plus the example's eth_rlp / eth_rpc / keccak256 helpers sit around ~50 KB.
| Symptom | Cause | Fix |
|---|---|---|
| esp-tls: mbedtls_ssl_handshake returned -0x2700 | RPC's chain not in the bundled root store | Switch to PublicNode (Google Trust Services R4 is bundled) or add the custom root via the certificate-bundle component |
| Wi-Fi never connects | Wrong SSID / password, or a 5 GHz-only network | ESP32-S3 is 2.4 GHz only — verify WIFI_SSID / WIFI_PASSWORD |
| tx.to is not a valid 40-char hex string | Bad hex in ADDR_TO | 40 hex chars, no 0x, lowercase preferred |
| yParity determination failed! | ADDR_FROM doesn't match the card's m/44'/60'/0'/0/0 address | Derive the address with the Cryptnox CLI and copy it into ADDR_FROM |
| RPC returns nonce too low in the JSON error.message | Stale nonce from the RPC | Wait a few seconds and re-run; the firmware fetches the nonce just before signing |
| Wrong PIN — halting to protect retry counter | CARD_PIN does not match the card | Fix CARD_PIN — do not keep retrying, every attempt burns one of the on-card tries (see VerifyPin) |
| Sign failed: 0x81 | Card has no seed | cryptnox seed generate |
cryptnox-sdk-esp32 is dual-licensed:
For commercial inquiries, contact: conta.nosp@m.ct@c.nosp@m.ryptn.nosp@m.ox.c.nosp@m.om