28#if PC_ENABLE_SSH_SNTRUP761
43#define PC_SNTRUP_P 761
44#define PC_SNTRUP_Q 4591
45#define PC_SNTRUP_W 286
46#define PC_Q12 ((PC_SNTRUP_Q - 1) / 2)
47#define PC_HASH_BYTES 32
48#define PC_SMALL_BYTES ((PC_SNTRUP_P + 3) / 4)
49#define PC_CONFIRM_BYTES 32
50#define PC_CT_BYTES PC_SNTRUP761_CT_BYTES
51#define PC_PK_BYTES PC_SNTRUP761_PK_BYTES
53typedef int8_t small_t;
61small_t F3_freeze(int16_t x)
63 return (small_t)(x - 3 * ((10923 * x + 16384) >> 15));
66Fq Fq_freeze(int32_t x)
68 const int32_t q16 = (0x10000 + PC_SNTRUP_Q / 2) / PC_SNTRUP_Q;
69 const int32_t q20 = (0x100000 + PC_SNTRUP_Q / 2) / PC_SNTRUP_Q;
70 const int32_t q28 = (0x10000000 + PC_SNTRUP_Q / 2) / PC_SNTRUP_Q;
71 x -= PC_SNTRUP_Q * ((q16 * x) >> 16);
72 x -= PC_SNTRUP_Q * ((q20 * x) >> 20);
73 return (Fq)(x - PC_SNTRUP_Q * ((q28 * x + 0x8000000) >> 28));
77inline int32_t negative_mask(int32_t x)
79 return -(int32_t)((uint32_t)x >> 31);
82void uint32_divmod_uint14(uint32_t *Qout, uint16_t *rout, uint32_t x, uint16_t m)
84 uint32_t qpart,
mask, v = 0x80000000u / m;
85 qpart = (uint32_t)((x * (uint64_t)v) >> 31);
88 qpart = (uint32_t)((x * (uint64_t)v) >> 31);
93 mask = (uint32_t)negative_mask((int32_t)x);
94 x +=
mask & (uint32_t)m;
99uint16_t uint32_mod_uint14(uint32_t x, uint16_t m)
103 uint32_divmod_uint14(&Qq, &r, x, m);
108uint8_t *Encode(uint8_t *out,
const uint16_t *R,
const uint16_t *M,
int len, uint16_t *scr)
112 uint16_t r = R[0], m = M[0];
117 m = (uint16_t)((m + 255) >> 8);
121 int half = (len + 1) / 2;
122 uint16_t *
R2 = scr, *M2 = scr + half;
124 for (i = 0; i + 1 < len; i += 2)
127 uint32_t r = (uint32_t)R[i] + (uint32_t)R[i + 1] * m0;
128 uint32_t m = (uint32_t)M[i + 1] * m0;
135 R2[i / 2] = (uint16_t)r;
136 M2[i / 2] = (uint16_t)m;
143 return Encode(out,
R2, M2, half, scr + 2 * half);
147void Decode(uint16_t *out,
const uint8_t *S,
const uint16_t *M,
int len, uint16_t *scr, uint32_t *scr32)
161 else if (M[0] <= 256)
163 out[0] = uint32_mod_uint14(S[0], M[0]);
167 out[0] = uint32_mod_uint14((uint32_t)S[0] + ((uint32_t)(uint16_t)S[1] << 8), M[0]);
171 int half = (len + 1) / 2;
172 uint16_t *
R2 = scr, *M2 = scr + half, *bottomr = scr + 2 * half;
173 uint32_t *bottomt = scr32;
175 for (i = 0; i + 1 < len; i += 2)
177 uint32_t m = (uint32_t)M[i] * (uint32_t)M[i + 1];
180 bottomt[i / 2] = 256 * 256;
181 bottomr[i / 2] = (uint16_t)(S[0] + 256 * S[1]);
183 M2[i / 2] = (uint16_t)((((m + 255) >> 8) + 255) >> 8);
190 bottomt[i / 2] = 256;
191 bottomr[i / 2] = S[0];
193 M2[i / 2] = (uint16_t)((m + 255) >> 8);
199 M2[i / 2] = (uint16_t)m;
206 Decode(
R2, S, M2, half, scr + 3 * half, scr32 + half);
207 for (i = 0; i + 1 < len; i += 2)
209 uint32_t r1, r = bottomr[i / 2];
211 r += bottomt[i / 2] *
R2[i / 2];
212 uint32_divmod_uint14(&r1, &r0, r, M[i]);
213 r1 = uint32_mod_uint14(r1, M[i + 1]);
215 *out++ = (uint16_t)r1;
224void Rq_mult_small(Fq *h,
const Fq *f,
const small_t *g)
226 int32_t fg[PC_SNTRUP_P + PC_SNTRUP_P - 1];
228 for (i = 0; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
232 for (i = 0; i < PC_SNTRUP_P; ++i)
234 for (j = 0; j < PC_SNTRUP_P; ++j)
236 fg[i + j] += f[i] * (int32_t)g[j];
239 for (i = PC_SNTRUP_P; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
241 fg[i - PC_SNTRUP_P] += fg[i];
243 for (i = PC_SNTRUP_P; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
245 fg[i - PC_SNTRUP_P + 1] += fg[i];
247 for (i = 0; i < PC_SNTRUP_P; ++i)
249 h[i] = Fq_freeze(fg[i]);
253void Round(Fq *out,
const Fq *a)
255 for (
int i = 0; i < PC_SNTRUP_P; ++i)
257 out[i] = (Fq)(a[i] - F3_freeze(a[i]));
262inline void int32_minmax(int32_t *pp, int32_t *pq)
264 int32_t x = *pp, y = *pq;
265 int64_t d = (int64_t)y - (int64_t)x;
268 int32_t swap = -(int32_t)((uint64_t)d >> 63) & (x ^ y);
273void crypto_sort_int32(int32_t *x,
long long n)
275 long long top, p, q, r, i, j;
283 while (top < n - top)
287 for (p = top; p >= 1; p >>= 1)
290 while (i + 2 * p <= n)
292 for (j = i; j < i + p; ++j)
294 int32_minmax(&x[j], &x[j + p]);
298 for (j = i; j < n - p; ++j)
300 int32_minmax(&x[j], &x[j + p]);
304 for (q = top; q > p; q >>= 1)
320 int32_t a = x[j + p];
321 for (r = q; r > p; r >>= 1)
323 int32_minmax(&a, &x[j + r]);
334 while (i + p <= n - q)
336 for (j = i; j < i + p; ++j)
338 int32_t a = x[j + p];
339 for (r = q; r > p; r >>= 1)
341 int32_minmax(&a, &x[j + r]);
350 int32_t a = x[j + p];
351 for (r = q; r > p; r >>= 1)
353 int32_minmax(&a, &x[j + r]);
363void crypto_sort_uint32(uint32_t *x,
long long n)
365 for (
long long j = 0; j < n; ++j)
369 crypto_sort_int32((int32_t *)x, n);
370 for (
long long j = 0; j < n; ++j)
376void Short_fromlist(small_t *out,
const uint32_t *in)
378 uint32_t L[PC_SNTRUP_P];
380 for (i = 0; i < PC_SNTRUP_W; ++i)
382 L[i] = in[i] & (uint32_t)-2;
384 for (i = PC_SNTRUP_W; i < PC_SNTRUP_P; ++i)
386 L[i] = (in[i] & (uint32_t)-3) | 1;
388 crypto_sort_uint32(L, PC_SNTRUP_P);
389 for (i = 0; i < PC_SNTRUP_P; ++i)
391 out[i] = (small_t)((L[i] & 3) - 1);
395void Short_random(small_t *out)
397 uint32_t L[PC_SNTRUP_P];
399 for (
int i = 0; i < PC_SNTRUP_P; ++i)
402 L[i] = (uint32_t)rb[0] | ((uint32_t)rb[1] << 8) | ((uint32_t)rb[2] << 16) | ((uint32_t)rb[3] << 24);
404 Short_fromlist(out, L);
408void Hash_prefix(uint8_t *out,
int b,
const uint8_t *in,
size_t inlen)
412 uint8_t bb = (uint8_t)b;
417 memcpy(out, h, PC_HASH_BYTES);
420void Small_encode(uint8_t *s,
const small_t *f)
422 for (
int i = 0; i < PC_SNTRUP_P / 4; ++i)
425 for (
int j = 0; j < 4; ++j)
427 x = (small_t)(x + ((*f++ + 1) << (2 * j)));
431 *s = (uint8_t)(*f + 1);
434void Rq_decode(Fq *r,
const uint8_t *s, uint16_t *scr, uint32_t *scr32)
436 uint16_t Rr[PC_SNTRUP_P], M[PC_SNTRUP_P];
437 for (
int i = 0; i < PC_SNTRUP_P; ++i)
441 Decode(Rr, s, M, PC_SNTRUP_P, scr, scr32);
442 for (
int i = 0; i < PC_SNTRUP_P; ++i)
444 r[i] = (Fq)(((Fq)Rr[i]) - PC_Q12);
448void Rounded_encode(uint8_t *s,
const Fq *r, uint16_t *scr)
450 uint16_t Rr[PC_SNTRUP_P], M[PC_SNTRUP_P];
451 for (
int i = 0; i < PC_SNTRUP_P; ++i)
453 Rr[i] = (uint16_t)(((r[i] + PC_Q12) * 10923) >> 15);
455 for (
int i = 0; i < PC_SNTRUP_P; ++i)
457 M[i] = (PC_SNTRUP_Q + 2) / 3;
459 Encode(s, Rr, M, PC_SNTRUP_P, scr);
462void HashConfirm(uint8_t *h,
const uint8_t *r_enc,
const uint8_t *cache)
464 uint8_t x[PC_HASH_BYTES * 2];
465 Hash_prefix(x, 3, r_enc, PC_SMALL_BYTES);
466 memcpy(x + PC_HASH_BYTES, cache, PC_HASH_BYTES);
467 Hash_prefix(h, 2, x,
sizeof x);
470void HashSession(uint8_t *k,
int b,
const uint8_t *r_enc,
const uint8_t *c)
472 uint8_t x[PC_HASH_BYTES + PC_CT_BYTES];
473 Hash_prefix(x, 3, r_enc, PC_SMALL_BYTES);
474 memcpy(x + PC_HASH_BYTES, c, PC_CT_BYTES);
475 Hash_prefix(k, b, x,
sizeof x);
479void Hide(uint8_t *c, uint8_t *r_enc,
const small_t *r,
const uint8_t *pk,
const uint8_t *cache, uint16_t *scr,
482 Small_encode(r_enc, r);
483 Fq h[PC_SNTRUP_P], cp[PC_SNTRUP_P];
484 Rq_decode(h, pk, scr, scr32);
485 Rq_mult_small(cp, h, r);
487 Rounded_encode(c, cp, scr);
488 HashConfirm(c + PC_CT_BYTES - PC_CONFIRM_BYTES, r_enc, cache);
496inline int nonzero_mask16(int16_t x)
498 uint32_t u = (uint16_t)x;
499 return -(int)((u | (0u - u)) >> 31);
501inline int negative_mask16(int16_t x)
503 return -((uint16_t)x >> 15);
506void R3_fromRq(small_t *out,
const Fq *r)
508 for (
int i = 0; i < PC_SNTRUP_P; ++i)
510 out[i] = F3_freeze(r[i]);
514void R3_mult(small_t *h,
const small_t *f,
const small_t *g)
516 int16_t fg[PC_SNTRUP_P + PC_SNTRUP_P - 1];
518 for (i = 0; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
522 for (i = 0; i < PC_SNTRUP_P; ++i)
524 for (j = 0; j < PC_SNTRUP_P; ++j)
526 fg[i + j] = (int16_t)(fg[i + j] + f[i] * (int16_t)g[j]);
529 for (i = PC_SNTRUP_P; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
531 fg[i - PC_SNTRUP_P] = (int16_t)(fg[i - PC_SNTRUP_P] + fg[i]);
533 for (i = PC_SNTRUP_P; i < PC_SNTRUP_P + PC_SNTRUP_P - 1; ++i)
535 fg[i - PC_SNTRUP_P + 1] = (int16_t)(fg[i - PC_SNTRUP_P + 1] + fg[i]);
537 for (i = 0; i < PC_SNTRUP_P; ++i)
539 h[i] = F3_freeze(fg[i]);
544int R3_recip(small_t *out,
const small_t *in)
546 small_t f[PC_SNTRUP_P + 1], g[PC_SNTRUP_P + 1], v[PC_SNTRUP_P + 1], r[PC_SNTRUP_P + 1];
547 int sign, swap, t, i, loop, delta = 1;
548 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
552 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
557 for (i = 0; i < PC_SNTRUP_P; ++i)
562 f[PC_SNTRUP_P - 1] = f[PC_SNTRUP_P] = -1;
563 for (i = 0; i < PC_SNTRUP_P; ++i)
565 g[PC_SNTRUP_P - 1 - i] = in[i];
568 for (loop = 0; loop < 2 * PC_SNTRUP_P - 1; ++loop)
570 for (i = PC_SNTRUP_P; i > 0; --i)
576 swap = negative_mask16((int16_t)-delta) & nonzero_mask16(g[0]);
577 delta ^= swap & (delta ^ -delta);
579 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
581 t = swap & (f[i] ^ g[i]);
582 f[i] = (small_t)(f[i] ^ t);
583 g[i] = (small_t)(g[i] ^ t);
584 t = swap & (v[i] ^ r[i]);
585 v[i] = (small_t)(v[i] ^ t);
586 r[i] = (small_t)(r[i] ^ t);
588 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
590 g[i] = F3_freeze((int16_t)(g[i] + sign * f[i]));
592 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
594 r[i] = F3_freeze((int16_t)(r[i] + sign * v[i]));
596 for (i = 0; i < PC_SNTRUP_P; ++i)
603 for (i = 0; i < PC_SNTRUP_P; ++i)
605 out[i] = (small_t)(sign * v[PC_SNTRUP_P - 1 - i]);
607 return nonzero_mask16((int16_t)delta);
610void Rq_mult3(Fq *h,
const Fq *f)
612 for (
int i = 0; i < PC_SNTRUP_P; ++i)
614 h[i] = Fq_freeze(3 * f[i]);
622 while (i < PC_SNTRUP_Q - 2)
624 ai = Fq_freeze(a1 * (int32_t)ai);
631int Rq_recip3(Fq *out,
const small_t *in)
633 Fq f[PC_SNTRUP_P + 1], g[PC_SNTRUP_P + 1], v[PC_SNTRUP_P + 1], r[PC_SNTRUP_P + 1], scale;
634 int swap, i, loop, delta = 1;
636 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
640 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
645 for (i = 0; i < PC_SNTRUP_P; ++i)
650 f[PC_SNTRUP_P - 1] = f[PC_SNTRUP_P] = -1;
651 for (i = 0; i < PC_SNTRUP_P; ++i)
653 g[PC_SNTRUP_P - 1 - i] = in[i];
656 for (loop = 0; loop < 2 * PC_SNTRUP_P - 1; ++loop)
658 for (i = PC_SNTRUP_P; i > 0; --i)
663 swap = negative_mask16((int16_t)-delta) & nonzero_mask16(g[0]);
664 delta ^= swap & (delta ^ -delta);
667 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
669 tmp = (Fq)(swap & (f[i] ^ g[i]));
672 tmp = (Fq)(swap & (v[i] ^ r[i]));
678 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
680 g[i] = Fq_freeze(f0 * g[i] - g0 * f[i]);
682 for (i = 0; i < PC_SNTRUP_P + 1; ++i)
684 r[i] = Fq_freeze(f0 * r[i] - g0 * v[i]);
686 for (i = 0; i < PC_SNTRUP_P; ++i)
692 scale = Fq_recip(f[0]);
693 for (i = 0; i < PC_SNTRUP_P; ++i)
695 out[i] = Fq_freeze(scale * (int32_t)v[PC_SNTRUP_P - 1 - i]);
697 return nonzero_mask16((int16_t)delta);
700int Weightw_mask(
const small_t *r)
703 for (
int i = 0; i < PC_SNTRUP_P; ++i)
705 weight += (r[i] & 1);
707 return nonzero_mask16((int16_t)(weight - PC_SNTRUP_W));
710void Small_random(small_t *out)
713 for (
int i = 0; i < PC_SNTRUP_P; ++i)
716 uint32_t u = (uint32_t)rb[0] | ((uint32_t)rb[1] << 8) | ((uint32_t)rb[2] << 16) | ((uint32_t)rb[3] << 24);
717 out[i] = (small_t)((((u & 0x3fffffff) * 3) >> 30) - 1);
721void KeyGen(Fq *h, small_t *f, small_t *ginv)
723 small_t g[PC_SNTRUP_P];
724 Fq finv[PC_SNTRUP_P];
728 if (R3_recip(ginv, g) == 0)
735 Rq_mult_small(h, finv, g);
738void Small_decode(small_t *f,
const uint8_t *s)
740 for (
int i = 0; i < PC_SNTRUP_P / 4; ++i)
743 for (
int j = 0; j < 4; ++j)
745 *f++ = (small_t)(((x >> (2 * j)) & 3) - 1);
748 *f = (small_t)((*s & 3) - 1);
751void Rounded_decode(Fq *r,
const uint8_t *s, uint16_t *scr, uint32_t *scr32)
753 uint16_t Rr[PC_SNTRUP_P], M[PC_SNTRUP_P];
754 for (
int i = 0; i < PC_SNTRUP_P; ++i)
756 M[i] = (PC_SNTRUP_Q + 2) / 3;
758 Decode(Rr, s, M, PC_SNTRUP_P, scr, scr32);
759 for (
int i = 0; i < PC_SNTRUP_P; ++i)
761 r[i] = (Fq)(Rr[i] * 3 - PC_Q12);
765void Rq_encode(uint8_t *s,
const Fq *r, uint16_t *scr)
767 uint16_t Rr[PC_SNTRUP_P], M[PC_SNTRUP_P];
768 for (
int i = 0; i < PC_SNTRUP_P; ++i)
770 Rr[i] = (uint16_t)(r[i] + PC_Q12);
772 for (
int i = 0; i < PC_SNTRUP_P; ++i)
776 Encode(s, Rr, M, PC_SNTRUP_P, scr);
779void Decrypt(small_t *r,
const Fq *c,
const small_t *f,
const small_t *ginv)
781 Fq cf[PC_SNTRUP_P], cf3[PC_SNTRUP_P];
782 small_t e[PC_SNTRUP_P], ev[PC_SNTRUP_P];
784 Rq_mult_small(cf, c, f);
787 R3_mult(ev, e, ginv);
788 mask = Weightw_mask(ev);
789 for (i = 0; i < PC_SNTRUP_W; ++i)
791 r[i] = (small_t)(((ev[i] ^ 1) & ~mask) ^ 1);
793 for (i = PC_SNTRUP_W; i < PC_SNTRUP_P; ++i)
795 r[i] = (small_t)(ev[i] & ~mask);
800int Ciphertexts_diff_mask(
const uint8_t *c,
const uint8_t *c2)
802 uint16_t differentbits = 0;
803 for (
int i = 0; i < PC_CT_BYTES; ++i)
805 differentbits |= (uint16_t)(c[i] ^ c2[i]);
809 return ((((uint16_t)(differentbits - 1)) >> 8) & 1) - 1;
814void pc_sntrup761_enc(
const uint8_t pk[PC_SNTRUP761_PK_BYTES], uint8_t ct[PC_SNTRUP761_CT_BYTES],
815 uint8_t ss[PC_SNTRUP761_SS_BYTES])
817 uint16_t scr16[PC_SCR16];
818 uint32_t scr32[PC_SCR32];
819 small_t r[PC_SNTRUP_P];
820 uint8_t r_enc[PC_SMALL_BYTES];
821 uint8_t cache[PC_HASH_BYTES];
823 Hash_prefix(cache, 4, pk, PC_PK_BYTES);
825 Hide(ct, r_enc, r, pk, cache, scr16, scr32);
826 HashSession(ss, 1, r_enc, ct);
829void pc_sntrup761_keypair(uint8_t pk[PC_SNTRUP761_PK_BYTES], uint8_t sk[PC_SNTRUP761_SK_BYTES])
831 uint16_t scr16[PC_SCR16];
833 small_t f[PC_SNTRUP_P];
834 small_t ginv[PC_SNTRUP_P];
837 Rq_encode(pk, h, scr16);
839 Small_encode(sk + PC_SMALL_BYTES, ginv);
841 uint8_t *tail = sk + 2 * PC_SMALL_BYTES;
842 memcpy(tail, pk, PC_PK_BYTES);
844 Hash_prefix(tail + PC_PK_BYTES + PC_SMALL_BYTES, 4, pk, PC_PK_BYTES);
847void pc_sntrup761_dec(
const uint8_t sk[PC_SNTRUP761_SK_BYTES],
const uint8_t ct[PC_SNTRUP761_CT_BYTES],
848 uint8_t ss[PC_SNTRUP761_SS_BYTES])
850 uint16_t scr16[PC_SCR16];
851 uint32_t scr32[PC_SCR32];
852 const uint8_t *pk = sk + 2 * PC_SMALL_BYTES;
853 const uint8_t *rho = pk + PC_PK_BYTES;
854 const uint8_t *cache = rho + PC_SMALL_BYTES;
855 small_t f[PC_SNTRUP_P];
856 small_t ginv[PC_SNTRUP_P];
857 small_t r[PC_SNTRUP_P];
859 uint8_t r_enc[PC_SMALL_BYTES];
860 uint8_t cnew[PC_CT_BYTES];
863 Small_decode(ginv, sk + PC_SMALL_BYTES);
864 Rounded_decode(cp, ct, scr16, scr32);
865 Decrypt(r, cp, f, ginv);
866 Hide(cnew, r_enc, r, pk, cache, scr16, scr32);
867 int mask = Ciphertexts_diff_mask(ct, cnew);
868 for (
int i = 0; i < PC_SMALL_BYTES; ++i)
870 r_enc[i] = (uint8_t)(r_enc[i] ^ (mask & (r_enc[i] ^ rho[i])));
872 HashSession(ss, 1 + mask, r_enc, ct);
#define R2(A, B, C, D, K, S)
uint32_t mask(uint8_t width)
Mask of width low bits (width 32 handled without a 32-bit shift, which is UB).
void pc_sha512_update(pc_sha512_ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
PC_CRYPTO_HOT void pc_sha512_init(pc_sha512_ctx *ctx)
Initialize a streaming SHA-512 context (ctx must not be NULL).
void pc_sha512_final(pc_sha512_ctx *ctx, uint8_t digest[PC_SHA512_DIGEST_LEN])
Finalize the hash and write the 64-byte digest. The context is undefined afterwards; call init() agai...
SHA-512 (FIPS 180-4) - streaming context and one-shot API.
#define PC_SHA512_DIGEST_LEN
SHA-512 digest length in bytes.
Streamlined NTRU Prime sntrup761 KEM - responder (encapsulation) only.
void ssh_rng_fill(uint8_t *buf, size_t len)
Fill len bytes of buf with cryptographically random data.
Streaming SHA-512 context.