28#include <mbedtls/bignum.h>
33#ifndef DETWS_FE25519_MPI_HW
34static const ssh_gf GF_121665 = {0xDB41, 1};
39static void gf_carry(
ssh_gf o)
41 for (
int i = 0; i < 16; i++)
43 o[i] += (int64_t)1 << 16;
44 int64_t c = o[i] >> 16;
45 o[(i + 1) * (i < 15)] += c - 1 + 37 * (c - 1) * (i == 15);
52 for (
int i = 0; i < 16; i++)
58 for (
int i = 0; i < 16; i++)
64 for (
int i = 0; i < 16; i++)
68#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_IDF_TARGET_ESP32S3
79static void gf_balance_s16(int16_t o[16],
const ssh_gf a)
84 for (
int i = 0; i < 16; i++)
86 for (
int pass = 0; pass < 3; pass++)
89 for (
int i = 0; i < 16; i++)
91 int32_t v = c[i] + carry;
92 carry = (v + 0x8000) >> 16;
93 c[i] = v - (carry << 16);
97 for (
int i = 0; i < 16; i++)
103static inline int64_t gf_accx_dot_win(
const int16_t *as,
const int16_t *w)
106 const int16_t *pa = as, *pw = w;
107 asm volatile(
"ee.zero.accx\n"
108 "ee.vld.128.ip q3, %[a], 16\n"
109 "ee.ld.128.usar.ip q0, %[w], 16\n"
110 "ee.ld.128.usar.ip q1, %[w], 16\n"
111 "ee.src.q q2, q0, q1\n"
112 "ee.vmulas.s16.accx q3, q2\n"
113 "ee.vld.128.ip q3, %[a], 16\n"
114 "ee.ld.128.usar.ip q0, %[w], 16\n"
115 "ee.src.q q2, q1, q0\n"
116 "ee.vmulas.s16.accx q3, q2\n"
119 : [lo]
"=&r"(lo), [hi]
"=&r"(hi), [a]
"+r"(pa), [w]
"+r"(pw)
122 uint64_t raw = (uint64_t)lo | ((uint64_t)(uint8_t)hi << 32);
123 return ((int64_t)(raw << 24)) >> 24;
128static void gf_conv_finish(
ssh_gf out,
const int16_t *as,
const int16_t *bs)
131 __attribute__((aligned(16))) int16_t bp[64];
132 for (
int i = 0; i < 64; i++)
134 for (
int m = 0; m < 16; m++)
135 bp[15 + m] = bs[15 - m];
137 for (
int k = 0; k < 31; k++)
138 t[k] = gf_accx_dot_win(as, bp + (30 - k));
139 for (
int i = 0; i < 15; i++)
140 t[i] += 38 * t[i + 16];
141 for (
int i = 0; i < 16; i++)
149 __attribute__((aligned(16))) int16_t as[16];
151 gf_balance_s16(as, a);
152 gf_balance_s16(bs, b);
153 gf_conv_finish(out, as, bs);
161 __attribute__((aligned(16))) int16_t as[16];
162 gf_balance_s16(as, a);
163 gf_conv_finish(out, as, as);
169 for (
int i = 0; i < 31; i++)
175 for (
int i = 0; i < 16; i++)
177 int32_t ai = (int32_t)a[i];
178 for (
int j = 0; j < 16; j++)
179 t[i + j] += (int64_t)ai * (int32_t)b[j];
181 for (
int i = 0; i < 15; i++)
182 t[i] += 38 * t[i + 16];
183 for (
int i = 0; i < 16; i++)
190#if !(defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_IDF_TARGET_ESP32S3)
204 for (
int i = 253; i >= 0; i--)
207 if (i != 2 && i != 4)
215static const uint8_t P25519_BE[32] = {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed};
218static const uint8_t P25519_MINUS2_BE[32] = {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb};
233 for (
int i = 0; i < 32; i++)
240 mbedtls_mpi_init(&A);
241 mbedtls_mpi_init(&E);
242 mbedtls_mpi_init(&N);
243 mbedtls_mpi_init(&X);
244 bool ok = mbedtls_mpi_read_binary(&A, be, 32) == 0 && mbedtls_mpi_read_binary(&E, P25519_MINUS2_BE, 32) == 0 &&
245 mbedtls_mpi_read_binary(&N, P25519_BE, 32) == 0 && mbedtls_mpi_exp_mod(&X, &A, &E, &N,
nullptr) == 0 &&
246 mbedtls_mpi_write_binary(&X, be, 32) == 0;
247 mbedtls_mpi_free(&A);
248 mbedtls_mpi_free(&E);
249 mbedtls_mpi_free(&N);
250 mbedtls_mpi_free(&X);
256 for (
int i = 0; i < 32; i++)
270 int64_t mask = ~((int64_t)b - 1);
271 for (
int i = 0; i < 16; i++)
273 int64_t t = mask & (p[i] ^ q[i]);
289 for (
int j = 0; j < 2; j++)
291 m[0] = t[0] - 0xffed;
292 for (
int i = 1; i < 15; i++)
294 m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
297 m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
298 int b = (int)((m[15] >> 16) & 1);
302 for (
int i = 0; i < 16; i++)
304 out[2 * i] = (uint8_t)(t[i] & 0xff);
305 out[2 * i + 1] = (uint8_t)(t[i] >> 8);
312 for (
int i = 0; i < 16; i++)
313 out[i] = (int64_t)in[2 * i] + ((int64_t)in[2 * i + 1] << 8);
317#ifdef DETWS_FE25519_MPI_HW
321static const uint32_t FE_A24[8] = {121665u, 0, 0, 0, 0, 0, 0, 0};
323void ssh_x25519(uint8_t out[32],
const uint8_t scalar[32],
const uint8_t point[32])
326 for (
int i = 0; i < 32; i++)
350 fe_frombytes(x1, point);
358 for (
int t = 254; t >= 0; t--)
360 uint32_t k_t = (e[t >> 3] >> (t & 7)) & 1;
362 fe_cswap(x2, x3, swap);
363 fe_cswap(z2, z3, swap);
380 fe_mul(t0, FE_A24, E);
384 fe_cswap(x2, x3, swap);
385 fe_cswap(z2, z3, swap);
394void ssh_x25519(uint8_t out[32],
const uint8_t scalar[32],
const uint8_t point[32])
397 for (
int i = 0; i < 31; i++)
399 z[31] = (uint8_t)((scalar[31] & 127) | 64);
410 for (
int i = 0; i < 16; i++)
413 a[i] = c[i] = d[i] = 0;
418 for (
int i = 254; i >= 0; i--)
420 int r = (z[i >> 3] >> (i & 7)) & 1;
454 uint8_t base[32] = {9};
void ssh_gf_cswap(ssh_gf p, ssh_gf q, int b)
constant-time conditional swap of p,q when b==1
void ssh_x25519_base(uint8_t out[32], const uint8_t scalar[32])
X25519 with the standard base point u=9: out = scalar * G.
void ssh_gf_add(ssh_gf out, const ssh_gf a, const ssh_gf b)
out = a + b (unreduced)
void ssh_gf_mul(ssh_gf out, const ssh_gf a, const ssh_gf b)
out = a * b mod p
void ssh_gf_unpack(ssh_gf out, const uint8_t in[32])
decode 32 bytes (high bit ignored)
void ssh_gf_copy(ssh_gf out, const ssh_gf in)
out = in
void ssh_gf_pack(uint8_t out[32], const ssh_gf a)
canonical little-endian 32-byte encoding
void ssh_gf_sub(ssh_gf out, const ssh_gf a, const ssh_gf b)
out = a - b (unreduced)
void ssh_x25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32])
X25519 scalar multiplication: out = scalar * point (RFC 7748 §5).
void ssh_gf_sq(ssh_gf out, const ssh_gf a)
out = a^2 mod p
void ssh_gf_inv(ssh_gf out, const ssh_gf a)
out = a^-1 mod p (= a^(p-2))
Curve25519 field arithmetic + X25519 (RFC 7748) for the curve25519-sha256 KEX.
int64_t ssh_gf[16]
A field element of GF(2^255 - 19): 16 limbs, radix 2^16 (limb i weighs 2^(16i)).
ESP32-S3 GF(2^255-19) field layer on the RSA/MPI hardware accelerator (X25519 + Ed25519).