cryptnox-sdk-arduino 1.0.0
Arduino library for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
Sign.ino

Minimal Cryptnox example: sign a 32-byte hash on the secp256k1 curve.

Minimal Cryptnox example: sign a 32-byte hash on the secp256k1 curve.Wiring & prerequisites:

  • PN532 NFC reader on SPI, with SS on pin PN532_SS_PIN.
  • A Cryptnox card initialised with a known PIN AND a loaded seed (use the Cryptnox CLI: cryptnox init then cryptnox seed generate).
  • DEMO_PIN must match the PIN set on the card.

What the sketch does in each loop iteration:

  1. Connect to the card and establish the secure channel.
  2. Sign a 32-byte hash on the secp256k1 curve (key type CW_SIGN_CURR_K1, signature type CW_SIGN_SIG_ECDSA_LOW_S, PIN included in the sign payload CW_SIGN_WITH_PIN).
  3. Print the result, securely wipe local secrets, disconnect.
Warning
On CW_SIGN_PIN_INCORRECT (0x82) the sketch enters an infinite halt: every wrong PIN attempt decrements the card's retry counter and reaching 0 permanently blocks the PIN. Recovery then requires the PUK via cryptnox unblock_pin. Verify DEMO_PIN before retrying.
Note
The PIN "000000000" used by the project examples is a demo placeholder. In real deployments set a strong PIN, never commit source files containing a real PIN, and keep this value out of any version-controlled config.
The hash filled with 0x01 below is a test pattern. In real use replace it with the SHA-256 (or Keccak-256 for Ethereum) digest of the transaction you want the card to sign.
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
* Copyright (c) 2026 Cryptnox SA
*/
#include <CryptnoxWallet.h>
#include <SPI.h>
#define PN532_SS_PIN (10U)
#define DEMO_PIN "000000000"
void setup() {
serialAdapter.begin(115200);
delay(1000); /* Arduino R4: wait for Serial */
SPI.begin();
if (!wallet.begin()) {
serialAdapter.println(F("PN532 init failed"));
while (1);
}
}
void loop() {
if (!wallet.connect(session)) {
serialAdapter.println(F("Card not detected"));
wallet.disconnect(session);
delay(1000);
return;
}
uint8_t hash[CW_HASH_SIZE];
memset(hash, 0x01, sizeof(hash)); /* replace with SHA-256 of your tx */
CW_SignRequest req(session,
req.hash = hash;
req.hashLength = sizeof(hash);
CW_Utils::safe_memcpy(req.pin, sizeof(req.pin),
reinterpret_cast<const uint8_t*>(DEMO_PIN), strlen(DEMO_PIN));
CW_SignResult sig = wallet.sign(req);
if (sig.errorCode == CW_OK) {
serialAdapter.println(F("Signature OK"));
serialAdapter.print(F(" r = "));
for (uint8_t i = 0U; i < 32U; i++) {
uint8_t b = sig.signature[CW_SIG_R_OFFSET + i];
if (b < 0x10U) { serialAdapter.print(F("0")); }
serialAdapter.print(b, HEX);
}
serialAdapter.println();
serialAdapter.print(F(" s = "));
for (uint8_t i = 0U; i < 32U; i++) {
uint8_t b = sig.signature[CW_SIG_S_OFFSET + i];
if (b < 0x10U) { serialAdapter.print(F("0")); }
serialAdapter.print(b, HEX);
}
serialAdapter.println();
serialAdapter.print(F(" errorCode = 0x"));
serialAdapter.println(sig.errorCode, HEX);
} else if (sig.errorCode == CW_SIGN_PIN_INCORRECT) {
/* CRITICAL: do NOT loop — each wrong PIN attempt burns a retry. */
serialAdapter.println(F("Wrong PIN — halting to protect retry counter"));
CW_Utils::secure_wipe(hash, sizeof(hash));
wallet.disconnect(session);
while (1);
} else {
serialAdapter.print(F("Sign failed: 0x"));
serialAdapter.println(sig.errorCode, HEX);
}
CW_Utils::secure_wipe(hash, sizeof(hash));
wallet.disconnect(session);
delay(1000);
}
void setup()
Arduino setup function.
CryptnoxWallet wallet(nfc, serialAdapter, cryptoProvider, platform)
PN532Adapter nfc(serialAdapter, PN532_SS, &SPI)
ArduinoLoggerAdapter serialAdapter
ArduinoPlatform platform
ArduinoCryptoProvider cryptoProvider
void loop()
Arduino main loop.
#define CW_SIG_R_OFFSET
Definition CW_Defs.h:116
#define CW_HASH_SIZE
Definition CW_Defs.h:108
#define CW_OK
Definition CW_Defs.h:80
#define CW_SIGN_WITH_PIN
Definition CW_Defs.h:92
#define CW_SIGN_CURR_K1
Definition CW_Defs.h:85
#define CW_SIGN_SIG_ECDSA_LOW_S
Definition CW_Defs.h:96
#define CW_SIG_S_OFFSET
Definition CW_Defs.h:117
#define CW_SIGN_PIN_INCORRECT
Definition CW_Defs.h:103
#define PN532_SS_PIN
SPI slave-select (CS) pin connected to the PN532 module.
Definition Connect.ino:31
#define DEMO_PIN
Demo PIN used by this example. Must match the PIN that the card was initialised with (4–9 ASCII digit...
Definition Sign.ino:50
CW_CryptoProvider implementation for the Arduino UNO R4 (RA4M1).
CW_Logger implementation wrapping Arduino's HardwareSerial.
CW_Platform implementation using Arduino's blocking delay().
static bool safe_memcpy(uint8_t *dst, size_t dstSize, const uint8_t *src, size_t count)
Safe memcpy — validates pointers, sizes, and checks for overlap.
Definition CW_Utils.cpp:50
static void secure_wipe(uint8_t *buf, size_t len)
Securely zero a buffer, guaranteed not to be optimised away.
Definition CW_Utils.cpp:37
High-level interface for interacting with a Cryptnox Hardware Wallet over NFC.
CW_NfcTransport implementation over the Adafruit_PN532 driver.
#define F(string_literal)
#define HEX
Holds cryptographic session state for reentrant secure channel operations.
Definition CW_Defs.h:168
Request parameters for CryptnoxWallet::sign.
Result of CryptnoxWallet::sign.
uint8_t signature[CW_RAW_SIGNATURE_SIZE]