518 lines
26 KiB
C++
518 lines
26 KiB
C++
|
/*
|
||
|
* Copyright (c) 2012-2020 MIRACL UK Ltd.
|
||
|
*
|
||
|
* This file is part of MIRACL Core
|
||
|
* (see https://github.com/miracl/core).
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
/* NewHope API implementation. Constant time.
|
||
|
|
||
|
LOOK - no if statements!
|
||
|
|
||
|
M.Scott 21/07/2017
|
||
|
*/
|
||
|
|
||
|
#include "newhope.h"
|
||
|
|
||
|
using namespace core;
|
||
|
|
||
|
const sign16 roots[] = {0x2ac8, 0x2baf, 0x299b, 0x685, 0x2f04, 0x158d, 0x2d49, 0x24b5, 0x1edc, 0xab3, 0x2a95, 0x24d, 0x3cb, 0x6a8, 0x12f9, 0x15ba, 0x1861, 0x2a89, 0x1c5c, 0xbe6, 0xc1e, 0x2024, 0x207, 0x19ce, 0x2710, 0x1744, 0x18bc, 0x2cd7, 0x396, 0x18d5, 0x1c45, 0xc4, 0x21a6, 0xe03, 0x2b3c, 0x2d91, 0xc5d, 0x432, 0x1fbc, 0xcae, 0x2512, 0x2979, 0x3b2, 0x714, 0xb2e, 0x1a97, 0x1a03, 0x1bcd, 0x2216, 0x2701, 0xa, 0x263c, 0x1179, 0x200c, 0x2d08, 0x1c34, 0x291, 0x2c99, 0x2a5a, 0x723, 0xb1d, 0x1ccc, 0x1fb6, 0x2f58, 0x2bfe, 0x1cda, 0x2a0, 0x5f1, 0x2de, 0x1fc7, 0x1ea8, 0x1719, 0x2fa7, 0x27ec, 0x20ff, 0x12c0, 0x1ac1, 0x2232, 0x2f9b, 0xd3e, 0x2aed, 0x15f0, 0x11e8, 0xed0, 0x26a, 0x1de5, 0xa3f, 0xf43, 0xebf, 0x204e, 0xac7, 0x2d9c, 0x5ea, 0x25d1, 0xb6, 0x49c, 0x995, 0x2555, 0x26e2, 0x100, 0x1878, 0x5aa, 0x2e10, 0x271c, 0xcb, 0x1b4c, 0x2fb8, 0x25b7, 0x1543, 0x2c7b, 0x241a, 0x2223, 0x20ca, 0x24ed, 0x137, 0x1b65, 0x1dc2, 0x7c7, 0x2ec3, 0xd0c, 0x1169, 0x1c7a, 0x1ea1, 0xf89, 0x2199, 0x291d, 0x1088, 0x2046, 0x256d, 0x2bc7, 0x2e9b, 0x41f, 0x1b55, 0x2b38, 0xd0, 0x2e6a, 0x1755, 0x6bc, 0x2724, 0x3ba, 0x222e, 0x2c5c, 0x2da5, 0x213c, 0x10fe, 0x169a, 0x1552, 0x5d3, 0x300, 0x1b5d, 0x1342, 0x2004, 0x256f, 0x2039, 0x667, 0x23b5, 0x1123, 0xdb, 0x2da0, 0xe1e, 0x2f54, 0x2767, 0x154a, 0x40a, 0x11d3, 0x2821, 0xc09, 0x974, 0x694, 0xfbf, 0x27ba, 0x132, 0x83f, 0x2d06, 0x10e, 0x183f, 0x29ae, 0x28c3, 0x2dc9, 0x1144, 0x2c70, 0x2a4a, 0xf3c, 0x1e32, 0x1171, 0x1e43, 0xdd4, 0x2ddf, 0x28d2, 0xfac, 0x3c4, 0x2f19, 0x10a6, 0x2f7, 0xe1d, 0x828, 0x138f, 0x1332, 0xfab, 0xcf6, 0x13f8, 0x24a0, 0x112d, 0x2717, 0x6e7, 0x1044, 0x36e, 0xfe8, 0x6a, 0xba7, 0x1d69, 0x29ec, 0x23b2, 0xaee, 0x16df, 0x1068, 0x1a7e, 0x253f, 0x24c, 0xb33, 0x2683, 0x15ce, 0x1ad3, 0x1a36, 0xc96, 0xaea, 0x260a, 0xce, 0x28b1, 0xe4f, 0x2b11, 0x5f8, 0x1fc4, 0xe77, 0x2366, 0x11f9, 0x153c, 0x24eb, 0x20cd, 0x1398, 0x22, 0x2b97, 0x249b, 0x8eb, 0x12b2, 0x2fe3, 0x29c1, 0x1b00, 0x2663, 0xeaa, 0x2e06, 0xe0, 0x1569, 0x10f5, 0x284e, 0xa38, 0x201d, 0x1c53, 0x1681, 0x1f6f, 0x2f95, 0x2fe8, 0xacb, 0x1680, 0x17fd, 0x2c39, 0x165a, 0x10bb, 0x29d8, 0x2622, 0x1196, 0x884, 0x2a79, 0x140e, 0x2d80, 0x6fa, 0x11b2, 0x26c4, 0x355, 0x1054, 0x29e9, 0x23ed, 0xbe3, 0x24fa, 0x1fb3, 0x10ac, 0x2919, 0x2584, 0x10a4, 0xe85, 0x650, 0x1893, 0x1dc1, 0xd8e, 0x12dc, 0x2d42, 0x284d, 0xfff, 0x250f, 0xacd, 0x13c3, 0x6cc, 0x1a79, 0x1221, 0x2614, 0x270a, 0x1ea, 0x155, 0x2818, 0x222c, 0x2e5b, 0x25d8, 0x1dbf, 0x191c, 0xb0f, 0xdac, 0x1082, 0x12ef, 0x11b6, 0xfa8, 0x2b72, 0x159d, 0x209e, 0x31b, 0x2c7c, 0x14f7, 0xe09, 0x1bb2, 0x1ec7, 0x2404, 0x20ae, 0x6ad, 0xed6, 0x2b70, 0x1c7b, 0x18d1, 0x2732, 0x12da, 0xd56, 0x5c1, 0x1648, 0x18b7, 0x1605, 0x1bc4, 0x280, 0x2ece, 0xc, 0x1aae, 0x1c4, 0x1cdb, 0x22d6, 0x21d8, 0x257c, 0x51f, 0x211b, 0xff, 0x2ee0, 0x2585, 0xe1, 0x2c35, 0x26db, 0x2971, 0x2208, 0x17e1, 0x21be, 0x135e, 0x28d6, 0x2891, 0x1689, 0x2138, 0xb86, 0x2e3a, 0x1204, 0x2d10, 0x2324, 0xf3f, 0x2508, 0x33d, 0xcb2, 0x292a, 0xe27, 0x2e64, 0x29f8, 0x2d46, 0x9b7, 0x20eb, 0x1b7c, 0x9eb, 0x2b2a, 0x58c, 0x27d0, 0x121b, 0x272e, 0x29f6, 0x2dbd, 0x2697, 0x2aac, 0xd6f, 0x1c67, 0x2c5b, 0x108d, 0x363, 0x249d, 0x2d5e, 0x2fd, 0x2cb2, 0x1f8f, 0x20a4, 0xa19, 0x2ac9, 0x19b1, 0x1581, 0x17a2, 0x29eb, 0x1b72, 0x13b0, 0xee4, 0xa8f, 0x2315, 0x5e6, 0x951, 0x2e29, 0xdad, 0x1f2b, 0x224e, 0x37f, 0x1a72, 0xa91, 0x1407, 0x2df9, 0x3ad, 0x23f7, 0x1a24, 0x1d2a, 0x234b, 0x1df3, 0x1143, 0x7ff, 0x1a6d, 0x2774, 0x2690, 0x2ab5, 0x586, 0x2781, 0x2009, 0x2fdd, 0x2881, 0x399, 0x2fb6, 0x144, 0x137f, 0xfa0, 0x2e4c, 0x1c7f, 0x2fac, 0xb09, 0x1264, 0x127b, 0x198c, 0x2b40, 0x230, 0x1cf4, 0x180b, 0xb58, 0x144a, 0x2aec, 0xfb, 0x2602, 0x14ee, 0x783, 0x1098, 0x23d8, 0x203, 0xe9, 0x108a, 0x14b8, 0xeec, 0xc58, 0x1248, 0x243c, 0x28aa, 0x6bf, 0x27c4, 0x276e, 0x19b8, 0x1d11, 0x2e16, 0x472, 0x1464, 0x24b9, 0x662, 0x1097, 0x2067, 0x20d6, 0x171c, 0x4, 0x682, 0x17bb, 0x1186, 0x4f2, 0x3ff, 0x2a43, 0x1dc7, 0x1ae5, 0x8cc, 0x2e7c, 0x2ef8, 0x2ae0, 0x2904, 0xed4, 0x6c5, 0x14ae, 0xb72, 0x11c3, 0x337, 0x2da3, 0x2916, 0x6d8, 0x1cf9, 0x10ee, 0x1800, 0x1ae4, 0xa0d, 0x101b, 0x1a8d, 0x2e98, 0x24cd, 0x813, 0x1aa4, 0x9b9, 0x680, 0x2349,
|
||
|
const sign16 iroots[] = {0x2ac8, 0x452, 0x297c, 0x666, 0xb4c, 0x2b8, 0x1a74, 0xfd, 0x1a47, 0x1d08, 0x2959, 0x2c36, 0x2db4, 0x56c, 0x254e, 0x1125, 0x2f3d, 0x13bc, 0x172c, 0x2c6b, 0x32a, 0x1745, 0x18bd, 0x8f1, 0x1633, 0x2dfa, 0xfdd, 0x23e3, 0x241b, 0x13a5, 0x578, 0x17a0, 0xa9, 0x104b, 0x1335, 0x24e4, 0x28de, 0x5a7, 0x368, 0x2d70, 0x13cd, 0x2f9, 0xff5, 0x1e88, 0x9c5, 0x2ff7, 0x900, 0xdeb, 0x1434, 0x15fe, 0x156a, 0x24d3, 0x28ed, 0x2c4f, 0x688, 0xaef, 0x2353, 0x1045, 0x2bcf, 0x23a4, 0x270, 0x4c5, 0x21fe, 0xe5b, 0xfbb, 0x1f79, 0x6e4, 0xe68, 0x2078, 0x1160, 0x1387, 0x1e98, 0x22f5, 0x13e, 0x283a, 0x123f, 0x149c, 0x2eca, 0xb14, 0xf37, 0xdde, 0xbe7, 0x386, 0x1abe, 0xa4a, 0x49, 0x14b5, 0x2f36, 0x8e5, 0x1f1, 0x2a57, 0x1789, 0x2f01, 0x91f, 0xaac, 0x266c, 0x2b65, 0x2f4b, 0xa30, 0x2a17, 0x265, 0x253a, 0xfb3, 0x2142, 0x20be, 0x25c2, 0x121c, 0x2d97, 0x2131, 0x1e19, 0x1a11, 0x514, 0x22c3, 0x66, 0xdcf, 0x1540, 0x1d41, 0xf02, 0x815, 0x5a, 0x18e8, 0x1159, 0x103a, 0x2d23, 0x2a10, 0x2d61, 0x1327, 0x403, 0x25c9, 0x7b3, 0x1f0c, 0x1a98, 0x2f21, 0x1fb, 0x2157, 0x99e, 0x1501, 0x640, 0x1e, 0x1d4f, 0x2716, 0xb66, 0x46a, 0x2fdf, 0x1c69, 0xf34, 0xb16, 0x1ac5, 0x1e08, 0xc9b, 0x218a, 0x103d, 0x2a09, 0x4f0, 0x21b2, 0x750, 0x2f33, 0x9f7, 0x2517, 0x236b, 0x15cb, 0x152e, 0x1a33, 0x97e, 0x24ce, 0x2db5, 0xac2, 0x1583, 0x1f99, 0x1922, 0x2513, 0xc4f, 0x615, 0x1298, 0x245a, 0x2f97, 0x2019, 0x2c93, 0x1fbd, 0x291a, 0x8ea, 0x1ed4, 0xb61, 0x1c09, 0x230b, 0x2056, 0x1ccf, 0x1c72, 0x27d9, 0x21e4, 0x2d0a, 0x1f5b, 0xe8, 0x2c3d, 0x2055, 0x72f, 0x222, 0x222d, 0x11be, 0x1e90, 0x11cf, 0x20c5, 0x5b7, 0x391, 0x1ebd, 0x238, 0x73e, 0x653, 0x17c2, 0x2ef3, 0x2fb, 0x27c2, 0x2ecf, 0x847, 0x2042, 0x296d, 0x268d, 0x23f8, 0x7e0, 0x1e2e, 0x2bf7, 0x1ab7, 0x89a, 0xad, 0x21e3, 0x261, 0x2f26, 0x1ede, 0xc4c, 0x299a, 0xfc8, 0xa92, 0xffd, 0x1cbf, 0x14a4, 0x2d01, 0x2a2e, 0x1aaf, 0x1967, 0x1f03, 0xec5, 0x25c, 0x3a5, 0xdd3, 0x2c47, 0x8dd, 0x2945, 0x18ac, 0x197, 0x2f31, 0x4c9, 0x14ac, 0x2be2, 0x166, 0x43a, 0xa94, 0x1b53, 0x293c, 0x212d, 0x6fd, 0x521, 0x109, 0x185, 0x2735, 0x151c, 0x123a, 0x5be, 0x2c02, 0x2b0f, 0x1e7b, 0x1846, 0x297f, 0x2ffd, 0x18e5, 0xf2b, 0xf9a, 0x1f6a, 0x299f, 0xb48, 0x1b9d, 0x2b8f, 0x1eb, 0x12f0, 0x1649, 0x893, 0x83d, 0x2942, 0x757, 0xbc5, 0x1db9, 0x23a9, 0x2115, 0x1b49, 0x1f77, 0x2f18, 0x2dfe, 0xc29, 0x1f69, 0x287e, 0x1b13, 0x9ff, 0x2f06, 0x515, 0x1bb7, 0x24a9, 0x17f6, 0x130d, 0x2dd1, 0x4c1, 0x1675, 0x1d86, 0x1d9d, 0x24f8, 0x55, 0x1382, 0x1b5, 0x2061, 0x1c82, 0x2ebd, 0x4b, 0x2c68, 0x780, 0x24, 0xff8, 0x880, 0x2a7b, 0x54c, 0x971, 0x88d, 0x1594, 0x2802, 0x1ebe, 0x120e, 0xcb6, 0x12d7, 0x15dd, 0xc0a, 0x2c54, 0x208, 0x1bfa, 0x2570, 0x158f, 0x2c82, 0xdb3, 0x10d6, 0x2254, 0x1d8, 0x26b0, 0x2a1b, 0xcec, 0x2572, 0x211d, 0x1c51, 0x148f, 0x616, 0x185f, 0x1a80, 0x1650, 0x538, 0x25e8, 0xf5d, 0x1072, 0x34f, 0x2d04, 0x2a3, 0xb64, 0x2c9e, 0x1f74, 0x3a6, 0x139a, 0x2292, 0x555, 0x96a, 0x244, 0x60b, 0x8d3, 0x1de6, 0x831, 0x2a75, 0x4d7, 0x2616, 0x1485, 0xf16, 0x264a, 0x2bb, 0x609, 0x19d, 0x21da, 0x6d7, 0x234f, 0x2cc4, 0xaf9, 0x20c2, 0xcdd, 0x2f1, 0x1dfd, 0x1c7, 0x247b, 0xec9, 0x1978, 0x770, 0x72b, 0x1ca3, 0xe43, 0x1820, 0xdf9, 0x690, 0x926, 0x3cc, 0x2f20, 0xa7c, 0x121, 0x2f02, 0xee6, 0x2ae2, 0xa85, 0xe29, 0xd2b, 0x1326, 0x2e3d, 0x1553, 0x2ff5, 0x133, 0x2d81, 0x143d, 0x19fc, 0x174a, 0x19b9, 0x2a40, 0x22ab, 0x1d27, 0x8cf, 0x1730, 0x1386, 0x491, 0x212b, 0x2954, 0xf53, 0xbfd, 0x113a, 0x144f, 0x21f8, 0x1b0a, 0x385, 0x2ce6, 0xf63, 0x1a64, 0x48f, 0x2059, 0x1e4b, 0x1d12, 0x1f7f, 0x2255, 0x24f2, 0x16e5, 0x1242, 0xa29, 0x1a6, 0xdd5, 0x7e9, 0x2eac, 0x2e17, 0x8f7, 0x9ed, 0x1de0, 0x1588, 0x2935, 0x1c3e, 0x2534, 0xaf2, 0x2002, 0x7b4, 0x2bf, 0x1d25, 0x2273, 0x1240, 0x176e, 0x29b1, 0x217c, 0x1f5d, 0xa7d, 0x6e8, 0x1f55, 0x104e, 0xb07, 0x241e, 0xc14, 0x618, 0x1fad, 0x2cac, 0x93d, 0x1e4f, 0x2907, 0x281, 0x1bf3, 0x588, 0x277d, 0x1e6b, 0x9df, 0x629, 0x1f46, 0x19a7, 0x3c8, 0x1804, 0x1981, 0x2536, 0x19, 0x6c, 0x1092, 0x1980, 0x13ae, 0xfe4, 0x2f42, 0x9e, 0x2837, 0xea, 0x23e7, 0x73f, 0xaa3, 0x226e, 0x3c1, 0x1f94, 0x2832, 0x1408, 0xd63, 0x1559, 0x19e7, 0x273, 0x2fe5, 0x1e40, 0xa2b, 0xd34, 0x1be2, 0x353, 0x1ef7, 0x147, 0x10
|
||
|
const sign16 inv = 0xeab;
|
||
|
const sign16 invpr = 0x2c2a;
|
||
|
|
||
|
#define DEGREE (1<<RLWE_LGN)
|
||
|
#define WL 32
|
||
|
|
||
|
#define round(a,b) (((a)+((b)/2))/(b))
|
||
|
|
||
|
/* constant time absolute vaue */
|
||
|
static sign32 nabs(sign32 x)
|
||
|
{
|
||
|
sign32 mask = (x >> 31);
|
||
|
return (x + mask)^mask;
|
||
|
}
|
||
|
|
||
|
/* Montgomery stuff */
|
||
|
|
||
|
static sign32 redc(unsign64 T)
|
||
|
{
|
||
|
unsign32 m = (unsign32)T * (unsign32)RLWE_ND;
|
||
|
return ((unsign64)m * RLWE_PRIME + T) >> WL;
|
||
|
}
|
||
|
|
||
|
static sign32 nres(unsign32 x)
|
||
|
{
|
||
|
return redc((unsign64)x * RLWE_R2MODP);
|
||
|
}
|
||
|
|
||
|
static sign32 modmul(unsign32 a, unsign32 b)
|
||
|
{
|
||
|
return redc((unsign64)a * b);
|
||
|
}
|
||
|
|
||
|
/* NTT code */
|
||
|
/* Cooley-Tukey NTT */
|
||
|
|
||
|
static void ntt(sign32 *x)
|
||
|
{
|
||
|
int m, i, j, k, t = DEGREE / 2;
|
||
|
sign32 S, U, V, W, q = RLWE_PRIME;
|
||
|
|
||
|
/* Convert to Montgomery form */
|
||
|
for (j = 0; j < DEGREE; j++)
|
||
|
x[j] = nres(x[j]);
|
||
|
|
||
|
m = 1;
|
||
|
while (m < DEGREE)
|
||
|
{
|
||
|
k = 0;
|
||
|
for (i = 0; i < m; i++)
|
||
|
{
|
||
|
S = roots[m + i];
|
||
|
for (j = k; j < k + t; j++)
|
||
|
{
|
||
|
U = x[j];
|
||
|
V = modmul(x[j + t], S);
|
||
|
x[j] = U + V;
|
||
|
x[j + t] = U + 2 * q - V;
|
||
|
}
|
||
|
k += 2 * t;
|
||
|
}
|
||
|
t /= 2;
|
||
|
m *= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Gentleman-Sande INTT */
|
||
|
|
||
|
static void intt(sign32 *x)
|
||
|
{
|
||
|
int m, i, j, k, t = 1;
|
||
|
sign32 S, U, V, W, q = RLWE_PRIME;
|
||
|
|
||
|
m = DEGREE / 2;
|
||
|
while (m > 1)
|
||
|
{
|
||
|
k = 0;
|
||
|
for (i = 0; i < m; i++)
|
||
|
{
|
||
|
S = iroots[m + i];
|
||
|
for (j = k; j < k + t; j++)
|
||
|
{
|
||
|
U = x[j];
|
||
|
V = x[j + t];
|
||
|
x[j] = U + V;
|
||
|
W = U + DEGREE * q - V;
|
||
|
x[j + t] = modmul(W, S);
|
||
|
}
|
||
|
k += 2 * t;
|
||
|
}
|
||
|
t *= 2;
|
||
|
m /= 2;
|
||
|
}
|
||
|
|
||
|
/* Last iteration merged with n^-1 */
|
||
|
|
||
|
t = DEGREE / 2;
|
||
|
for (j = 0; j < t; j++)
|
||
|
{
|
||
|
U = x[j];
|
||
|
V = x[j + t];
|
||
|
W = U + DEGREE * q - V;
|
||
|
x[j + t] = modmul(W, (sign32)invpr);
|
||
|
x[j] = modmul(U + V, (sign32)inv);
|
||
|
}
|
||
|
/* convert back from Montgomery to "normal" form */
|
||
|
for (j = 0; j < DEGREE; j++)
|
||
|
{
|
||
|
x[j] = redc(x[j]);
|
||
|
x[j] -= q;
|
||
|
x[j] += (x[j] >> (WL - 1))&q;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* See https://eprint.iacr.org/2016/1157.pdf */
|
||
|
|
||
|
static void NHSEncode(byte *key, sign32 *poly)
|
||
|
{
|
||
|
int i, j, b, k, kj, q2;
|
||
|
|
||
|
q2 = RLWE_PRIME / 2;
|
||
|
for (i = j = 0; i < 256;)
|
||
|
{
|
||
|
kj = key[j++];
|
||
|
for (k = 0; k < 8; k++)
|
||
|
{
|
||
|
b = kj & 1;
|
||
|
poly[i] = b * q2;
|
||
|
poly[i + 256] = b * q2;
|
||
|
poly[i + 512] = b * q2;
|
||
|
poly[i + 768] = b * q2;
|
||
|
kj >>= 1;
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void NHSDecode(sign32 *poly, byte *key)
|
||
|
{
|
||
|
int i, j, k;
|
||
|
sign32 b, t, q2;
|
||
|
q2 = RLWE_PRIME / 2;
|
||
|
for (i = 0; i < 32; i++)
|
||
|
key[i] = 0;
|
||
|
|
||
|
for (i = j = 0; i < 256;)
|
||
|
{
|
||
|
for (k = 0; k < 8; k++)
|
||
|
{
|
||
|
t = nabs(poly[i] - q2) + nabs(poly[i + 256] - q2) + nabs(poly[i + 512] - q2) + nabs(poly[i + 768] - q2);
|
||
|
|
||
|
b = t - RLWE_PRIME;
|
||
|
b = (b >> 31) & 1;
|
||
|
key[j] = (key[j] >> 1) + (b << 7);
|
||
|
i++;
|
||
|
}
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* convert 32-byte seed to random polynomial */
|
||
|
|
||
|
static void parse(byte *seed, sign32 *poly)
|
||
|
{
|
||
|
int i, j;
|
||
|
sign32 n;
|
||
|
byte hash[4 * DEGREE];
|
||
|
sha3 sh;
|
||
|
|
||
|
SHA3_init(&sh, SHAKE128);
|
||
|
for (i = 0; i < 32; i++)
|
||
|
SHA3_process(&sh, seed[i]);
|
||
|
SHA3_shake(&sh, (char *)hash, 4 * DEGREE);
|
||
|
|
||
|
for (i = j = 0; i < DEGREE; i++)
|
||
|
{
|
||
|
|
||
|
n = hash[j] & 0x7f; n <<= 8;
|
||
|
n += hash[j + 1]; n <<= 8;
|
||
|
n += hash[j + 2]; n <<= 8;
|
||
|
n += hash[j + 3]; j += 4;
|
||
|
poly[i] = nres(n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Compress 14 bits polynomial coefficients into byte array */
|
||
|
/* 7 bytes is 3x14 */
|
||
|
|
||
|
static void NHSpack(sign32 *poly, byte *array)
|
||
|
{
|
||
|
int i, j;
|
||
|
sign32 a, b, c, d;
|
||
|
|
||
|
for (i = j = 0; i < DEGREE; )
|
||
|
{
|
||
|
a = poly[i++]; b = poly[i++]; c = poly[i++]; d = poly[i++];
|
||
|
array[j++] = (byte)(a & 0xff);
|
||
|
array[j++] = (byte)(((a >> 8) | (b << 6)) & 0xff);
|
||
|
array[j++] = (byte)((b >> 2) & 0xff);
|
||
|
array[j++] = (byte)(((b >> 10) | (c << 4)) & 0xff);
|
||
|
array[j++] = (byte)((c >> 4) & 0xff);
|
||
|
array[j++] = (byte)(((c >> 12) | (d << 2)) & 0xff);
|
||
|
array[j++] = (byte)(d >> 6);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void NHSunpack(byte *array, sign32 *poly)
|
||
|
{
|
||
|
int i, j;
|
||
|
sign32 a, b, c, d, e, f, g;
|
||
|
|
||
|
for (i = j = 0; i < DEGREE; )
|
||
|
{
|
||
|
a = ((sign32)array[j++]) & 0xff; b = ((sign32)array[j++]) & 0xff; c = ((sign32)array[j++]) & 0xff; d = ((sign32)array[j++]) & 0xff; e = ((sign32)array[j++]) & 0xff; f = ((sign32)array[j++]) & 0xff; g = ((sign32)array[j++]) & 0xff;
|
||
|
poly[i++] = a | ((b & 0x3f) << 8);
|
||
|
poly[i++] = (b >> 6) | (c << 2) | ((d & 0xf) << 10);
|
||
|
poly[i++] = (d >> 4) | (e << 4) | ((f & 3) << 12);
|
||
|
poly[i++] = (f >> 2) | (g << 6);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* See https://eprint.iacr.org/2016/1157.pdf */
|
||
|
|
||
|
static void NHSCompress(sign32 *poly, byte *array)
|
||
|
{
|
||
|
int i, j, k, b;
|
||
|
unsign32 col = 0;
|
||
|
|
||
|
for (i = j = 0; i < DEGREE;)
|
||
|
{
|
||
|
for (k = 0; k < 8; k++)
|
||
|
{
|
||
|
b = round((poly[i] * 8), RLWE_PRIME) & 7;
|
||
|
col = (col << 3) + b;
|
||
|
i++;
|
||
|
}
|
||
|
array[j] = col & 0xff;
|
||
|
array[j + 1] = (col >> 8) & 0xff;
|
||
|
array[j + 2] = (col >> 16) & 0xff;
|
||
|
j += 3; col = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void NHSDecompress(byte *array, sign32 *poly)
|
||
|
{
|
||
|
int i, j, k, b;
|
||
|
unsign32 col = 0;
|
||
|
|
||
|
for (i = j = 0; i < DEGREE;)
|
||
|
{
|
||
|
col = array[j + 2];
|
||
|
col = (col << 8) + array[j + 1];
|
||
|
col = (col << 8) + array[j];
|
||
|
j += 3;
|
||
|
for (k = 0; k < 8; k++)
|
||
|
{
|
||
|
b = (col & 0xe00000) >> 21; col <<= 3;
|
||
|
poly[i] = round((b * RLWE_PRIME), 8);
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* generate centered binomial distribution */
|
||
|
|
||
|
static void NHSError(csprng *RNG, sign32 *poly)
|
||
|
{
|
||
|
int i, j;
|
||
|
sign32 n1, n2, r;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
{
|
||
|
n1 = RAND_byte(RNG) + (RAND_byte(RNG) << 8);
|
||
|
n2 = RAND_byte(RNG) + (RAND_byte(RNG) << 8);
|
||
|
r = 0;
|
||
|
for (j = 0; j < 16; j++)
|
||
|
{
|
||
|
r += (n1 & 1) - (n2 & 1);
|
||
|
n1 >>= 1; n2 >>= 1;
|
||
|
}
|
||
|
poly[i] = (r + RLWE_PRIME);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void redc_it(sign32 *p)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
p[i] = redc(p[i]);
|
||
|
}
|
||
|
|
||
|
static void nres_it(sign32 *p)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
p[i] = nres(p[i]);
|
||
|
}
|
||
|
|
||
|
static void poly_mul(sign32 *p1, sign32 *p2, sign32 *p3)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
p1[i] = modmul(p2[i], p3[i]);
|
||
|
}
|
||
|
|
||
|
static void poly_add(sign32 *p1, sign32 *p2, sign32 *p3)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
p1[i] = (p2[i] + p3[i]);
|
||
|
}
|
||
|
|
||
|
static void poly_sub(sign32 *p1, sign32 *p2, sign32 *p3)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
p1[i] = (p2[i] + RLWE_PRIME - p3[i]);
|
||
|
}
|
||
|
|
||
|
/* reduces inputs < 2q */
|
||
|
static void poly_soft_reduce(sign32 *poly)
|
||
|
{
|
||
|
int i;
|
||
|
sign32 e;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
{
|
||
|
e = poly[i] - RLWE_PRIME;
|
||
|
poly[i] = e + ((e >> (WL - 1))&RLWE_PRIME);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* fully reduces modulo q */
|
||
|
static void poly_hard_reduce(sign32 *poly)
|
||
|
{
|
||
|
int i;
|
||
|
sign32 e;
|
||
|
for (i = 0; i < DEGREE; i++)
|
||
|
{
|
||
|
e = modmul(poly[i], RLWE_ONE);
|
||
|
e = e - RLWE_PRIME;
|
||
|
poly[i] = e + ((e >> (WL - 1))&RLWE_PRIME);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* API functions. See https://eprint.iacr.org/2016/1157.pdf Protocol 1 */
|
||
|
// S is secret key key, SB is seed|public key to be sent to client
|
||
|
void core::NHS_SERVER_1(csprng *RNG, octet *SB, octet *S)
|
||
|
{
|
||
|
int i;
|
||
|
byte seed[32], array[1792];
|
||
|
sign32 s[DEGREE], e[DEGREE], b[DEGREE];
|
||
|
|
||
|
for (i = 0; i < 32; i++)
|
||
|
seed[i] = RAND_byte(RNG);
|
||
|
|
||
|
parse(seed, b);
|
||
|
|
||
|
NHSError(RNG, e);
|
||
|
NHSError(RNG, s);
|
||
|
|
||
|
ntt(s);
|
||
|
ntt(e);
|
||
|
|
||
|
poly_mul(b, b, s);
|
||
|
poly_add(b, b, e);
|
||
|
poly_hard_reduce(b);
|
||
|
|
||
|
redc_it(b);
|
||
|
NHSpack(b, array);
|
||
|
|
||
|
OCT_empty(SB);
|
||
|
OCT_jbytes(SB, (char *)seed, 32);
|
||
|
OCT_jbytes(SB, (char *)array, 1792);
|
||
|
|
||
|
poly_hard_reduce(s);
|
||
|
|
||
|
NHSpack(s, array);
|
||
|
OCT_empty(S);
|
||
|
OCT_jbytes(S, (char *)array, 1792);
|
||
|
|
||
|
}
|
||
|
|
||
|
// optimized to reduce memory
|
||
|
// UC is U|cbar to be returned to server
|
||
|
// KEY is shared key
|
||
|
void core::NHS_CLIENT(csprng *RNG, octet *SB, octet *UC, octet *KEY)
|
||
|
{
|
||
|
int i;
|
||
|
sha3 sh;
|
||
|
byte seed[32], array[1792], key[32], cc[384];
|
||
|
sign32 sd[DEGREE], ed[DEGREE], u[DEGREE];
|
||
|
NHSError(RNG, sd);
|
||
|
NHSError(RNG, ed);
|
||
|
|
||
|
ntt(sd);
|
||
|
ntt(ed);
|
||
|
|
||
|
for (i = 0; i < 32; i++)
|
||
|
seed[i] = SB->val[i];
|
||
|
|
||
|
parse(seed, u);
|
||
|
|
||
|
poly_mul(u, u, sd);
|
||
|
poly_add(u, u, ed);
|
||
|
poly_hard_reduce(u);
|
||
|
|
||
|
redc_it(u);
|
||
|
NHSpack(u, array);
|
||
|
OCT_empty(UC);
|
||
|
OCT_jbytes(UC, (char *)array, 1792);
|
||
|
|
||
|
for (i = 0; i < 32; i++)
|
||
|
key[i] = RAND_byte(RNG);
|
||
|
|
||
|
SHA3_init(&sh, SHA3_HASH256);
|
||
|
for (i = 0; i < 32; i++)
|
||
|
SHA3_process(&sh, key[i]);
|
||
|
SHA3_hash(&sh, (char *)key);
|
||
|
|
||
|
for (i = 0; i < 1792; i++)
|
||
|
array[i] = SB->val[i + 32];
|
||
|
|
||
|
NHSunpack(array, u);
|
||
|
nres_it(u);
|
||
|
|
||
|
poly_mul(u, u, sd);
|
||
|
intt(u);
|
||
|
NHSError(RNG, ed);
|
||
|
poly_add(u, u, ed);
|
||
|
|
||
|
NHSEncode(key, sd);
|
||
|
poly_add(u, u, sd);
|
||
|
|
||
|
NHSCompress(u, cc);
|
||
|
|
||
|
SHA3_init(&sh, SHA3_HASH256);
|
||
|
for (i = 0; i < 32; i++)
|
||
|
SHA3_process(&sh, key[i]);
|
||
|
SHA3_hash(&sh, (char *)key);
|
||
|
|
||
|
OCT_empty(KEY);
|
||
|
OCT_jbytes(KEY, (char *)key, 32);
|
||
|
|
||
|
OCT_jbytes(UC, (char *)cc, 384);
|
||
|
}
|
||
|
|
||
|
// calculate shared key from UC and secret key S
|
||
|
void core::NHS_SERVER_2(octet *S, octet *UC, octet *KEY)
|
||
|
{
|
||
|
int i;
|
||
|
sha3 sh;
|
||
|
sign32 c[DEGREE], s[DEGREE], k[DEGREE];
|
||
|
byte array[1792], key[32], cc[384];
|
||
|
|
||
|
for (i = 0; i < 1792; i++)
|
||
|
array[i] = UC->val[i];
|
||
|
|
||
|
NHSunpack(array, k);
|
||
|
nres_it(k);
|
||
|
|
||
|
for (i = 0; i < 384; i++)
|
||
|
cc[i] = UC->val[i + 1792];
|
||
|
|
||
|
NHSDecompress(cc, c);
|
||
|
|
||
|
for (i = 0; i < 1792; i++)
|
||
|
array[i] = S->val[i];
|
||
|
|
||
|
NHSunpack(array, s);
|
||
|
|
||
|
poly_mul(k, k, s);
|
||
|
intt(k);
|
||
|
poly_sub(k, c, k);
|
||
|
poly_soft_reduce(k);
|
||
|
|
||
|
NHSDecode(k, key);
|
||
|
|
||
|
SHA3_init(&sh, SHA3_HASH256);
|
||
|
for (i = 0; i < 32; i++)
|
||
|
SHA3_process(&sh, key[i]);
|
||
|
SHA3_hash(&sh, (char *)key);
|
||
|
|
||
|
OCT_empty(KEY);
|
||
|
OCT_jbytes(KEY, (char *)key, 32);
|
||
|
}
|
||
|
|