xref: /dflybsd-src/crypto/openssh/sntrup761.c (revision ba1276acd1c8c22d225b1bcf370a14c878644f44)
1*ba1276acSMatthew Dillon /*  $OpenBSD: sntrup761.c,v 1.6 2023/01/11 02:13:52 djm Exp $ */
250a69bb5SSascha Wildner 
350a69bb5SSascha Wildner /*
450a69bb5SSascha Wildner  * Public Domain, Authors:
550a69bb5SSascha Wildner  * - Daniel J. Bernstein
650a69bb5SSascha Wildner  * - Chitchanok Chuengsatiansup
750a69bb5SSascha Wildner  * - Tanja Lange
850a69bb5SSascha Wildner  * - Christine van Vredendaal
950a69bb5SSascha Wildner  */
1050a69bb5SSascha Wildner 
1150a69bb5SSascha Wildner #include "includes.h"
1250a69bb5SSascha Wildner 
1350a69bb5SSascha Wildner #ifdef USE_SNTRUP761X25519
1450a69bb5SSascha Wildner 
1550a69bb5SSascha Wildner #include <string.h>
1650a69bb5SSascha Wildner #include "crypto_api.h"
1750a69bb5SSascha Wildner 
1850a69bb5SSascha Wildner #define int8 crypto_int8
1950a69bb5SSascha Wildner #define uint8 crypto_uint8
2050a69bb5SSascha Wildner #define int16 crypto_int16
2150a69bb5SSascha Wildner #define uint16 crypto_uint16
2250a69bb5SSascha Wildner #define int32 crypto_int32
2350a69bb5SSascha Wildner #define uint32 crypto_uint32
2450a69bb5SSascha Wildner #define int64 crypto_int64
2550a69bb5SSascha Wildner #define uint64 crypto_uint64
2650a69bb5SSascha Wildner 
2750a69bb5SSascha Wildner /* from supercop-20201130/crypto_sort/int32/portable4/int32_minmax.inc */
2850a69bb5SSascha Wildner #define int32_MINMAX(a,b) \
2950a69bb5SSascha Wildner do { \
3050a69bb5SSascha Wildner   int64_t ab = (int64_t)b ^ (int64_t)a; \
3150a69bb5SSascha Wildner   int64_t c = (int64_t)b - (int64_t)a; \
3250a69bb5SSascha Wildner   c ^= ab & (c ^ b); \
3350a69bb5SSascha Wildner   c >>= 31; \
3450a69bb5SSascha Wildner   c &= ab; \
3550a69bb5SSascha Wildner   a ^= c; \
3650a69bb5SSascha Wildner   b ^= c; \
3750a69bb5SSascha Wildner } while(0)
3850a69bb5SSascha Wildner 
3950a69bb5SSascha Wildner /* from supercop-20201130/crypto_sort/int32/portable4/sort.c */
4050a69bb5SSascha Wildner 
4150a69bb5SSascha Wildner 
crypto_sort_int32(void * array,long long n)4250a69bb5SSascha Wildner static void crypto_sort_int32(void *array,long long n)
4350a69bb5SSascha Wildner {
4450a69bb5SSascha Wildner   long long top,p,q,r,i,j;
4550a69bb5SSascha Wildner   int32 *x = array;
4650a69bb5SSascha Wildner 
4750a69bb5SSascha Wildner   if (n < 2) return;
4850a69bb5SSascha Wildner   top = 1;
4950a69bb5SSascha Wildner   while (top < n - top) top += top;
5050a69bb5SSascha Wildner 
5150a69bb5SSascha Wildner   for (p = top;p >= 1;p >>= 1) {
5250a69bb5SSascha Wildner     i = 0;
5350a69bb5SSascha Wildner     while (i + 2 * p <= n) {
5450a69bb5SSascha Wildner       for (j = i;j < i + p;++j)
5550a69bb5SSascha Wildner         int32_MINMAX(x[j],x[j+p]);
5650a69bb5SSascha Wildner       i += 2 * p;
5750a69bb5SSascha Wildner     }
5850a69bb5SSascha Wildner     for (j = i;j < n - p;++j)
5950a69bb5SSascha Wildner       int32_MINMAX(x[j],x[j+p]);
6050a69bb5SSascha Wildner 
6150a69bb5SSascha Wildner     i = 0;
6250a69bb5SSascha Wildner     j = 0;
6350a69bb5SSascha Wildner     for (q = top;q > p;q >>= 1) {
6450a69bb5SSascha Wildner       if (j != i) for (;;) {
6550a69bb5SSascha Wildner         if (j == n - q) goto done;
6650a69bb5SSascha Wildner         int32 a = x[j + p];
6750a69bb5SSascha Wildner         for (r = q;r > p;r >>= 1)
6850a69bb5SSascha Wildner           int32_MINMAX(a,x[j + r]);
6950a69bb5SSascha Wildner         x[j + p] = a;
7050a69bb5SSascha Wildner         ++j;
7150a69bb5SSascha Wildner         if (j == i + p) {
7250a69bb5SSascha Wildner           i += 2 * p;
7350a69bb5SSascha Wildner           break;
7450a69bb5SSascha Wildner         }
7550a69bb5SSascha Wildner       }
7650a69bb5SSascha Wildner       while (i + p <= n - q) {
7750a69bb5SSascha Wildner         for (j = i;j < i + p;++j) {
7850a69bb5SSascha Wildner           int32 a = x[j + p];
7950a69bb5SSascha Wildner           for (r = q;r > p;r >>= 1)
8050a69bb5SSascha Wildner             int32_MINMAX(a,x[j+r]);
8150a69bb5SSascha Wildner           x[j + p] = a;
8250a69bb5SSascha Wildner         }
8350a69bb5SSascha Wildner         i += 2 * p;
8450a69bb5SSascha Wildner       }
8550a69bb5SSascha Wildner       /* now i + p > n - q */
8650a69bb5SSascha Wildner       j = i;
8750a69bb5SSascha Wildner       while (j < n - q) {
8850a69bb5SSascha Wildner         int32 a = x[j + p];
8950a69bb5SSascha Wildner         for (r = q;r > p;r >>= 1)
9050a69bb5SSascha Wildner           int32_MINMAX(a,x[j+r]);
9150a69bb5SSascha Wildner         x[j + p] = a;
9250a69bb5SSascha Wildner         ++j;
9350a69bb5SSascha Wildner       }
9450a69bb5SSascha Wildner 
9550a69bb5SSascha Wildner       done: ;
9650a69bb5SSascha Wildner     }
9750a69bb5SSascha Wildner   }
9850a69bb5SSascha Wildner }
9950a69bb5SSascha Wildner 
10050a69bb5SSascha Wildner /* from supercop-20201130/crypto_sort/uint32/useint32/sort.c */
10150a69bb5SSascha Wildner 
10250a69bb5SSascha Wildner /* can save time by vectorizing xor loops */
10350a69bb5SSascha Wildner /* can save time by integrating xor loops with int32_sort */
10450a69bb5SSascha Wildner 
crypto_sort_uint32(void * array,long long n)10550a69bb5SSascha Wildner static void crypto_sort_uint32(void *array,long long n)
10650a69bb5SSascha Wildner {
10750a69bb5SSascha Wildner   crypto_uint32 *x = array;
10850a69bb5SSascha Wildner   long long j;
10950a69bb5SSascha Wildner   for (j = 0;j < n;++j) x[j] ^= 0x80000000;
11050a69bb5SSascha Wildner   crypto_sort_int32(array,n);
11150a69bb5SSascha Wildner   for (j = 0;j < n;++j) x[j] ^= 0x80000000;
11250a69bb5SSascha Wildner }
11350a69bb5SSascha Wildner 
11450a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/uint32.c */
11550a69bb5SSascha Wildner 
11650a69bb5SSascha Wildner /*
11750a69bb5SSascha Wildner CPU division instruction typically takes time depending on x.
11850a69bb5SSascha Wildner This software is designed to take time independent of x.
11950a69bb5SSascha Wildner Time still varies depending on m; user must ensure that m is constant.
12050a69bb5SSascha Wildner Time also varies on CPUs where multiplication is variable-time.
12150a69bb5SSascha Wildner There could be more CPU issues.
12250a69bb5SSascha Wildner There could also be compiler issues.
12350a69bb5SSascha Wildner */
12450a69bb5SSascha Wildner 
uint32_divmod_uint14(uint32 * q,uint16 * r,uint32 x,uint16 m)12550a69bb5SSascha Wildner static void uint32_divmod_uint14(uint32 *q,uint16 *r,uint32 x,uint16 m)
12650a69bb5SSascha Wildner {
12750a69bb5SSascha Wildner   uint32 v = 0x80000000;
12850a69bb5SSascha Wildner   uint32 qpart;
12950a69bb5SSascha Wildner   uint32 mask;
13050a69bb5SSascha Wildner 
13150a69bb5SSascha Wildner   v /= m;
13250a69bb5SSascha Wildner 
13350a69bb5SSascha Wildner   /* caller guarantees m > 0 */
13450a69bb5SSascha Wildner   /* caller guarantees m < 16384 */
13550a69bb5SSascha Wildner   /* vm <= 2^31 <= vm+m-1 */
13650a69bb5SSascha Wildner   /* xvm <= 2^31 x <= xvm+x(m-1) */
13750a69bb5SSascha Wildner 
13850a69bb5SSascha Wildner   *q = 0;
13950a69bb5SSascha Wildner 
14050a69bb5SSascha Wildner   qpart = (x*(uint64)v)>>31;
14150a69bb5SSascha Wildner   /* 2^31 qpart <= xv <= 2^31 qpart + 2^31-1 */
14250a69bb5SSascha Wildner   /* 2^31 qpart m <= xvm <= 2^31 qpart m + (2^31-1)m */
14350a69bb5SSascha Wildner   /* 2^31 qpart m <= 2^31 x <= 2^31 qpart m + (2^31-1)m + x(m-1) */
14450a69bb5SSascha Wildner   /* 0 <= 2^31 newx <= (2^31-1)m + x(m-1) */
14550a69bb5SSascha Wildner   /* 0 <= newx <= (1-1/2^31)m + x(m-1)/2^31 */
14650a69bb5SSascha Wildner   /* 0 <= newx <= (1-1/2^31)(2^14-1) + (2^32-1)((2^14-1)-1)/2^31 */
14750a69bb5SSascha Wildner 
14850a69bb5SSascha Wildner   x -= qpart*m; *q += qpart;
14950a69bb5SSascha Wildner   /* x <= 49146 */
15050a69bb5SSascha Wildner 
15150a69bb5SSascha Wildner   qpart = (x*(uint64)v)>>31;
15250a69bb5SSascha Wildner   /* 0 <= newx <= (1-1/2^31)m + x(m-1)/2^31 */
15350a69bb5SSascha Wildner   /* 0 <= newx <= m + 49146(2^14-1)/2^31 */
15450a69bb5SSascha Wildner   /* 0 <= newx <= m + 0.4 */
15550a69bb5SSascha Wildner   /* 0 <= newx <= m */
15650a69bb5SSascha Wildner 
15750a69bb5SSascha Wildner   x -= qpart*m; *q += qpart;
15850a69bb5SSascha Wildner   /* x <= m */
15950a69bb5SSascha Wildner 
16050a69bb5SSascha Wildner   x -= m; *q += 1;
16150a69bb5SSascha Wildner   mask = -(x>>31);
16250a69bb5SSascha Wildner   x += mask&(uint32)m; *q += mask;
16350a69bb5SSascha Wildner   /* x < m */
16450a69bb5SSascha Wildner 
16550a69bb5SSascha Wildner   *r = x;
16650a69bb5SSascha Wildner }
16750a69bb5SSascha Wildner 
16850a69bb5SSascha Wildner 
uint32_mod_uint14(uint32 x,uint16 m)16950a69bb5SSascha Wildner static uint16 uint32_mod_uint14(uint32 x,uint16 m)
17050a69bb5SSascha Wildner {
17150a69bb5SSascha Wildner   uint32 q;
17250a69bb5SSascha Wildner   uint16 r;
17350a69bb5SSascha Wildner   uint32_divmod_uint14(&q,&r,x,m);
17450a69bb5SSascha Wildner   return r;
17550a69bb5SSascha Wildner }
17650a69bb5SSascha Wildner 
17750a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/int32.c */
17850a69bb5SSascha Wildner 
int32_divmod_uint14(int32 * q,uint16 * r,int32 x,uint16 m)17950a69bb5SSascha Wildner static void int32_divmod_uint14(int32 *q,uint16 *r,int32 x,uint16 m)
18050a69bb5SSascha Wildner {
18150a69bb5SSascha Wildner   uint32 uq,uq2;
18250a69bb5SSascha Wildner   uint16 ur,ur2;
18350a69bb5SSascha Wildner   uint32 mask;
18450a69bb5SSascha Wildner 
18550a69bb5SSascha Wildner   uint32_divmod_uint14(&uq,&ur,0x80000000+(uint32)x,m);
18650a69bb5SSascha Wildner   uint32_divmod_uint14(&uq2,&ur2,0x80000000,m);
18750a69bb5SSascha Wildner   ur -= ur2; uq -= uq2;
18850a69bb5SSascha Wildner   mask = -(uint32)(ur>>15);
18950a69bb5SSascha Wildner   ur += mask&m; uq += mask;
19050a69bb5SSascha Wildner   *r = ur; *q = uq;
19150a69bb5SSascha Wildner }
19250a69bb5SSascha Wildner 
19350a69bb5SSascha Wildner 
int32_mod_uint14(int32 x,uint16 m)19450a69bb5SSascha Wildner static uint16 int32_mod_uint14(int32 x,uint16 m)
19550a69bb5SSascha Wildner {
19650a69bb5SSascha Wildner   int32 q;
19750a69bb5SSascha Wildner   uint16 r;
19850a69bb5SSascha Wildner   int32_divmod_uint14(&q,&r,x,m);
19950a69bb5SSascha Wildner   return r;
20050a69bb5SSascha Wildner }
20150a69bb5SSascha Wildner 
20250a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/paramsmenu.h */
20350a69bb5SSascha Wildner /* pick one of these three: */
20450a69bb5SSascha Wildner #define SIZE761
20550a69bb5SSascha Wildner #undef SIZE653
20650a69bb5SSascha Wildner #undef SIZE857
20750a69bb5SSascha Wildner 
20850a69bb5SSascha Wildner /* pick one of these two: */
20950a69bb5SSascha Wildner #define SNTRUP /* Streamlined NTRU Prime */
21050a69bb5SSascha Wildner #undef LPR /* NTRU LPRime */
21150a69bb5SSascha Wildner 
21250a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/params.h */
21350a69bb5SSascha Wildner #ifndef params_H
21450a69bb5SSascha Wildner #define params_H
21550a69bb5SSascha Wildner 
21650a69bb5SSascha Wildner /* menu of parameter choices: */
21750a69bb5SSascha Wildner 
21850a69bb5SSascha Wildner 
21950a69bb5SSascha Wildner /* what the menu means: */
22050a69bb5SSascha Wildner 
22150a69bb5SSascha Wildner #if defined(SIZE761)
22250a69bb5SSascha Wildner #define p 761
22350a69bb5SSascha Wildner #define q 4591
22450a69bb5SSascha Wildner #define Rounded_bytes 1007
22550a69bb5SSascha Wildner #ifndef LPR
22650a69bb5SSascha Wildner #define Rq_bytes 1158
22750a69bb5SSascha Wildner #define w 286
22850a69bb5SSascha Wildner #else
22950a69bb5SSascha Wildner #define w 250
23050a69bb5SSascha Wildner #define tau0 2156
23150a69bb5SSascha Wildner #define tau1 114
23250a69bb5SSascha Wildner #define tau2 2007
23350a69bb5SSascha Wildner #define tau3 287
23450a69bb5SSascha Wildner #endif
23550a69bb5SSascha Wildner 
23650a69bb5SSascha Wildner #elif defined(SIZE653)
23750a69bb5SSascha Wildner #define p 653
23850a69bb5SSascha Wildner #define q 4621
23950a69bb5SSascha Wildner #define Rounded_bytes 865
24050a69bb5SSascha Wildner #ifndef LPR
24150a69bb5SSascha Wildner #define Rq_bytes 994
24250a69bb5SSascha Wildner #define w 288
24350a69bb5SSascha Wildner #else
24450a69bb5SSascha Wildner #define w 252
24550a69bb5SSascha Wildner #define tau0 2175
24650a69bb5SSascha Wildner #define tau1 113
24750a69bb5SSascha Wildner #define tau2 2031
24850a69bb5SSascha Wildner #define tau3 290
24950a69bb5SSascha Wildner #endif
25050a69bb5SSascha Wildner 
25150a69bb5SSascha Wildner #elif defined(SIZE857)
25250a69bb5SSascha Wildner #define p 857
25350a69bb5SSascha Wildner #define q 5167
25450a69bb5SSascha Wildner #define Rounded_bytes 1152
25550a69bb5SSascha Wildner #ifndef LPR
25650a69bb5SSascha Wildner #define Rq_bytes 1322
25750a69bb5SSascha Wildner #define w 322
25850a69bb5SSascha Wildner #else
25950a69bb5SSascha Wildner #define w 281
26050a69bb5SSascha Wildner #define tau0 2433
26150a69bb5SSascha Wildner #define tau1 101
26250a69bb5SSascha Wildner #define tau2 2265
26350a69bb5SSascha Wildner #define tau3 324
26450a69bb5SSascha Wildner #endif
26550a69bb5SSascha Wildner 
26650a69bb5SSascha Wildner #else
26750a69bb5SSascha Wildner #error "no parameter set defined"
26850a69bb5SSascha Wildner #endif
26950a69bb5SSascha Wildner 
27050a69bb5SSascha Wildner #ifdef LPR
27150a69bb5SSascha Wildner #define I 256
27250a69bb5SSascha Wildner #endif
27350a69bb5SSascha Wildner 
27450a69bb5SSascha Wildner #endif
27550a69bb5SSascha Wildner 
27650a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/Decode.h */
27750a69bb5SSascha Wildner #ifndef Decode_H
27850a69bb5SSascha Wildner #define Decode_H
27950a69bb5SSascha Wildner 
28050a69bb5SSascha Wildner 
28150a69bb5SSascha Wildner /* Decode(R,s,M,len) */
28250a69bb5SSascha Wildner /* assumes 0 < M[i] < 16384 */
28350a69bb5SSascha Wildner /* produces 0 <= R[i] < M[i] */
28450a69bb5SSascha Wildner 
28550a69bb5SSascha Wildner #endif
28650a69bb5SSascha Wildner 
28750a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/Decode.c */
28850a69bb5SSascha Wildner 
Decode(uint16 * out,const unsigned char * S,const uint16 * M,long long len)28950a69bb5SSascha Wildner static void Decode(uint16 *out,const unsigned char *S,const uint16 *M,long long len)
29050a69bb5SSascha Wildner {
29150a69bb5SSascha Wildner   if (len == 1) {
29250a69bb5SSascha Wildner     if (M[0] == 1)
29350a69bb5SSascha Wildner       *out = 0;
29450a69bb5SSascha Wildner     else if (M[0] <= 256)
29550a69bb5SSascha Wildner       *out = uint32_mod_uint14(S[0],M[0]);
29650a69bb5SSascha Wildner     else
29750a69bb5SSascha Wildner       *out = uint32_mod_uint14(S[0]+(((uint16)S[1])<<8),M[0]);
29850a69bb5SSascha Wildner   }
29950a69bb5SSascha Wildner   if (len > 1) {
30050a69bb5SSascha Wildner     uint16 R2[(len+1)/2];
30150a69bb5SSascha Wildner     uint16 M2[(len+1)/2];
30250a69bb5SSascha Wildner     uint16 bottomr[len/2];
30350a69bb5SSascha Wildner     uint32 bottomt[len/2];
30450a69bb5SSascha Wildner     long long i;
30550a69bb5SSascha Wildner     for (i = 0;i < len-1;i += 2) {
30650a69bb5SSascha Wildner       uint32 m = M[i]*(uint32) M[i+1];
30750a69bb5SSascha Wildner       if (m > 256*16383) {
30850a69bb5SSascha Wildner         bottomt[i/2] = 256*256;
30950a69bb5SSascha Wildner         bottomr[i/2] = S[0]+256*S[1];
31050a69bb5SSascha Wildner         S += 2;
31150a69bb5SSascha Wildner         M2[i/2] = (((m+255)>>8)+255)>>8;
31250a69bb5SSascha Wildner       } else if (m >= 16384) {
31350a69bb5SSascha Wildner         bottomt[i/2] = 256;
31450a69bb5SSascha Wildner         bottomr[i/2] = S[0];
31550a69bb5SSascha Wildner         S += 1;
31650a69bb5SSascha Wildner         M2[i/2] = (m+255)>>8;
31750a69bb5SSascha Wildner       } else {
31850a69bb5SSascha Wildner         bottomt[i/2] = 1;
31950a69bb5SSascha Wildner         bottomr[i/2] = 0;
32050a69bb5SSascha Wildner         M2[i/2] = m;
32150a69bb5SSascha Wildner       }
32250a69bb5SSascha Wildner     }
32350a69bb5SSascha Wildner     if (i < len)
32450a69bb5SSascha Wildner       M2[i/2] = M[i];
32550a69bb5SSascha Wildner     Decode(R2,S,M2,(len+1)/2);
32650a69bb5SSascha Wildner     for (i = 0;i < len-1;i += 2) {
32750a69bb5SSascha Wildner       uint32 r = bottomr[i/2];
32850a69bb5SSascha Wildner       uint32 r1;
32950a69bb5SSascha Wildner       uint16 r0;
33050a69bb5SSascha Wildner       r += bottomt[i/2]*R2[i/2];
33150a69bb5SSascha Wildner       uint32_divmod_uint14(&r1,&r0,r,M[i]);
33250a69bb5SSascha Wildner       r1 = uint32_mod_uint14(r1,M[i+1]); /* only needed for invalid inputs */
33350a69bb5SSascha Wildner       *out++ = r0;
33450a69bb5SSascha Wildner       *out++ = r1;
33550a69bb5SSascha Wildner     }
33650a69bb5SSascha Wildner     if (i < len)
33750a69bb5SSascha Wildner       *out++ = R2[i/2];
33850a69bb5SSascha Wildner   }
33950a69bb5SSascha Wildner }
34050a69bb5SSascha Wildner 
34150a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/Encode.h */
34250a69bb5SSascha Wildner #ifndef Encode_H
34350a69bb5SSascha Wildner #define Encode_H
34450a69bb5SSascha Wildner 
34550a69bb5SSascha Wildner 
34650a69bb5SSascha Wildner /* Encode(s,R,M,len) */
34750a69bb5SSascha Wildner /* assumes 0 <= R[i] < M[i] < 16384 */
34850a69bb5SSascha Wildner 
34950a69bb5SSascha Wildner #endif
35050a69bb5SSascha Wildner 
35150a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/Encode.c */
35250a69bb5SSascha Wildner 
35350a69bb5SSascha Wildner /* 0 <= R[i] < M[i] < 16384 */
Encode(unsigned char * out,const uint16 * R,const uint16 * M,long long len)35450a69bb5SSascha Wildner static void Encode(unsigned char *out,const uint16 *R,const uint16 *M,long long len)
35550a69bb5SSascha Wildner {
35650a69bb5SSascha Wildner   if (len == 1) {
35750a69bb5SSascha Wildner     uint16 r = R[0];
35850a69bb5SSascha Wildner     uint16 m = M[0];
35950a69bb5SSascha Wildner     while (m > 1) {
36050a69bb5SSascha Wildner       *out++ = r;
36150a69bb5SSascha Wildner       r >>= 8;
36250a69bb5SSascha Wildner       m = (m+255)>>8;
36350a69bb5SSascha Wildner     }
36450a69bb5SSascha Wildner   }
36550a69bb5SSascha Wildner   if (len > 1) {
36650a69bb5SSascha Wildner     uint16 R2[(len+1)/2];
36750a69bb5SSascha Wildner     uint16 M2[(len+1)/2];
36850a69bb5SSascha Wildner     long long i;
36950a69bb5SSascha Wildner     for (i = 0;i < len-1;i += 2) {
37050a69bb5SSascha Wildner       uint32 m0 = M[i];
37150a69bb5SSascha Wildner       uint32 r = R[i]+R[i+1]*m0;
37250a69bb5SSascha Wildner       uint32 m = M[i+1]*m0;
37350a69bb5SSascha Wildner       while (m >= 16384) {
37450a69bb5SSascha Wildner         *out++ = r;
37550a69bb5SSascha Wildner         r >>= 8;
37650a69bb5SSascha Wildner         m = (m+255)>>8;
37750a69bb5SSascha Wildner       }
37850a69bb5SSascha Wildner       R2[i/2] = r;
37950a69bb5SSascha Wildner       M2[i/2] = m;
38050a69bb5SSascha Wildner     }
38150a69bb5SSascha Wildner     if (i < len) {
38250a69bb5SSascha Wildner       R2[i/2] = R[i];
38350a69bb5SSascha Wildner       M2[i/2] = M[i];
38450a69bb5SSascha Wildner     }
38550a69bb5SSascha Wildner     Encode(out,R2,M2,(len+1)/2);
38650a69bb5SSascha Wildner   }
38750a69bb5SSascha Wildner }
38850a69bb5SSascha Wildner 
38950a69bb5SSascha Wildner /* from supercop-20201130/crypto_kem/sntrup761/ref/kem.c */
39050a69bb5SSascha Wildner 
39150a69bb5SSascha Wildner #ifdef LPR
39250a69bb5SSascha Wildner #endif
39350a69bb5SSascha Wildner 
39450a69bb5SSascha Wildner 
39550a69bb5SSascha Wildner /* ----- masks */
39650a69bb5SSascha Wildner 
39750a69bb5SSascha Wildner #ifndef LPR
39850a69bb5SSascha Wildner 
39950a69bb5SSascha Wildner /* return -1 if x!=0; else return 0 */
int16_nonzero_mask(int16 x)40050a69bb5SSascha Wildner static int int16_nonzero_mask(int16 x)
40150a69bb5SSascha Wildner {
40250a69bb5SSascha Wildner   uint16 u = x; /* 0, else 1...65535 */
40350a69bb5SSascha Wildner   uint32 v = u; /* 0, else 1...65535 */
40450a69bb5SSascha Wildner   v = -v; /* 0, else 2^32-65535...2^32-1 */
40550a69bb5SSascha Wildner   v >>= 31; /* 0, else 1 */
40650a69bb5SSascha Wildner   return -v; /* 0, else -1 */
40750a69bb5SSascha Wildner }
40850a69bb5SSascha Wildner 
40950a69bb5SSascha Wildner #endif
41050a69bb5SSascha Wildner 
41150a69bb5SSascha Wildner /* return -1 if x<0; otherwise return 0 */
int16_negative_mask(int16 x)41250a69bb5SSascha Wildner static int int16_negative_mask(int16 x)
41350a69bb5SSascha Wildner {
41450a69bb5SSascha Wildner   uint16 u = x;
41550a69bb5SSascha Wildner   u >>= 15;
41650a69bb5SSascha Wildner   return -(int) u;
41750a69bb5SSascha Wildner   /* alternative with gcc -fwrapv: */
41850a69bb5SSascha Wildner   /* x>>15 compiles to CPU's arithmetic right shift */
41950a69bb5SSascha Wildner }
42050a69bb5SSascha Wildner 
42150a69bb5SSascha Wildner /* ----- arithmetic mod 3 */
42250a69bb5SSascha Wildner 
42350a69bb5SSascha Wildner typedef int8 small;
42450a69bb5SSascha Wildner 
42550a69bb5SSascha Wildner /* F3 is always represented as -1,0,1 */
42650a69bb5SSascha Wildner /* so ZZ_fromF3 is a no-op */
42750a69bb5SSascha Wildner 
42850a69bb5SSascha Wildner /* x must not be close to top int16 */
F3_freeze(int16 x)42950a69bb5SSascha Wildner static small F3_freeze(int16 x)
43050a69bb5SSascha Wildner {
43150a69bb5SSascha Wildner   return int32_mod_uint14(x+1,3)-1;
43250a69bb5SSascha Wildner }
43350a69bb5SSascha Wildner 
43450a69bb5SSascha Wildner /* ----- arithmetic mod q */
43550a69bb5SSascha Wildner 
43650a69bb5SSascha Wildner #define q12 ((q-1)/2)
43750a69bb5SSascha Wildner typedef int16 Fq;
43850a69bb5SSascha Wildner /* always represented as -q12...q12 */
43950a69bb5SSascha Wildner /* so ZZ_fromFq is a no-op */
44050a69bb5SSascha Wildner 
44150a69bb5SSascha Wildner /* x must not be close to top int32 */
Fq_freeze(int32 x)44250a69bb5SSascha Wildner static Fq Fq_freeze(int32 x)
44350a69bb5SSascha Wildner {
44450a69bb5SSascha Wildner   return int32_mod_uint14(x+q12,q)-q12;
44550a69bb5SSascha Wildner }
44650a69bb5SSascha Wildner 
44750a69bb5SSascha Wildner #ifndef LPR
44850a69bb5SSascha Wildner 
Fq_recip(Fq a1)44950a69bb5SSascha Wildner static Fq Fq_recip(Fq a1)
45050a69bb5SSascha Wildner {
45150a69bb5SSascha Wildner   int i = 1;
45250a69bb5SSascha Wildner   Fq ai = a1;
45350a69bb5SSascha Wildner 
45450a69bb5SSascha Wildner   while (i < q-2) {
45550a69bb5SSascha Wildner     ai = Fq_freeze(a1*(int32)ai);
45650a69bb5SSascha Wildner     i += 1;
45750a69bb5SSascha Wildner   }
45850a69bb5SSascha Wildner   return ai;
45950a69bb5SSascha Wildner }
46050a69bb5SSascha Wildner 
46150a69bb5SSascha Wildner #endif
46250a69bb5SSascha Wildner 
46350a69bb5SSascha Wildner /* ----- Top and Right */
46450a69bb5SSascha Wildner 
46550a69bb5SSascha Wildner #ifdef LPR
46650a69bb5SSascha Wildner #define tau 16
46750a69bb5SSascha Wildner 
Top(Fq C)46850a69bb5SSascha Wildner static int8 Top(Fq C)
46950a69bb5SSascha Wildner {
47050a69bb5SSascha Wildner   return (tau1*(int32)(C+tau0)+16384)>>15;
47150a69bb5SSascha Wildner }
47250a69bb5SSascha Wildner 
Right(int8 T)47350a69bb5SSascha Wildner static Fq Right(int8 T)
47450a69bb5SSascha Wildner {
47550a69bb5SSascha Wildner   return Fq_freeze(tau3*(int32)T-tau2);
47650a69bb5SSascha Wildner }
47750a69bb5SSascha Wildner #endif
47850a69bb5SSascha Wildner 
47950a69bb5SSascha Wildner /* ----- small polynomials */
48050a69bb5SSascha Wildner 
48150a69bb5SSascha Wildner #ifndef LPR
48250a69bb5SSascha Wildner 
48350a69bb5SSascha Wildner /* 0 if Weightw_is(r), else -1 */
Weightw_mask(small * r)48450a69bb5SSascha Wildner static int Weightw_mask(small *r)
48550a69bb5SSascha Wildner {
48650a69bb5SSascha Wildner   int weight = 0;
48750a69bb5SSascha Wildner   int i;
48850a69bb5SSascha Wildner 
48950a69bb5SSascha Wildner   for (i = 0;i < p;++i) weight += r[i]&1;
49050a69bb5SSascha Wildner   return int16_nonzero_mask(weight-w);
49150a69bb5SSascha Wildner }
49250a69bb5SSascha Wildner 
49350a69bb5SSascha Wildner /* R3_fromR(R_fromRq(r)) */
R3_fromRq(small * out,const Fq * r)49450a69bb5SSascha Wildner static void R3_fromRq(small *out,const Fq *r)
49550a69bb5SSascha Wildner {
49650a69bb5SSascha Wildner   int i;
49750a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = F3_freeze(r[i]);
49850a69bb5SSascha Wildner }
49950a69bb5SSascha Wildner 
50050a69bb5SSascha Wildner /* h = f*g in the ring R3 */
R3_mult(small * h,const small * f,const small * g)50150a69bb5SSascha Wildner static void R3_mult(small *h,const small *f,const small *g)
50250a69bb5SSascha Wildner {
50350a69bb5SSascha Wildner   small fg[p+p-1];
50450a69bb5SSascha Wildner   small result;
50550a69bb5SSascha Wildner   int i,j;
50650a69bb5SSascha Wildner 
50750a69bb5SSascha Wildner   for (i = 0;i < p;++i) {
50850a69bb5SSascha Wildner     result = 0;
50950a69bb5SSascha Wildner     for (j = 0;j <= i;++j) result = F3_freeze(result+f[j]*g[i-j]);
51050a69bb5SSascha Wildner     fg[i] = result;
51150a69bb5SSascha Wildner   }
51250a69bb5SSascha Wildner   for (i = p;i < p+p-1;++i) {
51350a69bb5SSascha Wildner     result = 0;
51450a69bb5SSascha Wildner     for (j = i-p+1;j < p;++j) result = F3_freeze(result+f[j]*g[i-j]);
51550a69bb5SSascha Wildner     fg[i] = result;
51650a69bb5SSascha Wildner   }
51750a69bb5SSascha Wildner 
51850a69bb5SSascha Wildner   for (i = p+p-2;i >= p;--i) {
51950a69bb5SSascha Wildner     fg[i-p] = F3_freeze(fg[i-p]+fg[i]);
52050a69bb5SSascha Wildner     fg[i-p+1] = F3_freeze(fg[i-p+1]+fg[i]);
52150a69bb5SSascha Wildner   }
52250a69bb5SSascha Wildner 
52350a69bb5SSascha Wildner   for (i = 0;i < p;++i) h[i] = fg[i];
52450a69bb5SSascha Wildner }
52550a69bb5SSascha Wildner 
52650a69bb5SSascha Wildner /* returns 0 if recip succeeded; else -1 */
R3_recip(small * out,const small * in)52750a69bb5SSascha Wildner static int R3_recip(small *out,const small *in)
52850a69bb5SSascha Wildner {
52950a69bb5SSascha Wildner   small f[p+1],g[p+1],v[p+1],r[p+1];
53050a69bb5SSascha Wildner   int i,loop,delta;
53150a69bb5SSascha Wildner   int sign,swap,t;
53250a69bb5SSascha Wildner 
53350a69bb5SSascha Wildner   for (i = 0;i < p+1;++i) v[i] = 0;
53450a69bb5SSascha Wildner   for (i = 0;i < p+1;++i) r[i] = 0;
53550a69bb5SSascha Wildner   r[0] = 1;
53650a69bb5SSascha Wildner   for (i = 0;i < p;++i) f[i] = 0;
53750a69bb5SSascha Wildner   f[0] = 1; f[p-1] = f[p] = -1;
53850a69bb5SSascha Wildner   for (i = 0;i < p;++i) g[p-1-i] = in[i];
53950a69bb5SSascha Wildner   g[p] = 0;
54050a69bb5SSascha Wildner 
54150a69bb5SSascha Wildner   delta = 1;
54250a69bb5SSascha Wildner 
54350a69bb5SSascha Wildner   for (loop = 0;loop < 2*p-1;++loop) {
54450a69bb5SSascha Wildner     for (i = p;i > 0;--i) v[i] = v[i-1];
54550a69bb5SSascha Wildner     v[0] = 0;
54650a69bb5SSascha Wildner 
54750a69bb5SSascha Wildner     sign = -g[0]*f[0];
54850a69bb5SSascha Wildner     swap = int16_negative_mask(-delta) & int16_nonzero_mask(g[0]);
54950a69bb5SSascha Wildner     delta ^= swap&(delta^-delta);
55050a69bb5SSascha Wildner     delta += 1;
55150a69bb5SSascha Wildner 
55250a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) {
55350a69bb5SSascha Wildner       t = swap&(f[i]^g[i]); f[i] ^= t; g[i] ^= t;
55450a69bb5SSascha Wildner       t = swap&(v[i]^r[i]); v[i] ^= t; r[i] ^= t;
55550a69bb5SSascha Wildner     }
55650a69bb5SSascha Wildner 
55750a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) g[i] = F3_freeze(g[i]+sign*f[i]);
55850a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) r[i] = F3_freeze(r[i]+sign*v[i]);
55950a69bb5SSascha Wildner 
56050a69bb5SSascha Wildner     for (i = 0;i < p;++i) g[i] = g[i+1];
56150a69bb5SSascha Wildner     g[p] = 0;
56250a69bb5SSascha Wildner   }
56350a69bb5SSascha Wildner 
56450a69bb5SSascha Wildner   sign = f[0];
56550a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = sign*v[p-1-i];
56650a69bb5SSascha Wildner 
56750a69bb5SSascha Wildner   return int16_nonzero_mask(delta);
56850a69bb5SSascha Wildner }
56950a69bb5SSascha Wildner 
57050a69bb5SSascha Wildner #endif
57150a69bb5SSascha Wildner 
57250a69bb5SSascha Wildner /* ----- polynomials mod q */
57350a69bb5SSascha Wildner 
57450a69bb5SSascha Wildner /* h = f*g in the ring Rq */
Rq_mult_small(Fq * h,const Fq * f,const small * g)57550a69bb5SSascha Wildner static void Rq_mult_small(Fq *h,const Fq *f,const small *g)
57650a69bb5SSascha Wildner {
57750a69bb5SSascha Wildner   Fq fg[p+p-1];
57850a69bb5SSascha Wildner   Fq result;
57950a69bb5SSascha Wildner   int i,j;
58050a69bb5SSascha Wildner 
58150a69bb5SSascha Wildner   for (i = 0;i < p;++i) {
58250a69bb5SSascha Wildner     result = 0;
58350a69bb5SSascha Wildner     for (j = 0;j <= i;++j) result = Fq_freeze(result+f[j]*(int32)g[i-j]);
58450a69bb5SSascha Wildner     fg[i] = result;
58550a69bb5SSascha Wildner   }
58650a69bb5SSascha Wildner   for (i = p;i < p+p-1;++i) {
58750a69bb5SSascha Wildner     result = 0;
58850a69bb5SSascha Wildner     for (j = i-p+1;j < p;++j) result = Fq_freeze(result+f[j]*(int32)g[i-j]);
58950a69bb5SSascha Wildner     fg[i] = result;
59050a69bb5SSascha Wildner   }
59150a69bb5SSascha Wildner 
59250a69bb5SSascha Wildner   for (i = p+p-2;i >= p;--i) {
59350a69bb5SSascha Wildner     fg[i-p] = Fq_freeze(fg[i-p]+fg[i]);
59450a69bb5SSascha Wildner     fg[i-p+1] = Fq_freeze(fg[i-p+1]+fg[i]);
59550a69bb5SSascha Wildner   }
59650a69bb5SSascha Wildner 
59750a69bb5SSascha Wildner   for (i = 0;i < p;++i) h[i] = fg[i];
59850a69bb5SSascha Wildner }
59950a69bb5SSascha Wildner 
60050a69bb5SSascha Wildner #ifndef LPR
60150a69bb5SSascha Wildner 
60250a69bb5SSascha Wildner /* h = 3f in Rq */
Rq_mult3(Fq * h,const Fq * f)60350a69bb5SSascha Wildner static void Rq_mult3(Fq *h,const Fq *f)
60450a69bb5SSascha Wildner {
60550a69bb5SSascha Wildner   int i;
60650a69bb5SSascha Wildner 
60750a69bb5SSascha Wildner   for (i = 0;i < p;++i) h[i] = Fq_freeze(3*f[i]);
60850a69bb5SSascha Wildner }
60950a69bb5SSascha Wildner 
61050a69bb5SSascha Wildner /* out = 1/(3*in) in Rq */
61150a69bb5SSascha Wildner /* returns 0 if recip succeeded; else -1 */
Rq_recip3(Fq * out,const small * in)61250a69bb5SSascha Wildner static int Rq_recip3(Fq *out,const small *in)
61350a69bb5SSascha Wildner {
61450a69bb5SSascha Wildner   Fq f[p+1],g[p+1],v[p+1],r[p+1];
61550a69bb5SSascha Wildner   int i,loop,delta;
61650a69bb5SSascha Wildner   int swap,t;
61750a69bb5SSascha Wildner   int32 f0,g0;
61850a69bb5SSascha Wildner   Fq scale;
61950a69bb5SSascha Wildner 
62050a69bb5SSascha Wildner   for (i = 0;i < p+1;++i) v[i] = 0;
62150a69bb5SSascha Wildner   for (i = 0;i < p+1;++i) r[i] = 0;
62250a69bb5SSascha Wildner   r[0] = Fq_recip(3);
62350a69bb5SSascha Wildner   for (i = 0;i < p;++i) f[i] = 0;
62450a69bb5SSascha Wildner   f[0] = 1; f[p-1] = f[p] = -1;
62550a69bb5SSascha Wildner   for (i = 0;i < p;++i) g[p-1-i] = in[i];
62650a69bb5SSascha Wildner   g[p] = 0;
62750a69bb5SSascha Wildner 
62850a69bb5SSascha Wildner   delta = 1;
62950a69bb5SSascha Wildner 
63050a69bb5SSascha Wildner   for (loop = 0;loop < 2*p-1;++loop) {
63150a69bb5SSascha Wildner     for (i = p;i > 0;--i) v[i] = v[i-1];
63250a69bb5SSascha Wildner     v[0] = 0;
63350a69bb5SSascha Wildner 
63450a69bb5SSascha Wildner     swap = int16_negative_mask(-delta) & int16_nonzero_mask(g[0]);
63550a69bb5SSascha Wildner     delta ^= swap&(delta^-delta);
63650a69bb5SSascha Wildner     delta += 1;
63750a69bb5SSascha Wildner 
63850a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) {
63950a69bb5SSascha Wildner       t = swap&(f[i]^g[i]); f[i] ^= t; g[i] ^= t;
64050a69bb5SSascha Wildner       t = swap&(v[i]^r[i]); v[i] ^= t; r[i] ^= t;
64150a69bb5SSascha Wildner     }
64250a69bb5SSascha Wildner 
64350a69bb5SSascha Wildner     f0 = f[0];
64450a69bb5SSascha Wildner     g0 = g[0];
64550a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) g[i] = Fq_freeze(f0*g[i]-g0*f[i]);
64650a69bb5SSascha Wildner     for (i = 0;i < p+1;++i) r[i] = Fq_freeze(f0*r[i]-g0*v[i]);
64750a69bb5SSascha Wildner 
64850a69bb5SSascha Wildner     for (i = 0;i < p;++i) g[i] = g[i+1];
64950a69bb5SSascha Wildner     g[p] = 0;
65050a69bb5SSascha Wildner   }
65150a69bb5SSascha Wildner 
65250a69bb5SSascha Wildner   scale = Fq_recip(f[0]);
65350a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = Fq_freeze(scale*(int32)v[p-1-i]);
65450a69bb5SSascha Wildner 
65550a69bb5SSascha Wildner   return int16_nonzero_mask(delta);
65650a69bb5SSascha Wildner }
65750a69bb5SSascha Wildner 
65850a69bb5SSascha Wildner #endif
65950a69bb5SSascha Wildner 
66050a69bb5SSascha Wildner /* ----- rounded polynomials mod q */
66150a69bb5SSascha Wildner 
Round(Fq * out,const Fq * a)66250a69bb5SSascha Wildner static void Round(Fq *out,const Fq *a)
66350a69bb5SSascha Wildner {
66450a69bb5SSascha Wildner   int i;
66550a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = a[i]-F3_freeze(a[i]);
66650a69bb5SSascha Wildner }
66750a69bb5SSascha Wildner 
66850a69bb5SSascha Wildner /* ----- sorting to generate short polynomial */
66950a69bb5SSascha Wildner 
Short_fromlist(small * out,const uint32 * in)67050a69bb5SSascha Wildner static void Short_fromlist(small *out,const uint32 *in)
67150a69bb5SSascha Wildner {
67250a69bb5SSascha Wildner   uint32 L[p];
67350a69bb5SSascha Wildner   int i;
67450a69bb5SSascha Wildner 
67550a69bb5SSascha Wildner   for (i = 0;i < w;++i) L[i] = in[i]&(uint32)-2;
67650a69bb5SSascha Wildner   for (i = w;i < p;++i) L[i] = (in[i]&(uint32)-3)|1;
67750a69bb5SSascha Wildner   crypto_sort_uint32(L,p);
67850a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = (L[i]&3)-1;
67950a69bb5SSascha Wildner }
68050a69bb5SSascha Wildner 
68150a69bb5SSascha Wildner /* ----- underlying hash function */
68250a69bb5SSascha Wildner 
68350a69bb5SSascha Wildner #define Hash_bytes 32
68450a69bb5SSascha Wildner 
68550a69bb5SSascha Wildner /* e.g., b = 0 means out = Hash0(in) */
Hash_prefix(unsigned char * out,int b,const unsigned char * in,int inlen)68650a69bb5SSascha Wildner static void Hash_prefix(unsigned char *out,int b,const unsigned char *in,int inlen)
68750a69bb5SSascha Wildner {
68850a69bb5SSascha Wildner   unsigned char x[inlen+1];
68950a69bb5SSascha Wildner   unsigned char h[64];
69050a69bb5SSascha Wildner   int i;
69150a69bb5SSascha Wildner 
69250a69bb5SSascha Wildner   x[0] = b;
69350a69bb5SSascha Wildner   for (i = 0;i < inlen;++i) x[i+1] = in[i];
69450a69bb5SSascha Wildner   crypto_hash_sha512(h,x,inlen+1);
69550a69bb5SSascha Wildner   for (i = 0;i < 32;++i) out[i] = h[i];
69650a69bb5SSascha Wildner }
69750a69bb5SSascha Wildner 
69850a69bb5SSascha Wildner /* ----- higher-level randomness */
69950a69bb5SSascha Wildner 
urandom32(void)70050a69bb5SSascha Wildner static uint32 urandom32(void)
70150a69bb5SSascha Wildner {
70250a69bb5SSascha Wildner   unsigned char c[4];
70350a69bb5SSascha Wildner   uint32 out[4];
70450a69bb5SSascha Wildner 
70550a69bb5SSascha Wildner   randombytes(c,4);
70650a69bb5SSascha Wildner   out[0] = (uint32)c[0];
70750a69bb5SSascha Wildner   out[1] = ((uint32)c[1])<<8;
70850a69bb5SSascha Wildner   out[2] = ((uint32)c[2])<<16;
70950a69bb5SSascha Wildner   out[3] = ((uint32)c[3])<<24;
71050a69bb5SSascha Wildner   return out[0]+out[1]+out[2]+out[3];
71150a69bb5SSascha Wildner }
71250a69bb5SSascha Wildner 
Short_random(small * out)71350a69bb5SSascha Wildner static void Short_random(small *out)
71450a69bb5SSascha Wildner {
71550a69bb5SSascha Wildner   uint32 L[p];
71650a69bb5SSascha Wildner   int i;
71750a69bb5SSascha Wildner 
71850a69bb5SSascha Wildner   for (i = 0;i < p;++i) L[i] = urandom32();
71950a69bb5SSascha Wildner   Short_fromlist(out,L);
72050a69bb5SSascha Wildner }
72150a69bb5SSascha Wildner 
72250a69bb5SSascha Wildner #ifndef LPR
72350a69bb5SSascha Wildner 
Small_random(small * out)72450a69bb5SSascha Wildner static void Small_random(small *out)
72550a69bb5SSascha Wildner {
72650a69bb5SSascha Wildner   int i;
72750a69bb5SSascha Wildner 
72850a69bb5SSascha Wildner   for (i = 0;i < p;++i) out[i] = (((urandom32()&0x3fffffff)*3)>>30)-1;
72950a69bb5SSascha Wildner }
73050a69bb5SSascha Wildner 
73150a69bb5SSascha Wildner #endif
73250a69bb5SSascha Wildner 
73350a69bb5SSascha Wildner /* ----- Streamlined NTRU Prime Core */
73450a69bb5SSascha Wildner 
73550a69bb5SSascha Wildner #ifndef LPR
73650a69bb5SSascha Wildner 
73750a69bb5SSascha Wildner /* h,(f,ginv) = KeyGen() */
KeyGen(Fq * h,small * f,small * ginv)73850a69bb5SSascha Wildner static void KeyGen(Fq *h,small *f,small *ginv)
73950a69bb5SSascha Wildner {
74050a69bb5SSascha Wildner   small g[p];
74150a69bb5SSascha Wildner   Fq finv[p];
74250a69bb5SSascha Wildner 
74350a69bb5SSascha Wildner   for (;;) {
74450a69bb5SSascha Wildner     Small_random(g);
74550a69bb5SSascha Wildner     if (R3_recip(ginv,g) == 0) break;
74650a69bb5SSascha Wildner   }
74750a69bb5SSascha Wildner   Short_random(f);
74850a69bb5SSascha Wildner   Rq_recip3(finv,f); /* always works */
74950a69bb5SSascha Wildner   Rq_mult_small(h,finv,g);
75050a69bb5SSascha Wildner }
75150a69bb5SSascha Wildner 
75250a69bb5SSascha Wildner /* c = Encrypt(r,h) */
Encrypt(Fq * c,const small * r,const Fq * h)75350a69bb5SSascha Wildner static void Encrypt(Fq *c,const small *r,const Fq *h)
75450a69bb5SSascha Wildner {
75550a69bb5SSascha Wildner   Fq hr[p];
75650a69bb5SSascha Wildner 
75750a69bb5SSascha Wildner   Rq_mult_small(hr,h,r);
75850a69bb5SSascha Wildner   Round(c,hr);
75950a69bb5SSascha Wildner }
76050a69bb5SSascha Wildner 
76150a69bb5SSascha Wildner /* r = Decrypt(c,(f,ginv)) */
Decrypt(small * r,const Fq * c,const small * f,const small * ginv)76250a69bb5SSascha Wildner static void Decrypt(small *r,const Fq *c,const small *f,const small *ginv)
76350a69bb5SSascha Wildner {
76450a69bb5SSascha Wildner   Fq cf[p];
76550a69bb5SSascha Wildner   Fq cf3[p];
76650a69bb5SSascha Wildner   small e[p];
76750a69bb5SSascha Wildner   small ev[p];
76850a69bb5SSascha Wildner   int mask;
76950a69bb5SSascha Wildner   int i;
77050a69bb5SSascha Wildner 
77150a69bb5SSascha Wildner   Rq_mult_small(cf,c,f);
77250a69bb5SSascha Wildner   Rq_mult3(cf3,cf);
77350a69bb5SSascha Wildner   R3_fromRq(e,cf3);
77450a69bb5SSascha Wildner   R3_mult(ev,e,ginv);
77550a69bb5SSascha Wildner 
77650a69bb5SSascha Wildner   mask = Weightw_mask(ev); /* 0 if weight w, else -1 */
77750a69bb5SSascha Wildner   for (i = 0;i < w;++i) r[i] = ((ev[i]^1)&~mask)^1;
77850a69bb5SSascha Wildner   for (i = w;i < p;++i) r[i] = ev[i]&~mask;
77950a69bb5SSascha Wildner }
78050a69bb5SSascha Wildner 
78150a69bb5SSascha Wildner #endif
78250a69bb5SSascha Wildner 
78350a69bb5SSascha Wildner /* ----- NTRU LPRime Core */
78450a69bb5SSascha Wildner 
78550a69bb5SSascha Wildner #ifdef LPR
78650a69bb5SSascha Wildner 
78750a69bb5SSascha Wildner /* (G,A),a = KeyGen(G); leaves G unchanged */
KeyGen(Fq * A,small * a,const Fq * G)78850a69bb5SSascha Wildner static void KeyGen(Fq *A,small *a,const Fq *G)
78950a69bb5SSascha Wildner {
79050a69bb5SSascha Wildner   Fq aG[p];
79150a69bb5SSascha Wildner 
79250a69bb5SSascha Wildner   Short_random(a);
79350a69bb5SSascha Wildner   Rq_mult_small(aG,G,a);
79450a69bb5SSascha Wildner   Round(A,aG);
79550a69bb5SSascha Wildner }
79650a69bb5SSascha Wildner 
79750a69bb5SSascha Wildner /* B,T = Encrypt(r,(G,A),b) */
Encrypt(Fq * B,int8 * T,const int8 * r,const Fq * G,const Fq * A,const small * b)79850a69bb5SSascha Wildner static void Encrypt(Fq *B,int8 *T,const int8 *r,const Fq *G,const Fq *A,const small *b)
79950a69bb5SSascha Wildner {
80050a69bb5SSascha Wildner   Fq bG[p];
80150a69bb5SSascha Wildner   Fq bA[p];
80250a69bb5SSascha Wildner   int i;
80350a69bb5SSascha Wildner 
80450a69bb5SSascha Wildner   Rq_mult_small(bG,G,b);
80550a69bb5SSascha Wildner   Round(B,bG);
80650a69bb5SSascha Wildner   Rq_mult_small(bA,A,b);
80750a69bb5SSascha Wildner   for (i = 0;i < I;++i) T[i] = Top(Fq_freeze(bA[i]+r[i]*q12));
80850a69bb5SSascha Wildner }
80950a69bb5SSascha Wildner 
81050a69bb5SSascha Wildner /* r = Decrypt((B,T),a) */
Decrypt(int8 * r,const Fq * B,const int8 * T,const small * a)81150a69bb5SSascha Wildner static void Decrypt(int8 *r,const Fq *B,const int8 *T,const small *a)
81250a69bb5SSascha Wildner {
81350a69bb5SSascha Wildner   Fq aB[p];
81450a69bb5SSascha Wildner   int i;
81550a69bb5SSascha Wildner 
81650a69bb5SSascha Wildner   Rq_mult_small(aB,B,a);
81750a69bb5SSascha Wildner   for (i = 0;i < I;++i)
81850a69bb5SSascha Wildner     r[i] = -int16_negative_mask(Fq_freeze(Right(T[i])-aB[i]+4*w+1));
81950a69bb5SSascha Wildner }
82050a69bb5SSascha Wildner 
82150a69bb5SSascha Wildner #endif
82250a69bb5SSascha Wildner 
82350a69bb5SSascha Wildner /* ----- encoding I-bit inputs */
82450a69bb5SSascha Wildner 
82550a69bb5SSascha Wildner #ifdef LPR
82650a69bb5SSascha Wildner 
82750a69bb5SSascha Wildner #define Inputs_bytes (I/8)
82850a69bb5SSascha Wildner typedef int8 Inputs[I]; /* passed by reference */
82950a69bb5SSascha Wildner 
Inputs_encode(unsigned char * s,const Inputs r)83050a69bb5SSascha Wildner static void Inputs_encode(unsigned char *s,const Inputs r)
83150a69bb5SSascha Wildner {
83250a69bb5SSascha Wildner   int i;
83350a69bb5SSascha Wildner   for (i = 0;i < Inputs_bytes;++i) s[i] = 0;
83450a69bb5SSascha Wildner   for (i = 0;i < I;++i) s[i>>3] |= r[i]<<(i&7);
83550a69bb5SSascha Wildner }
83650a69bb5SSascha Wildner 
83750a69bb5SSascha Wildner #endif
83850a69bb5SSascha Wildner 
83950a69bb5SSascha Wildner /* ----- Expand */
84050a69bb5SSascha Wildner 
84150a69bb5SSascha Wildner #ifdef LPR
84250a69bb5SSascha Wildner 
84350a69bb5SSascha Wildner static const unsigned char aes_nonce[16] = {0};
84450a69bb5SSascha Wildner 
Expand(uint32 * L,const unsigned char * k)84550a69bb5SSascha Wildner static void Expand(uint32 *L,const unsigned char *k)
84650a69bb5SSascha Wildner {
84750a69bb5SSascha Wildner   int i;
84850a69bb5SSascha Wildner   crypto_stream_aes256ctr((unsigned char *) L,4*p,aes_nonce,k);
84950a69bb5SSascha Wildner   for (i = 0;i < p;++i) {
85050a69bb5SSascha Wildner     uint32 L0 = ((unsigned char *) L)[4*i];
85150a69bb5SSascha Wildner     uint32 L1 = ((unsigned char *) L)[4*i+1];
85250a69bb5SSascha Wildner     uint32 L2 = ((unsigned char *) L)[4*i+2];
85350a69bb5SSascha Wildner     uint32 L3 = ((unsigned char *) L)[4*i+3];
85450a69bb5SSascha Wildner     L[i] = L0+(L1<<8)+(L2<<16)+(L3<<24);
85550a69bb5SSascha Wildner   }
85650a69bb5SSascha Wildner }
85750a69bb5SSascha Wildner 
85850a69bb5SSascha Wildner #endif
85950a69bb5SSascha Wildner 
86050a69bb5SSascha Wildner /* ----- Seeds */
86150a69bb5SSascha Wildner 
86250a69bb5SSascha Wildner #ifdef LPR
86350a69bb5SSascha Wildner 
86450a69bb5SSascha Wildner #define Seeds_bytes 32
86550a69bb5SSascha Wildner 
Seeds_random(unsigned char * s)86650a69bb5SSascha Wildner static void Seeds_random(unsigned char *s)
86750a69bb5SSascha Wildner {
86850a69bb5SSascha Wildner   randombytes(s,Seeds_bytes);
86950a69bb5SSascha Wildner }
87050a69bb5SSascha Wildner 
87150a69bb5SSascha Wildner #endif
87250a69bb5SSascha Wildner 
87350a69bb5SSascha Wildner /* ----- Generator, HashShort */
87450a69bb5SSascha Wildner 
87550a69bb5SSascha Wildner #ifdef LPR
87650a69bb5SSascha Wildner 
87750a69bb5SSascha Wildner /* G = Generator(k) */
Generator(Fq * G,const unsigned char * k)87850a69bb5SSascha Wildner static void Generator(Fq *G,const unsigned char *k)
87950a69bb5SSascha Wildner {
88050a69bb5SSascha Wildner   uint32 L[p];
88150a69bb5SSascha Wildner   int i;
88250a69bb5SSascha Wildner 
88350a69bb5SSascha Wildner   Expand(L,k);
88450a69bb5SSascha Wildner   for (i = 0;i < p;++i) G[i] = uint32_mod_uint14(L[i],q)-q12;
88550a69bb5SSascha Wildner }
88650a69bb5SSascha Wildner 
88750a69bb5SSascha Wildner /* out = HashShort(r) */
HashShort(small * out,const Inputs r)88850a69bb5SSascha Wildner static void HashShort(small *out,const Inputs r)
88950a69bb5SSascha Wildner {
89050a69bb5SSascha Wildner   unsigned char s[Inputs_bytes];
89150a69bb5SSascha Wildner   unsigned char h[Hash_bytes];
89250a69bb5SSascha Wildner   uint32 L[p];
89350a69bb5SSascha Wildner 
89450a69bb5SSascha Wildner   Inputs_encode(s,r);
89550a69bb5SSascha Wildner   Hash_prefix(h,5,s,sizeof s);
89650a69bb5SSascha Wildner   Expand(L,h);
89750a69bb5SSascha Wildner   Short_fromlist(out,L);
89850a69bb5SSascha Wildner }
89950a69bb5SSascha Wildner 
90050a69bb5SSascha Wildner #endif
90150a69bb5SSascha Wildner 
90250a69bb5SSascha Wildner /* ----- NTRU LPRime Expand */
90350a69bb5SSascha Wildner 
90450a69bb5SSascha Wildner #ifdef LPR
90550a69bb5SSascha Wildner 
90650a69bb5SSascha Wildner /* (S,A),a = XKeyGen() */
XKeyGen(unsigned char * S,Fq * A,small * a)90750a69bb5SSascha Wildner static void XKeyGen(unsigned char *S,Fq *A,small *a)
90850a69bb5SSascha Wildner {
90950a69bb5SSascha Wildner   Fq G[p];
91050a69bb5SSascha Wildner 
91150a69bb5SSascha Wildner   Seeds_random(S);
91250a69bb5SSascha Wildner   Generator(G,S);
91350a69bb5SSascha Wildner   KeyGen(A,a,G);
91450a69bb5SSascha Wildner }
91550a69bb5SSascha Wildner 
91650a69bb5SSascha Wildner /* B,T = XEncrypt(r,(S,A)) */
XEncrypt(Fq * B,int8 * T,const int8 * r,const unsigned char * S,const Fq * A)91750a69bb5SSascha Wildner static void XEncrypt(Fq *B,int8 *T,const int8 *r,const unsigned char *S,const Fq *A)
91850a69bb5SSascha Wildner {
91950a69bb5SSascha Wildner   Fq G[p];
92050a69bb5SSascha Wildner   small b[p];
92150a69bb5SSascha Wildner 
92250a69bb5SSascha Wildner   Generator(G,S);
92350a69bb5SSascha Wildner   HashShort(b,r);
92450a69bb5SSascha Wildner   Encrypt(B,T,r,G,A,b);
92550a69bb5SSascha Wildner }
92650a69bb5SSascha Wildner 
92750a69bb5SSascha Wildner #define XDecrypt Decrypt
92850a69bb5SSascha Wildner 
92950a69bb5SSascha Wildner #endif
93050a69bb5SSascha Wildner 
93150a69bb5SSascha Wildner /* ----- encoding small polynomials (including short polynomials) */
93250a69bb5SSascha Wildner 
93350a69bb5SSascha Wildner #define Small_bytes ((p+3)/4)
93450a69bb5SSascha Wildner 
93550a69bb5SSascha Wildner /* these are the only functions that rely on p mod 4 = 1 */
93650a69bb5SSascha Wildner 
Small_encode(unsigned char * s,const small * f)93750a69bb5SSascha Wildner static void Small_encode(unsigned char *s,const small *f)
93850a69bb5SSascha Wildner {
93950a69bb5SSascha Wildner   small x;
94050a69bb5SSascha Wildner   int i;
94150a69bb5SSascha Wildner 
94250a69bb5SSascha Wildner   for (i = 0;i < p/4;++i) {
94350a69bb5SSascha Wildner     x = *f++ + 1;
94450a69bb5SSascha Wildner     x += (*f++ + 1)<<2;
94550a69bb5SSascha Wildner     x += (*f++ + 1)<<4;
94650a69bb5SSascha Wildner     x += (*f++ + 1)<<6;
94750a69bb5SSascha Wildner     *s++ = x;
94850a69bb5SSascha Wildner   }
94950a69bb5SSascha Wildner   x = *f++ + 1;
95050a69bb5SSascha Wildner   *s++ = x;
95150a69bb5SSascha Wildner }
95250a69bb5SSascha Wildner 
Small_decode(small * f,const unsigned char * s)95350a69bb5SSascha Wildner static void Small_decode(small *f,const unsigned char *s)
95450a69bb5SSascha Wildner {
95550a69bb5SSascha Wildner   unsigned char x;
95650a69bb5SSascha Wildner   int i;
95750a69bb5SSascha Wildner 
95850a69bb5SSascha Wildner   for (i = 0;i < p/4;++i) {
95950a69bb5SSascha Wildner     x = *s++;
96050a69bb5SSascha Wildner     *f++ = ((small)(x&3))-1; x >>= 2;
96150a69bb5SSascha Wildner     *f++ = ((small)(x&3))-1; x >>= 2;
96250a69bb5SSascha Wildner     *f++ = ((small)(x&3))-1; x >>= 2;
96350a69bb5SSascha Wildner     *f++ = ((small)(x&3))-1;
96450a69bb5SSascha Wildner   }
96550a69bb5SSascha Wildner   x = *s++;
96650a69bb5SSascha Wildner   *f++ = ((small)(x&3))-1;
96750a69bb5SSascha Wildner }
96850a69bb5SSascha Wildner 
96950a69bb5SSascha Wildner /* ----- encoding general polynomials */
97050a69bb5SSascha Wildner 
97150a69bb5SSascha Wildner #ifndef LPR
97250a69bb5SSascha Wildner 
Rq_encode(unsigned char * s,const Fq * r)97350a69bb5SSascha Wildner static void Rq_encode(unsigned char *s,const Fq *r)
97450a69bb5SSascha Wildner {
97550a69bb5SSascha Wildner   uint16 R[p],M[p];
97650a69bb5SSascha Wildner   int i;
97750a69bb5SSascha Wildner 
97850a69bb5SSascha Wildner   for (i = 0;i < p;++i) R[i] = r[i]+q12;
97950a69bb5SSascha Wildner   for (i = 0;i < p;++i) M[i] = q;
98050a69bb5SSascha Wildner   Encode(s,R,M,p);
98150a69bb5SSascha Wildner }
98250a69bb5SSascha Wildner 
Rq_decode(Fq * r,const unsigned char * s)98350a69bb5SSascha Wildner static void Rq_decode(Fq *r,const unsigned char *s)
98450a69bb5SSascha Wildner {
98550a69bb5SSascha Wildner   uint16 R[p],M[p];
98650a69bb5SSascha Wildner   int i;
98750a69bb5SSascha Wildner 
98850a69bb5SSascha Wildner   for (i = 0;i < p;++i) M[i] = q;
98950a69bb5SSascha Wildner   Decode(R,s,M,p);
99050a69bb5SSascha Wildner   for (i = 0;i < p;++i) r[i] = ((Fq)R[i])-q12;
99150a69bb5SSascha Wildner }
99250a69bb5SSascha Wildner 
99350a69bb5SSascha Wildner #endif
99450a69bb5SSascha Wildner 
99550a69bb5SSascha Wildner /* ----- encoding rounded polynomials */
99650a69bb5SSascha Wildner 
Rounded_encode(unsigned char * s,const Fq * r)99750a69bb5SSascha Wildner static void Rounded_encode(unsigned char *s,const Fq *r)
99850a69bb5SSascha Wildner {
99950a69bb5SSascha Wildner   uint16 R[p],M[p];
100050a69bb5SSascha Wildner   int i;
100150a69bb5SSascha Wildner 
100250a69bb5SSascha Wildner   for (i = 0;i < p;++i) R[i] = ((r[i]+q12)*10923)>>15;
100350a69bb5SSascha Wildner   for (i = 0;i < p;++i) M[i] = (q+2)/3;
100450a69bb5SSascha Wildner   Encode(s,R,M,p);
100550a69bb5SSascha Wildner }
100650a69bb5SSascha Wildner 
Rounded_decode(Fq * r,const unsigned char * s)100750a69bb5SSascha Wildner static void Rounded_decode(Fq *r,const unsigned char *s)
100850a69bb5SSascha Wildner {
100950a69bb5SSascha Wildner   uint16 R[p],M[p];
101050a69bb5SSascha Wildner   int i;
101150a69bb5SSascha Wildner 
101250a69bb5SSascha Wildner   for (i = 0;i < p;++i) M[i] = (q+2)/3;
101350a69bb5SSascha Wildner   Decode(R,s,M,p);
101450a69bb5SSascha Wildner   for (i = 0;i < p;++i) r[i] = R[i]*3-q12;
101550a69bb5SSascha Wildner }
101650a69bb5SSascha Wildner 
101750a69bb5SSascha Wildner /* ----- encoding top polynomials */
101850a69bb5SSascha Wildner 
101950a69bb5SSascha Wildner #ifdef LPR
102050a69bb5SSascha Wildner 
102150a69bb5SSascha Wildner #define Top_bytes (I/2)
102250a69bb5SSascha Wildner 
Top_encode(unsigned char * s,const int8 * T)102350a69bb5SSascha Wildner static void Top_encode(unsigned char *s,const int8 *T)
102450a69bb5SSascha Wildner {
102550a69bb5SSascha Wildner   int i;
102650a69bb5SSascha Wildner   for (i = 0;i < Top_bytes;++i)
102750a69bb5SSascha Wildner     s[i] = T[2*i]+(T[2*i+1]<<4);
102850a69bb5SSascha Wildner }
102950a69bb5SSascha Wildner 
Top_decode(int8 * T,const unsigned char * s)103050a69bb5SSascha Wildner static void Top_decode(int8 *T,const unsigned char *s)
103150a69bb5SSascha Wildner {
103250a69bb5SSascha Wildner   int i;
103350a69bb5SSascha Wildner   for (i = 0;i < Top_bytes;++i) {
103450a69bb5SSascha Wildner     T[2*i] = s[i]&15;
103550a69bb5SSascha Wildner     T[2*i+1] = s[i]>>4;
103650a69bb5SSascha Wildner   }
103750a69bb5SSascha Wildner }
103850a69bb5SSascha Wildner 
103950a69bb5SSascha Wildner #endif
104050a69bb5SSascha Wildner 
104150a69bb5SSascha Wildner /* ----- Streamlined NTRU Prime Core plus encoding */
104250a69bb5SSascha Wildner 
104350a69bb5SSascha Wildner #ifndef LPR
104450a69bb5SSascha Wildner 
104550a69bb5SSascha Wildner typedef small Inputs[p]; /* passed by reference */
104650a69bb5SSascha Wildner #define Inputs_random Short_random
104750a69bb5SSascha Wildner #define Inputs_encode Small_encode
104850a69bb5SSascha Wildner #define Inputs_bytes Small_bytes
104950a69bb5SSascha Wildner 
105050a69bb5SSascha Wildner #define Ciphertexts_bytes Rounded_bytes
105150a69bb5SSascha Wildner #define SecretKeys_bytes (2*Small_bytes)
105250a69bb5SSascha Wildner #define PublicKeys_bytes Rq_bytes
105350a69bb5SSascha Wildner 
105450a69bb5SSascha Wildner /* pk,sk = ZKeyGen() */
ZKeyGen(unsigned char * pk,unsigned char * sk)105550a69bb5SSascha Wildner static void ZKeyGen(unsigned char *pk,unsigned char *sk)
105650a69bb5SSascha Wildner {
105750a69bb5SSascha Wildner   Fq h[p];
105850a69bb5SSascha Wildner   small f[p],v[p];
105950a69bb5SSascha Wildner 
106050a69bb5SSascha Wildner   KeyGen(h,f,v);
106150a69bb5SSascha Wildner   Rq_encode(pk,h);
106250a69bb5SSascha Wildner   Small_encode(sk,f); sk += Small_bytes;
106350a69bb5SSascha Wildner   Small_encode(sk,v);
106450a69bb5SSascha Wildner }
106550a69bb5SSascha Wildner 
106650a69bb5SSascha Wildner /* C = ZEncrypt(r,pk) */
ZEncrypt(unsigned char * C,const Inputs r,const unsigned char * pk)106750a69bb5SSascha Wildner static void ZEncrypt(unsigned char *C,const Inputs r,const unsigned char *pk)
106850a69bb5SSascha Wildner {
106950a69bb5SSascha Wildner   Fq h[p];
107050a69bb5SSascha Wildner   Fq c[p];
107150a69bb5SSascha Wildner   Rq_decode(h,pk);
107250a69bb5SSascha Wildner   Encrypt(c,r,h);
107350a69bb5SSascha Wildner   Rounded_encode(C,c);
107450a69bb5SSascha Wildner }
107550a69bb5SSascha Wildner 
107650a69bb5SSascha Wildner /* r = ZDecrypt(C,sk) */
ZDecrypt(Inputs r,const unsigned char * C,const unsigned char * sk)107750a69bb5SSascha Wildner static void ZDecrypt(Inputs r,const unsigned char *C,const unsigned char *sk)
107850a69bb5SSascha Wildner {
107950a69bb5SSascha Wildner   small f[p],v[p];
108050a69bb5SSascha Wildner   Fq c[p];
108150a69bb5SSascha Wildner 
108250a69bb5SSascha Wildner   Small_decode(f,sk); sk += Small_bytes;
108350a69bb5SSascha Wildner   Small_decode(v,sk);
108450a69bb5SSascha Wildner   Rounded_decode(c,C);
108550a69bb5SSascha Wildner   Decrypt(r,c,f,v);
108650a69bb5SSascha Wildner }
108750a69bb5SSascha Wildner 
108850a69bb5SSascha Wildner #endif
108950a69bb5SSascha Wildner 
109050a69bb5SSascha Wildner /* ----- NTRU LPRime Expand plus encoding */
109150a69bb5SSascha Wildner 
109250a69bb5SSascha Wildner #ifdef LPR
109350a69bb5SSascha Wildner 
109450a69bb5SSascha Wildner #define Ciphertexts_bytes (Rounded_bytes+Top_bytes)
109550a69bb5SSascha Wildner #define SecretKeys_bytes Small_bytes
109650a69bb5SSascha Wildner #define PublicKeys_bytes (Seeds_bytes+Rounded_bytes)
109750a69bb5SSascha Wildner 
Inputs_random(Inputs r)109850a69bb5SSascha Wildner static void Inputs_random(Inputs r)
109950a69bb5SSascha Wildner {
110050a69bb5SSascha Wildner   unsigned char s[Inputs_bytes];
110150a69bb5SSascha Wildner   int i;
110250a69bb5SSascha Wildner 
110350a69bb5SSascha Wildner   randombytes(s,sizeof s);
110450a69bb5SSascha Wildner   for (i = 0;i < I;++i) r[i] = 1&(s[i>>3]>>(i&7));
110550a69bb5SSascha Wildner }
110650a69bb5SSascha Wildner 
110750a69bb5SSascha Wildner /* pk,sk = ZKeyGen() */
ZKeyGen(unsigned char * pk,unsigned char * sk)110850a69bb5SSascha Wildner static void ZKeyGen(unsigned char *pk,unsigned char *sk)
110950a69bb5SSascha Wildner {
111050a69bb5SSascha Wildner   Fq A[p];
111150a69bb5SSascha Wildner   small a[p];
111250a69bb5SSascha Wildner 
111350a69bb5SSascha Wildner   XKeyGen(pk,A,a); pk += Seeds_bytes;
111450a69bb5SSascha Wildner   Rounded_encode(pk,A);
111550a69bb5SSascha Wildner   Small_encode(sk,a);
111650a69bb5SSascha Wildner }
111750a69bb5SSascha Wildner 
111850a69bb5SSascha Wildner /* c = ZEncrypt(r,pk) */
ZEncrypt(unsigned char * c,const Inputs r,const unsigned char * pk)111950a69bb5SSascha Wildner static void ZEncrypt(unsigned char *c,const Inputs r,const unsigned char *pk)
112050a69bb5SSascha Wildner {
112150a69bb5SSascha Wildner   Fq A[p];
112250a69bb5SSascha Wildner   Fq B[p];
112350a69bb5SSascha Wildner   int8 T[I];
112450a69bb5SSascha Wildner 
112550a69bb5SSascha Wildner   Rounded_decode(A,pk+Seeds_bytes);
112650a69bb5SSascha Wildner   XEncrypt(B,T,r,pk,A);
112750a69bb5SSascha Wildner   Rounded_encode(c,B); c += Rounded_bytes;
112850a69bb5SSascha Wildner   Top_encode(c,T);
112950a69bb5SSascha Wildner }
113050a69bb5SSascha Wildner 
113150a69bb5SSascha Wildner /* r = ZDecrypt(C,sk) */
ZDecrypt(Inputs r,const unsigned char * c,const unsigned char * sk)113250a69bb5SSascha Wildner static void ZDecrypt(Inputs r,const unsigned char *c,const unsigned char *sk)
113350a69bb5SSascha Wildner {
113450a69bb5SSascha Wildner   small a[p];
113550a69bb5SSascha Wildner   Fq B[p];
113650a69bb5SSascha Wildner   int8 T[I];
113750a69bb5SSascha Wildner 
113850a69bb5SSascha Wildner   Small_decode(a,sk);
113950a69bb5SSascha Wildner   Rounded_decode(B,c);
114050a69bb5SSascha Wildner   Top_decode(T,c+Rounded_bytes);
114150a69bb5SSascha Wildner   XDecrypt(r,B,T,a);
114250a69bb5SSascha Wildner }
114350a69bb5SSascha Wildner 
114450a69bb5SSascha Wildner #endif
114550a69bb5SSascha Wildner 
114650a69bb5SSascha Wildner /* ----- confirmation hash */
114750a69bb5SSascha Wildner 
114850a69bb5SSascha Wildner #define Confirm_bytes 32
114950a69bb5SSascha Wildner 
115050a69bb5SSascha Wildner /* h = HashConfirm(r,pk,cache); cache is Hash4(pk) */
HashConfirm(unsigned char * h,const unsigned char * r,const unsigned char * pk,const unsigned char * cache)115150a69bb5SSascha Wildner static void HashConfirm(unsigned char *h,const unsigned char *r,const unsigned char *pk,const unsigned char *cache)
115250a69bb5SSascha Wildner {
115350a69bb5SSascha Wildner #ifndef LPR
115450a69bb5SSascha Wildner   unsigned char x[Hash_bytes*2];
115550a69bb5SSascha Wildner   int i;
115650a69bb5SSascha Wildner 
115750a69bb5SSascha Wildner   Hash_prefix(x,3,r,Inputs_bytes);
115850a69bb5SSascha Wildner   for (i = 0;i < Hash_bytes;++i) x[Hash_bytes+i] = cache[i];
115950a69bb5SSascha Wildner #else
116050a69bb5SSascha Wildner   unsigned char x[Inputs_bytes+Hash_bytes];
116150a69bb5SSascha Wildner   int i;
116250a69bb5SSascha Wildner 
116350a69bb5SSascha Wildner   for (i = 0;i < Inputs_bytes;++i) x[i] = r[i];
116450a69bb5SSascha Wildner   for (i = 0;i < Hash_bytes;++i) x[Inputs_bytes+i] = cache[i];
116550a69bb5SSascha Wildner #endif
116650a69bb5SSascha Wildner   Hash_prefix(h,2,x,sizeof x);
116750a69bb5SSascha Wildner }
116850a69bb5SSascha Wildner 
116950a69bb5SSascha Wildner /* ----- session-key hash */
117050a69bb5SSascha Wildner 
117150a69bb5SSascha Wildner /* k = HashSession(b,y,z) */
HashSession(unsigned char * k,int b,const unsigned char * y,const unsigned char * z)117250a69bb5SSascha Wildner static void HashSession(unsigned char *k,int b,const unsigned char *y,const unsigned char *z)
117350a69bb5SSascha Wildner {
117450a69bb5SSascha Wildner #ifndef LPR
117550a69bb5SSascha Wildner   unsigned char x[Hash_bytes+Ciphertexts_bytes+Confirm_bytes];
117650a69bb5SSascha Wildner   int i;
117750a69bb5SSascha Wildner 
117850a69bb5SSascha Wildner   Hash_prefix(x,3,y,Inputs_bytes);
117950a69bb5SSascha Wildner   for (i = 0;i < Ciphertexts_bytes+Confirm_bytes;++i) x[Hash_bytes+i] = z[i];
118050a69bb5SSascha Wildner #else
118150a69bb5SSascha Wildner   unsigned char x[Inputs_bytes+Ciphertexts_bytes+Confirm_bytes];
118250a69bb5SSascha Wildner   int i;
118350a69bb5SSascha Wildner 
118450a69bb5SSascha Wildner   for (i = 0;i < Inputs_bytes;++i) x[i] = y[i];
118550a69bb5SSascha Wildner   for (i = 0;i < Ciphertexts_bytes+Confirm_bytes;++i) x[Inputs_bytes+i] = z[i];
118650a69bb5SSascha Wildner #endif
118750a69bb5SSascha Wildner   Hash_prefix(k,b,x,sizeof x);
118850a69bb5SSascha Wildner }
118950a69bb5SSascha Wildner 
119050a69bb5SSascha Wildner /* ----- Streamlined NTRU Prime and NTRU LPRime */
119150a69bb5SSascha Wildner 
119250a69bb5SSascha Wildner /* pk,sk = KEM_KeyGen() */
KEM_KeyGen(unsigned char * pk,unsigned char * sk)119350a69bb5SSascha Wildner static void KEM_KeyGen(unsigned char *pk,unsigned char *sk)
119450a69bb5SSascha Wildner {
119550a69bb5SSascha Wildner   int i;
119650a69bb5SSascha Wildner 
119750a69bb5SSascha Wildner   ZKeyGen(pk,sk); sk += SecretKeys_bytes;
119850a69bb5SSascha Wildner   for (i = 0;i < PublicKeys_bytes;++i) *sk++ = pk[i];
119950a69bb5SSascha Wildner   randombytes(sk,Inputs_bytes); sk += Inputs_bytes;
120050a69bb5SSascha Wildner   Hash_prefix(sk,4,pk,PublicKeys_bytes);
120150a69bb5SSascha Wildner }
120250a69bb5SSascha Wildner 
120350a69bb5SSascha Wildner /* c,r_enc = Hide(r,pk,cache); cache is Hash4(pk) */
Hide(unsigned char * c,unsigned char * r_enc,const Inputs r,const unsigned char * pk,const unsigned char * cache)120450a69bb5SSascha Wildner static void Hide(unsigned char *c,unsigned char *r_enc,const Inputs r,const unsigned char *pk,const unsigned char *cache)
120550a69bb5SSascha Wildner {
120650a69bb5SSascha Wildner   Inputs_encode(r_enc,r);
120750a69bb5SSascha Wildner   ZEncrypt(c,r,pk); c += Ciphertexts_bytes;
120850a69bb5SSascha Wildner   HashConfirm(c,r_enc,pk,cache);
120950a69bb5SSascha Wildner }
121050a69bb5SSascha Wildner 
121150a69bb5SSascha Wildner /* c,k = Encap(pk) */
Encap(unsigned char * c,unsigned char * k,const unsigned char * pk)121250a69bb5SSascha Wildner static void Encap(unsigned char *c,unsigned char *k,const unsigned char *pk)
121350a69bb5SSascha Wildner {
121450a69bb5SSascha Wildner   Inputs r;
121550a69bb5SSascha Wildner   unsigned char r_enc[Inputs_bytes];
121650a69bb5SSascha Wildner   unsigned char cache[Hash_bytes];
121750a69bb5SSascha Wildner 
121850a69bb5SSascha Wildner   Hash_prefix(cache,4,pk,PublicKeys_bytes);
121950a69bb5SSascha Wildner   Inputs_random(r);
122050a69bb5SSascha Wildner   Hide(c,r_enc,r,pk,cache);
122150a69bb5SSascha Wildner   HashSession(k,1,r_enc,c);
122250a69bb5SSascha Wildner }
122350a69bb5SSascha Wildner 
122450a69bb5SSascha Wildner /* 0 if matching ciphertext+confirm, else -1 */
Ciphertexts_diff_mask(const unsigned char * c,const unsigned char * c2)122550a69bb5SSascha Wildner static int Ciphertexts_diff_mask(const unsigned char *c,const unsigned char *c2)
122650a69bb5SSascha Wildner {
122750a69bb5SSascha Wildner   uint16 differentbits = 0;
122850a69bb5SSascha Wildner   int len = Ciphertexts_bytes+Confirm_bytes;
122950a69bb5SSascha Wildner 
123050a69bb5SSascha Wildner   while (len-- > 0) differentbits |= (*c++)^(*c2++);
123150a69bb5SSascha Wildner   return (1&((differentbits-1)>>8))-1;
123250a69bb5SSascha Wildner }
123350a69bb5SSascha Wildner 
123450a69bb5SSascha Wildner /* k = Decap(c,sk) */
Decap(unsigned char * k,const unsigned char * c,const unsigned char * sk)123550a69bb5SSascha Wildner static void Decap(unsigned char *k,const unsigned char *c,const unsigned char *sk)
123650a69bb5SSascha Wildner {
123750a69bb5SSascha Wildner   const unsigned char *pk = sk + SecretKeys_bytes;
123850a69bb5SSascha Wildner   const unsigned char *rho = pk + PublicKeys_bytes;
123950a69bb5SSascha Wildner   const unsigned char *cache = rho + Inputs_bytes;
124050a69bb5SSascha Wildner   Inputs r;
124150a69bb5SSascha Wildner   unsigned char r_enc[Inputs_bytes];
124250a69bb5SSascha Wildner   unsigned char cnew[Ciphertexts_bytes+Confirm_bytes];
124350a69bb5SSascha Wildner   int mask;
124450a69bb5SSascha Wildner   int i;
124550a69bb5SSascha Wildner 
124650a69bb5SSascha Wildner   ZDecrypt(r,c,sk);
124750a69bb5SSascha Wildner   Hide(cnew,r_enc,r,pk,cache);
124850a69bb5SSascha Wildner   mask = Ciphertexts_diff_mask(c,cnew);
124950a69bb5SSascha Wildner   for (i = 0;i < Inputs_bytes;++i) r_enc[i] ^= mask&(r_enc[i]^rho[i]);
125050a69bb5SSascha Wildner   HashSession(k,1+mask,r_enc,c);
125150a69bb5SSascha Wildner }
125250a69bb5SSascha Wildner 
125350a69bb5SSascha Wildner /* ----- crypto_kem API */
125450a69bb5SSascha Wildner 
125550a69bb5SSascha Wildner 
crypto_kem_sntrup761_keypair(unsigned char * pk,unsigned char * sk)125650a69bb5SSascha Wildner int crypto_kem_sntrup761_keypair(unsigned char *pk,unsigned char *sk)
125750a69bb5SSascha Wildner {
125850a69bb5SSascha Wildner   KEM_KeyGen(pk,sk);
125950a69bb5SSascha Wildner   return 0;
126050a69bb5SSascha Wildner }
126150a69bb5SSascha Wildner 
crypto_kem_sntrup761_enc(unsigned char * c,unsigned char * k,const unsigned char * pk)126250a69bb5SSascha Wildner int crypto_kem_sntrup761_enc(unsigned char *c,unsigned char *k,const unsigned char *pk)
126350a69bb5SSascha Wildner {
126450a69bb5SSascha Wildner   Encap(c,k,pk);
126550a69bb5SSascha Wildner   return 0;
126650a69bb5SSascha Wildner }
126750a69bb5SSascha Wildner 
crypto_kem_sntrup761_dec(unsigned char * k,const unsigned char * c,const unsigned char * sk)126850a69bb5SSascha Wildner int crypto_kem_sntrup761_dec(unsigned char *k,const unsigned char *c,const unsigned char *sk)
126950a69bb5SSascha Wildner {
127050a69bb5SSascha Wildner   Decap(k,c,sk);
127150a69bb5SSascha Wildner   return 0;
127250a69bb5SSascha Wildner }
127350a69bb5SSascha Wildner #endif /* USE_SNTRUP761X25519 */
1274