cryptnox-sdk-esp32 1.0.0
ESP32 SDK for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
uECC_esp32.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
6#include "uECC.h"
7#include "CW_Utils.h"
8#include "mbedtls/ecp.h"
9#include "mbedtls/ecdsa.h"
10#include "esp_log.h"
11#include <algorithm>
12
13/******************************************************************
14 * 1. Module constants
15 ******************************************************************/
16
17#define COORD_SIZE_BYTES (32U) /* bytes per coordinate (256-bit curve) */
18static const char* const UECC_LOG_TAG = "uECC_esp32";
19#define ECC_XY_KEY_SIZE (COORD_SIZE_BYTES * 2U) /* X[32] || Y[32] without 0x04 prefix */
20#define UNCOMPRESSED_PUB_SIZE (65U) /* 0x04 || X[32] || Y[32] */
21#define UNCOMPRESSED_PREFIX (0x04U)
22#define POINT_PREFIX_OFFSET (0U) /* byte offset of the 0x04 prefix */
23#define COORD_X_OFFSET (1U) /* byte offset of X in 65-byte key */
24#define RAW_SIG_R_OFFSET (0U) /* byte offset of r in 64-byte raw sig */
25#define RAW_SIG_S_OFFSET (32U) /* byte offset of s in 64-byte raw sig */
26#define UECC_SUCCESS (1)
27#define UECC_FAILURE (0)
28#define MBEDTLS_OK (0)
29#define RNG_ERROR (-1) /* returned by RNG callback on invalid arguments */
30
31/******************************************************************
32 * 2. uECC_Curve_t definition (opaque in uECC.h)
33 ******************************************************************/
34
36 mbedtls_ecp_group_id grp_id;
37};
38
39/******************************************************************
40 * 3. Static curve instances
41 ******************************************************************/
42
43static const uECC_Curve_t s_secp256r1 = { MBEDTLS_ECP_DP_SECP256R1 };
44static const uECC_Curve_t s_secp256k1 = { MBEDTLS_ECP_DP_SECP256K1 };
45
46/******************************************************************
47 * 4. Internal RNG adapter for mbedTLS
48 ******************************************************************/
49
50static int esp32_mbedtls_rng(void *ctx, unsigned char *output, size_t len) {
51 int result = RNG_ERROR;
52 (void)ctx;
53
54 if ((output != NULL) && (len > 0U)) {
55 bool rng_result = CW_Utils::fill_secure_random(
56 reinterpret_cast<uint8_t *>(output), len);
57 if (rng_result) {
58 result = MBEDTLS_OK;
59 }
60 }
61
62 return result;
63}
64
65/******************************************************************
66 * 5. Public API
67 ******************************************************************/
68
71 return &s_secp256r1;
72}
73
76 return &s_secp256k1;
77}
78
80void uECC_set_rng(uECC_RNG_Function rng_function) {
81 if (rng_function != NULL) {
82 /* The caller's RNG callback is intentionally ignored: ESP32 routes all
83 * entropy through mbedTLS and the hardware TRNG directly (SEC-018).
84 * Log once so the drop is visible in debug output rather than silent. */
85 ESP_LOGW(UECC_LOG_TAG,
86 "uECC_set_rng: callback ignored — ESP32 uses hardware RNG internally");
87 }
88 (void)rng_function;
89}
90
92int uECC_make_key(uint8_t *public_key, uint8_t *private_key,
93 const uECC_Curve_t *curve) {
94 int result = UECC_FAILURE;
95
96 if ((public_key != NULL) && (private_key != NULL) && (curve != NULL)) {
97 mbedtls_ecp_group grp = {};
98 mbedtls_mpi d = {};
99 mbedtls_ecp_point Q = {};
100
101 mbedtls_ecp_group_init(&grp);
102 mbedtls_mpi_init(&d);
103 mbedtls_ecp_point_init(&Q);
104
105 int ret = mbedtls_ecp_group_load(&grp, curve->grp_id);
106
107 if (ret == MBEDTLS_OK) {
108 ret = mbedtls_ecp_gen_keypair(&grp, &d, &Q,
109 esp32_mbedtls_rng, NULL);
110 }
111
112 if (ret == MBEDTLS_OK) {
113 ret = mbedtls_mpi_write_binary(&d, private_key,
114 static_cast<size_t>(COORD_SIZE_BYTES));
115 }
116
117 if (ret == MBEDTLS_OK) {
118 uint8_t pub65[UNCOMPRESSED_PUB_SIZE] = { 0U };
119 size_t olen = 0U;
120 ret = mbedtls_ecp_point_write_binary(&grp, &Q,
121 MBEDTLS_ECP_PF_UNCOMPRESSED,
122 &olen,
123 pub65, sizeof(pub65));
124 if (ret == MBEDTLS_OK) {
125 (void)std::copy_n(pub65 + COORD_X_OFFSET,
126 static_cast<size_t>(ECC_XY_KEY_SIZE),
127 public_key);
128 }
129 }
130
131 if (ret == MBEDTLS_OK) {
132 result = UECC_SUCCESS;
133 }
134
135 mbedtls_ecp_point_free(&Q);
136 mbedtls_mpi_free(&d);
137 mbedtls_ecp_group_free(&grp);
138 }
139
140 return result;
141}
142
144int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
145 uint8_t *secret, const uECC_Curve_t *curve) {
146 int result = UECC_FAILURE;
147
148 if ((public_key != NULL) && (private_key != NULL) &&
149 (secret != NULL) && (curve != NULL)) {
150 mbedtls_ecp_group grp = {};
151 mbedtls_ecp_point remote_Q = {};
152 mbedtls_mpi local_d = {};
153 mbedtls_ecp_point shared_R = {};
154
155 mbedtls_ecp_group_init(&grp);
156 mbedtls_ecp_point_init(&remote_Q);
157 mbedtls_mpi_init(&local_d);
158 mbedtls_ecp_point_init(&shared_R);
159
160 int ret = mbedtls_ecp_group_load(&grp, curve->grp_id);
161
162 if (ret == MBEDTLS_OK) {
163 uint8_t pub65[UNCOMPRESSED_PUB_SIZE] = { 0U };
165 (void)std::copy_n(public_key,
166 static_cast<size_t>(ECC_XY_KEY_SIZE),
167 pub65 + COORD_X_OFFSET);
168 ret = mbedtls_ecp_point_read_binary(&grp, &remote_Q,
169 pub65, sizeof(pub65));
170 }
171
172 if (ret == MBEDTLS_OK) {
173 ret = mbedtls_mpi_read_binary(&local_d, private_key,
174 static_cast<size_t>(COORD_SIZE_BYTES));
175 }
176
177 if (ret == MBEDTLS_OK) {
178 ret = mbedtls_ecp_mul(&grp, &shared_R, &local_d, &remote_Q,
179 esp32_mbedtls_rng, NULL);
180 }
181
182 if (ret == MBEDTLS_OK) {
183 uint8_t shared65[UNCOMPRESSED_PUB_SIZE] = { 0U };
184 size_t olen = 0U;
185 ret = mbedtls_ecp_point_write_binary(&grp, &shared_R,
186 MBEDTLS_ECP_PF_UNCOMPRESSED,
187 &olen,
188 shared65, sizeof(shared65));
189 if (ret == MBEDTLS_OK) {
190 (void)std::copy_n(shared65 + COORD_X_OFFSET,
191 static_cast<size_t>(COORD_SIZE_BYTES),
192 secret);
193 }
194 }
195
196 if (ret == MBEDTLS_OK) {
197 result = UECC_SUCCESS;
198 }
199
200 mbedtls_ecp_point_free(&shared_R);
201 mbedtls_mpi_free(&local_d);
202 mbedtls_ecp_point_free(&remote_Q);
203 mbedtls_ecp_group_free(&grp);
204 }
205
206 return result;
207}
208
210int uECC_verify(const uint8_t *public_key, const uint8_t *hash, unsigned hash_size,
211 const uint8_t *signature, const uECC_Curve_t *curve) {
212 int result = UECC_FAILURE;
213
214 if ((public_key != NULL) && (hash != NULL) &&
215 (signature != NULL) && (curve != NULL)) {
216 mbedtls_ecp_group grp = {};
217 mbedtls_ecp_point Q = {};
218 mbedtls_mpi r = {};
219 mbedtls_mpi s = {};
220
221 mbedtls_ecp_group_init(&grp);
222 mbedtls_ecp_point_init(&Q);
223 mbedtls_mpi_init(&r);
224 mbedtls_mpi_init(&s);
225
226 int ret = mbedtls_ecp_group_load(&grp, curve->grp_id);
227
228 if (ret == MBEDTLS_OK) {
229 uint8_t pub65[UNCOMPRESSED_PUB_SIZE] = { 0U };
231 (void)std::copy_n(public_key,
232 static_cast<size_t>(ECC_XY_KEY_SIZE),
233 pub65 + COORD_X_OFFSET);
234 ret = mbedtls_ecp_point_read_binary(&grp, &Q,
235 pub65, sizeof(pub65));
236 }
237
238 if (ret == MBEDTLS_OK) {
239 ret = mbedtls_mpi_read_binary(&r,
240 signature + RAW_SIG_R_OFFSET,
241 static_cast<size_t>(COORD_SIZE_BYTES));
242 }
243
244 if (ret == MBEDTLS_OK) {
245 ret = mbedtls_mpi_read_binary(&s,
246 signature + RAW_SIG_S_OFFSET,
247 static_cast<size_t>(COORD_SIZE_BYTES));
248 }
249
250 if (ret == MBEDTLS_OK) {
251 ret = mbedtls_ecdsa_verify(&grp, hash,
252 static_cast<size_t>(hash_size),
253 &Q, &r, &s);
254 }
255
256 if (ret == MBEDTLS_OK) {
257 result = UECC_SUCCESS;
258 }
259
260 mbedtls_mpi_free(&s);
261 mbedtls_mpi_free(&r);
262 mbedtls_ecp_point_free(&Q);
263 mbedtls_ecp_group_free(&grp);
264 }
265
266 return result;
267}
#define MBEDTLS_OK
#define UECC_SUCCESS
mbedtls_ecp_group_id grp_id
int(* uECC_RNG_Function)(uint8_t *dest, unsigned size)
Definition uECC.h:32
int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uint8_t *secret, const uECC_Curve_t *curve)
Compute ECDH shared secret (X-coordinate of privKey * pubKey).
#define RAW_SIG_S_OFFSET
#define UNCOMPRESSED_PREFIX
#define RAW_SIG_R_OFFSET
#define RNG_ERROR
#define UECC_FAILURE
const uECC_Curve_t * uECC_secp256k1(void)
Return the static secp256k1 curve descriptor.
#define ECC_XY_KEY_SIZE
const uECC_Curve_t * uECC_secp256r1(void)
Return the static secp256r1 curve descriptor.
#define POINT_PREFIX_OFFSET
static int esp32_mbedtls_rng(void *ctx, unsigned char *output, size_t len)
#define COORD_SIZE_BYTES
void uECC_set_rng(uECC_RNG_Function rng_function)
No-op: ESP32 hardware RNG is used internally; no external callback needed.
#define COORD_X_OFFSET
static const char *const UECC_LOG_TAG
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, const uECC_Curve_t *curve)
Generate an ECC key pair using mbedTLS and the ESP32 hardware RNG.
int uECC_verify(const uint8_t *public_key, const uint8_t *hash, unsigned hash_size, const uint8_t *signature, const uECC_Curve_t *curve)
Verify an ECDSA signature (raw 64-byte r||s) against a hash.
#define UNCOMPRESSED_PUB_SIZE
static const uECC_Curve_t s_secp256r1
static const uECC_Curve_t s_secp256k1