31static const int64_t ED_L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
32 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0,
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
38static int ct_verify32(
const uint8_t *x,
const uint8_t *y)
41 for (
int i = 0; i < 32; i++)
42 diff |= (
unsigned)(x[i] ^ y[i]);
43 return (
int)((1 & ((diff - 1) >> 8)) - 1);
49static void ed_modL(uint8_t r[32], int64_t x[64])
54 for (i = 63; i >= 32; --i)
57 for (j = i - 32; j < i - 12; ++j)
59 x[j] += carry - 16 * x[i] * ED_L[j - (i - 32)];
60 carry = (x[j] + 128) >> 8;
67 for (j = 0; j < 32; ++j)
69 x[j] += carry - (x[31] >> 4) * ED_L[j];
73 for (j = 0; j < 32; ++j)
74 x[j] -= carry * ED_L[j];
75 for (i = 0; i < 32; ++i)
77 x[i + 1] += x[i] >> 8;
78 r[i] = (uint8_t)(x[i] & 255);
83static void ed_reduce(uint8_t r[64])
86 for (
int i = 0; i < 64; i++)
87 x[i] = (int64_t)(uint64_t)r[i];
88 for (
int i = 0; i < 64; i++)
96static bool ed_scalar_canonical(
const uint8_t s[32])
98 for (
int i = 31; i >= 0; i--)
100 uint8_t li = (uint8_t)ED_L[i];
109#ifdef DETWS_FE25519_MPI_HW
113static const fe ED_D_FE = {0x135978a3, 0x75eb4dca, 0x4141d8ab, 0x00700a4d,
114 0x7779e898, 0x8cc74079, 0x2b6ffe73, 0x52036cee};
115static const fe ED_D2_FE = {0x26b2f159, 0xebd69b94, 0x8283b156, 0x00e0149a,
116 0xeef3d130, 0x198e80f2, 0x56dffce7, 0x2406d9dc};
117static const fe ED_X_FE = {0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
118 0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3};
119static const fe ED_Y_FE = {0x66666658, 0x66666666, 0x66666666, 0x66666666,
120 0x66666666, 0x66666666, 0x66666666, 0x66666666};
121static const fe ED_I_FE = {0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806,
122 0x3dfbd7a7, 0x2b4d0099, 0x4fc1df0b, 0x2b832480};
129static void edf_add(fe p[4], fe q[4])
140 fe_sub(a, p[1], p[0]);
141 fe_sub(t, q[1], q[0]);
143 fe_add(b, p[0], p[1]);
144 fe_add(t, q[0], q[1]);
146 fe_mul(c, p[3], q[3]);
147 fe_mul(c, c, ED_D2_FE);
148 fe_mul(d, p[2], q[2]);
161static void edf_cswap(fe p[4], fe q[4],
int b)
163 for (
int i = 0; i < 4; i++)
164 fe_cswap(p[i], q[i], (uint32_t)b);
168static void edf_pack(uint8_t r[32], fe p[4])
174 fe_mul(tx, p[0], zi);
175 fe_mul(ty, p[1], zi);
177 r[31] ^= (uint8_t)(fe_parity(tx) << 7);
181static void edf_scalarmult(fe p[4], fe q[4],
const uint8_t *s)
187 for (
int i = 255; i >= 0; i--)
189 int b = (s[i >> 3] >> (i & 7)) & 1;
200static void edf_comb_select(fe t[4],
int idx,
int digit)
202 int32_t sign = digit >> 31;
203 uint32_t babs = (uint32_t)((digit ^ sign) - sign);
208 for (uint32_t j = 0; j < 8; j++)
210 uint32_t x = babs ^ (j + 1);
211 uint32_t nz = (x | (0u - x)) >> 31;
212 uint32_t mask = (uint32_t)(nz - 1u);
213 for (
int k = 0; k < 8; k++)
215 t[0][k] = (t[0][k] & ~mask) | (ED_COMB[idx][j][0][k] & mask);
216 t[1][k] = (t[1][k] & ~mask) | (ED_COMB[idx][j][1][k] & mask);
217 t[3][k] = (t[3][k] & ~mask) | (ED_COMB[idx][j][2][k] & mask);
221 uint32_t neg = (uint32_t)sign;
226 fe_sub(negx, zero, t[0]);
227 fe_sub(negt, zero, t[3]);
228 for (
int k = 0; k < 8; k++)
230 t[0][k] = (t[0][k] & ~neg) | (negx[k] & neg);
231 t[3][k] = (t[3][k] & ~neg) | (negt[k] & neg);
239static void edf_scalarbase(fe p[4],
const uint8_t *s)
242 for (
int i = 0; i < 32; i++)
244 e[2 * i] = (
signed char)(s[i] & 15);
245 e[2 * i + 1] = (
signed char)((s[i] >> 4) & 15);
248 for (
int i = 0; i < 63; i++)
250 e[i] = (
signed char)(e[i] + carry);
251 carry = (e[i] + 8) >> 4;
252 e[i] = (
signed char)(e[i] - (carry << 4));
254 e[63] = (
signed char)(e[63] + carry);
261 for (
int i = 1; i < 64; i += 2)
263 edf_comb_select(t, i >> 1, e[i]);
270 for (
int i = 0; i < 64; i += 2)
272 edf_comb_select(t, i >> 1, e[i]);
278static int edf_unpackneg(fe r[4],
const uint8_t p[32])
288 fe_frombytes(r[1], p);
290 fe_mul(den, num, ED_D_FE);
291 fe_sub(num, num, r[2]);
292 fe_add(den, r[2], den);
296 fe_mul(den6, den4, den2);
297 fe_mul(t, den6, num);
303 fe_mul(r[0], t, den);
306 fe_mul(chk, chk, den);
307 if (fe_neq(chk, num))
308 fe_mul(r[0], r[0], ED_I_FE);
310 fe_mul(chk, chk, den);
311 if (fe_neq(chk, num))
314 if (fe_parity(r[0]) == (p[31] >> 7))
318 fe_sub(r[0], zero, r[0]);
320 fe_mul(r[3], r[0], r[1]);
325static void ed_scalarbase_bytes(uint8_t out[32],
const uint8_t s[32])
329 edf_scalarbase(p, s);
335static bool ed_verify_recompute(uint8_t out[32],
const uint8_t S[32],
const uint8_t h[32],
const uint8_t pub[32])
341 if (edf_unpackneg(q, pub) != 0)
346 edf_scalarmult(p, q, h);
347 edf_scalarbase(sb, S);
356static const ssh_gf GF0 = {0};
357static const ssh_gf GF1 = {1};
359static const ssh_gf ED_D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070,
360 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203};
361static const ssh_gf ED_D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0,
362 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406};
364static const ssh_gf ED_X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c,
365 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169};
366static const ssh_gf ED_Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666,
367 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
369static const ssh_gf ED_I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43,
370 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
373static int gf_parity(
const ssh_gf a)
387 return ct_verify32(c, d);
395 for (
int i = 250; i >= 0; i--)
439 for (
int i = 0; i < 4; i++)
444static void ed_pack(uint8_t r[32],
ssh_gf p[4])
453 r[31] ^= (uint8_t)(gf_parity(tx) << 7);
457static void ed_scalarmult(
ssh_gf p[4],
ssh_gf q[4],
const uint8_t *s)
463 for (
int i = 255; i >= 0; i--)
465 int b = (s[i >> 3] >> (i & 7)) & 1;
474static void ed_scalarbase(
ssh_gf p[4],
const uint8_t *s)
481 ed_scalarmult(p, q, s);
486static int ed_unpackneg(
ssh_gf r[4],
const uint8_t p[32])
515 if (gf_neq(chk, num))
519 if (gf_neq(chk, num))
522 if (gf_parity(r[0]) == (p[31] >> 7))
529static void ed_scalarbase_bytes(uint8_t out[32],
const uint8_t s[32])
537static bool ed_verify_recompute(uint8_t out[32],
const uint8_t S[32],
const uint8_t h[32],
const uint8_t pub[32])
542 if (ed_unpackneg(q, pub) != 0)
544 ed_scalarmult(p, q, h);
545 ed_scalarbase(sb, S);
561 ed_scalarbase_bytes(pub, d);
564void ssh_ed25519_sign(uint8_t sig[64],
const uint8_t *msg,
size_t mlen,
const uint8_t seed[32])
576 ed_scalarbase_bytes(pub, d);
587 ed_scalarbase_bytes(sig, r);
599 for (
int i = 0; i < 64; i++)
601 for (
int i = 0; i < 32; i++)
602 x[i] = (int64_t)(uint64_t)r[i];
603 for (
int i = 0; i < 32; i++)
604 for (
int j = 0; j < 32; j++)
605 x[i + j] += (int64_t)(uint64_t)h[i] * (int64_t)(uint64_t)d[j];
606 ed_modL(sig + 32, x);
609bool ssh_ed25519_verify(
const uint8_t pub[32],
const uint8_t *msg,
size_t mlen,
const uint8_t sig[64])
611 if (!ed_scalar_canonical(sig + 32))
625 if (!ed_verify_recompute(t, sig + 32, h, pub))
627 return ct_verify32(sig, t) == 0;
void ssh_gf_cswap(ssh_gf p, ssh_gf q, int b)
constant-time conditional swap of p,q when b==1
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_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)).
void ssh_ed25519_sign(uint8_t sig[64], const uint8_t *msg, size_t mlen, const uint8_t seed[32])
bool ssh_ed25519_verify(const uint8_t pub[32], const uint8_t *msg, size_t mlen, const uint8_t sig[64])
void ssh_ed25519_pubkey(uint8_t pub[32], const uint8_t seed[32])
Ed25519 signatures (RFC 8032) for ssh-ed25519 host keys + client auth.
ESP32-S3 GF(2^255-19) field layer on the RSA/MPI hardware accelerator (X25519 + Ed25519).
void ssh_sha512_final(SshSha512Ctx *ctx, uint8_t digest[SSH_SHA512_DIGEST_LEN])
Finalize the hash and write the 64-byte digest. The context is undefined afterwards; call init() agai...
void ssh_sha512_init(SshSha512Ctx *ctx)
Initialize a streaming SHA-512 context (ctx must not be NULL).
void ssh_sha512(const uint8_t *data, size_t len, uint8_t digest[SSH_SHA512_DIGEST_LEN])
One-shot SHA-512: hash len bytes of data into digest (64 bytes).
void ssh_sha512_update(SshSha512Ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
SHA-512 (FIPS 180-4) - streaming context and one-shot API.
Streaming SHA-512 context.