]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
qske-newhope: Created NewHope QSKE plugin
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 20 Jun 2018 12:51:07 +0000 (14:51 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 14 May 2019 08:44:18 +0000 (10:44 +0200)
18 files changed:
configure.ac
src/libstrongswan/Makefile.am
src/libstrongswan/plugins/qske_newhope/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope.h [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.h [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.h [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.h [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/.gitignore [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.h [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_noise.c [new file with mode: 0644]
src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_reconciliation.c [new file with mode: 0644]

index a51271d9b73bddbcaff3c9ab2cc8f7030aba26c7..d8f2b37db623ad642d0b59260eaf9bfa8c91e4d1 100644 (file)
@@ -141,7 +141,8 @@ ARG_DISBL_SET([hmac],           [disable HMAC crypto implementation plugin.])
 ARG_ENABL_SET([md4],            [enable MD4 software implementation plugin.])
 ARG_DISBL_SET([md5],            [disable MD5 software implementation plugin.])
 ARG_ENABL_SET([mgf1],           [enable the MGF1 software implementation plugin.])
-ARG_ENABL_SET([newhope],        [enable New Hope crypto plugin.])
+ARG_ENABL_SET([newhope],        [enable NewHope crypto plugin.])
+ARG_ENABL_SET([qske-newhope],   [enable NewHope QSKE plugin.])
 ARG_DISBL_SET([nonce],          [disable nonce generation plugin.])
 ARG_ENABL_SET([ntru],           [enables the NTRU crypto plugin.])
 ARG_ENABL_SET([openssl],        [enables the OpenSSL crypto plugin.])
@@ -1435,6 +1436,7 @@ ADD_PLUGIN([ccm],                  [s charon scripts nm cmd])
 ADD_PLUGIN([gcm],                  [s charon scripts nm cmd])
 ADD_PLUGIN([ntru],                 [s charon scripts nm cmd])
 ADD_PLUGIN([newhope],              [s charon scripts nm cmd])
+ADD_PLUGIN([qske-newhope],         [s charon scripts nm cmd])
 ADD_PLUGIN([bliss],                [s charon pki scripts nm cmd])
 ADD_PLUGIN([curl],                 [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([files],                [s charon scepclient pki scripts nm cmd])
@@ -1602,6 +1604,7 @@ AM_CONDITIONAL(USE_GCM, test x$gcm = xtrue)
 AM_CONDITIONAL(USE_AF_ALG, test x$af_alg = xtrue)
 AM_CONDITIONAL(USE_NTRU, test x$ntru = xtrue)
 AM_CONDITIONAL(USE_NEWHOPE, test x$newhope = xtrue)
+AM_CONDITIONAL(USE_QSKE_NEWHOPE, test x$qske_newhope = xtrue)
 AM_CONDITIONAL(USE_BLISS, test x$bliss = xtrue)
 
 #  charon plugins
@@ -1720,7 +1723,7 @@ AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
 AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
 AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
 AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
-AM_CONDITIONAL(USE_LIBNTTFFT, test x$bliss = xtrue -o x$newhope = xtrue)
+AM_CONDITIONAL(USE_LIBNTTFFT, test x$bliss = xtrue -o x$newhope = xtrue -o x$qske_newhope = xtrue)
 AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
 AM_CONDITIONAL(USE_LIBPTTLS, test x$tnc_tnccs = xtrue)
@@ -1884,6 +1887,8 @@ AC_CONFIG_FILES([
        src/libstrongswan/plugins/bliss/tests/Makefile
        src/libstrongswan/plugins/newhope/Makefile
        src/libstrongswan/plugins/newhope/tests/Makefile
+       src/libstrongswan/plugins/qske_newhope/Makefile
+       src/libstrongswan/plugins/qske_newhope/tests/Makefile
        src/libstrongswan/plugins/test_vectors/Makefile
        src/libstrongswan/tests/Makefile
        src/libipsec/Makefile
index 4a416d2f579bb5d6795933e2a74a37882aba4230..3d351efb0768636f2b6e1634fb4be43a5c306dc2 100644 (file)
@@ -663,6 +663,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_QSKE_NEWHOPE
+  SUBDIRS += plugins/qske_newhope
+if MONOLITHIC
+  libstrongswan_la_LIBADD += plugins/qske_newhope/libstrongswan-qske-newhope.la
+endif
+endif
+
 if USE_TEST_VECTORS
   SUBDIRS += plugins/test_vectors
 if MONOLITHIC
@@ -690,3 +697,7 @@ endif
 if USE_NEWHOPE
   SUBDIRS += plugins/newhope/tests
 endif
+
+if USE_QSKE_NEWHOPE
+  SUBDIRS += plugins/qske_newhope/tests
+endif
diff --git a/src/libstrongswan/plugins/qske_newhope/Makefile.am b/src/libstrongswan/plugins/qske_newhope/Makefile.am
new file mode 100644 (file)
index 0000000..fc05772
--- /dev/null
@@ -0,0 +1,30 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libstrongswan/math/libnttfft
+
+AM_CFLAGS = \
+       $(PLUGIN_CFLAGS)
+
+# these files are also used by the tests, we can't directly refer to them
+# because of the subdirectory, which would cause distclean to fail
+noinst_LTLIBRARIES = libqske-newhope.la
+libqske_newhope_la_SOURCES = \
+       qske_newhope.h qske_newhope.c \
+       qske_newhope_noise.h qske_newhope_noise.c \
+       qske_newhope_reconciliation.h qske_newhope_reconciliation.c
+
+libqske_newhope_la_LIBADD = \
+       $(top_builddir)/src/libstrongswan/math/libnttfft/libnttfft.la
+
+if MONOLITHIC
+noinst_LTLIBRARIES += libstrongswan-qske-newhope.la
+else
+plugin_LTLIBRARIES = libstrongswan-qske-newhope.la
+endif
+
+libstrongswan_qske_newhope_la_SOURCES = \
+       qske_newhope_plugin.h qske_newhope_plugin.c
+
+libstrongswan_qske_newhope_la_LDFLAGS = -module -avoid-version
+
+libstrongswan_qske_newhope_la_LIBADD = libqske-newhope.la
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope.c b/src/libstrongswan/plugins/qske_newhope/qske_newhope.c
new file mode 100644 (file)
index 0000000..b616a3f
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann,
+ * and Peter Schwabe.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "qske_newhope.h"
+#include "qske_newhope_noise.h"
+#include "qske_newhope_reconciliation.h"
+
+#include <ntt_fft.h>
+#include <ntt_fft_reduce.h>
+#include <crypto/qske_mechanism.h>
+#include <utils/debug.h>
+
+static const int seed_len =   32;  /* 256 bits */
+static const int poly_len = 1792;  /* size of 1024 packed 14-bit coefficients */
+static const int rec_len =   256;  /* size of 1024 packed  2-bit coefficients */
+
+typedef struct private_qske_newhope_t private_qske_newhope_t;
+
+/**
+ * Private data of an qske_newhope_t object.
+ */
+struct private_qske_newhope_t {
+
+       /**
+        * Public qske_newhope_t interface.
+        */
+       qske_newhope_t public;
+
+       /**
+        * FFT parameter set
+        */
+       const ntt_fft_params_t *params;
+
+       /**
+        * Secret noise polynomial s
+        */
+       uint32_t *s;
+
+       /**
+        * Output polynomial u = a * NTT(s') + NTT(e')
+        */
+       uint32_t *u;
+
+       /**
+        * Error reconciliation help bits
+        */
+       uint8_t *r;
+
+       /**
+        * Shared secret
+        */
+       chunk_t shared_secret;
+
+};
+
+/**
+ * Derive 14-bit coefficients of polynomial a from 256 bit random seed
+ * using the SHAKE128 extended output function
+ */
+static uint32_t* derive_a_poly(private_qske_newhope_t *this, chunk_t seed)
+{
+       uint32_t *a;
+       uint8_t x[2];
+       int i = 0;
+       xof_t *xof;
+
+       xof = lib->crypto->create_xof(lib->crypto, XOF_SHAKE_128);
+       if (!xof)
+       {
+               DBG1(DBG_LIB, "could not instantiate SHAKE128 XOF");
+               return NULL;
+       }
+
+       if (!xof->set_seed(xof, seed))
+       {
+               DBG1(DBG_LIB, "could not set seed of SHAKE128 XOF");
+               xof->destroy(xof);
+               return NULL;
+       }
+
+       /* allocate dynamic memory for polynomial a */
+       a = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
+
+       while (i < this->params->n)
+       {
+               if (!xof->get_bytes(xof, sizeof(x), x))
+               {
+                       DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF");
+                       xof->destroy(xof);
+                       free(a);
+                       return NULL;
+               }
+
+               /*
+                * Treat x as a 16 bit unsigned little endian integer
+                * and truncate to 14 bits
+                */
+               a[i] = uletoh16(x) & 0x3fff;
+
+               if (a[i] < this->params->q)
+               {
+                       i++;
+               }
+       }
+       xof->destroy(xof);
+
+       return a;
+}
+
+/**
+ * Pack four 14-bit coefficients into seven consecutive bytes
+ *
+ *                       1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |L 0 0 0 0 0 0 0|L 1 H 0 0 0 0 0|M 1 1 1 1 1 1 1|L 2 2 2 H 1 1 1|
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |M 2 2 2 2 2 2 2|L 3 3 3 3 3 H 2|H 3 3 3 3 3 3 3|L 0 0 0 0 0 0 0|
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static void pack_poly(private_qske_newhope_t *this, uint8_t *x, uint32_t *p)
+{
+       int i;
+
+       for (i = 0; i < this->params->n; i += 4)
+       {
+               *x++ = (p[i] & 0xff );
+               *x++ = (p[i]   >>  8) | (p[i+1] << 6);
+               *x++ = (p[i+1] >>  2);
+               *x++ = (p[i+1] >> 10) | (p[i+2] << 4);
+               *x++ = (p[i+2] >>  4);
+               *x++ = (p[i+2] >> 12) | (p[i+3] << 2);
+               *x++ = (p[i+3] >>  6);
+       }
+}
+
+/**
+ * Unpack seven consecutive bytes into four 14-bit coefficients
+ */
+static uint32_t* unpack_poly(private_qske_newhope_t * this, uint8_t *x)
+{
+       uint32_t *p;
+       int i;
+
+       p = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
+
+       for (i = 0; i < this->params->n; i += 4)
+       {
+               p[i]   =  x[0]       | (((uint32_t)x[1] & 0x3f) <<  8);
+               p[i+1] = (x[1] >> 6) | (((uint32_t)x[2]) <<  2)
+                                                        | (((uint32_t)x[3] & 0x0f) << 10);
+               p[i+2] = (x[3] >> 4) | (((uint32_t)x[4]) <<  4)
+                                                        | (((uint32_t)x[5] & 0x03) << 12);
+               p[i+3] = (x[5] >> 2) | (((uint32_t)x[6]) <<  6);
+               x += 7;
+       }
+       for (i = 0; i < this->params->n; i++)
+       {
+               if (p[i] >= this->params->q)
+               {
+                       DBG1(DBG_LIB, "polynomial coefficient must be smaller than %u",
+                                                  this->params->q);
+                       free(p);
+                       return NULL;
+               }
+       }
+       return p;
+}
+
+/**
+ * Multiply and add polynomials in the frequency domain
+ */
+static uint32_t* multiply_add_poly(private_qske_newhope_t *this,
+                                                                  uint32_t *a, uint32_t *e)
+{
+       ntt_fft_t *fft;
+       uint32_t *b, t;
+       int i;
+
+       /* transform s and h to frequency domain */
+       fft = ntt_fft_create(this->params);
+       fft->transform(fft, this->s, this->s, FALSE);
+       fft->transform(fft, e, e, FALSE);
+       fft->destroy(fft);
+
+       b = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
+
+       /* compute  b = a * s + e in the frequency domain */
+       for (i = 0; i < this->params->n; i++)
+       {
+               /* convert a[i] to Montgomery domain */
+               t = ntt_fft_mreduce(a[i] * this->params->r2, this->params);
+
+               /* compute b[i] = a[i] * s[i] + e[i] in Montgomery domain */
+               t = ntt_fft_mreduce(t * this->s[i], this->params) + e[i];
+
+               /* exit Montgomery domain before transmitting polynomial b */
+               b[i] = ntt_fft_mreduce(t, this->params);
+       }
+       memwipe(e, this->params->n * sizeof(uint32_t));
+
+       return b;
+}
+
+/**
+ * Multiply polynomials in the frequency domain and return to time domain
+ */
+static uint32_t* multiply_ntt_inv_poly(private_qske_newhope_t *this, uint32_t *b)
+{
+       ntt_fft_t *fft;
+       uint32_t *v, t;
+       int i;
+
+       v = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
+
+       for (i = 0; i < this->params->n; i++)
+       {
+               /* convert b[i] to Montgomery domain */
+               t = ntt_fft_mreduce(b[i] * this->params->r2, this->params);
+
+               /* compute v[i] = b[i] * s[i] in Montgomery domain */
+               v[i] = ntt_fft_mreduce(t * this->s[i], this->params);
+       }
+
+       /* transform v back to time domain */
+       fft = ntt_fft_create(this->params);
+       fft->transform(fft, v, v, TRUE);
+       fft->destroy(fft);
+
+       return v;
+}
+
+/**
+ * Pack four 2-bit coefficients into one byte
+ */
+static void pack_rec(private_qske_newhope_t *this, uint8_t *x, uint8_t *r)
+{
+       int i;
+
+       for (i = 0; i < this->params->n; i += 4)
+       {
+               *x++ = r[i] | r[i+1] << 2 | r[i+2] << 4 | r[i+3] << 6;
+       }
+}
+
+static uint8_t* unpack_rec(private_qske_newhope_t *this, uint8_t *x)
+{
+       uint8_t *r;
+       int i;
+
+       r = (uint8_t*)malloc(this->params->n);
+
+       for (i = 0; i < this->params->n; i += 4)
+       {
+               r[i]   = (*x)      & 0x03;
+               r[i+1] = (*x >> 2) & 0x03;
+               r[i+2] = (*x >> 4) & 0x03;
+               r[i+3] = (*x >> 6) & 0x03;
+               x++;
+       }
+
+       return r;
+}
+
+METHOD(qske_t, get_public_key, bool,
+       private_qske_newhope_t *this, chunk_t *value)
+{
+       rng_t *rng;
+       int i;
+       uint32_t *a = NULL, *b = NULL, *e = NULL;
+       uint16_t n, q;
+       uint8_t noise_seed_buf[seed_len];
+       chunk_t noise_seed = { noise_seed_buf, seed_len};
+       chunk_t a_seed;
+       qske_newhope_noise_t *noise = NULL;
+       bool success = FALSE;
+
+       /* Define some often-used constants */
+       n = this->params->n;
+       q = this->params->q;
+
+       /* allocate space for public output value */
+       *value = chunk_alloc(poly_len + seed_len);
+       a_seed = chunk_create(value->ptr + poly_len, seed_len);
+
+       /* create polynomial a from 256 bit random seed */
+       rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+       if (!rng)
+       {
+               DBG1(DBG_LIB, "could not instatiate random source");
+               return FALSE;
+       }
+       if (!rng->get_bytes(rng, seed_len, a_seed.ptr))
+       {
+               DBG1(DBG_LIB, "could not generate seed for polynomial a");
+               goto end;
+       }
+
+       a = derive_a_poly(this, a_seed);
+       if (a == NULL)
+       {
+               goto end;
+       }
+
+       /* generate random seed for the derivation of noise polynomials */
+       if (!rng->get_bytes(rng, seed_len, noise_seed.ptr))
+       {
+               DBG1(DBG_LIB, "could not generate seed for noise polynomials");
+               goto end;
+       }
+
+       /* create noise polynomial generator */
+       noise = qske_newhope_noise_create(noise_seed);
+       if (!noise)
+       {
+               goto end;
+       }
+
+       /* create noise polynomial s from seed with nonce = 0x00 */
+       this->s = noise->get_binomial_words(noise, 0x00, n, q);
+       if (this->s == NULL)
+       {
+               goto end;
+       }
+
+       /* create noise polynomial e from seed with nonce = 0x01 */
+       e = noise->get_binomial_words(noise, 0x01, n, q);
+       if (e == NULL)
+       {
+               goto end;
+       }
+
+       /* compute b = a * NTT(s) + NTT(e) */
+       b = multiply_add_poly(this, a, e);
+
+       DBG3(DBG_LIB, "   i  a[i]  b[i]");
+       for (i = 0; i < n; i++)
+       {
+               DBG3(DBG_LIB, "%4d %5u %5u", i, a[i], b[i]);
+       }
+
+       /* pack coefficients of polynomial b */
+       pack_poly(this, value->ptr, b);
+       success = TRUE;
+
+end:
+       rng->destroy(rng);
+       DESTROY_IF(noise);
+       free(a);
+       free(b);
+       free(e);
+
+       if (!success)
+       {
+               chunk_free(value);
+       }
+       return success;
+}
+
+METHOD(qske_t, get_ciphertext, bool,
+       private_qske_newhope_t *this, chunk_t *value)
+{
+       int i;
+
+       DBG3(DBG_LIB, "   i  u[i]  r[i]");
+       for (i = 0; i < this->params->n; i++)
+       {
+               DBG3(DBG_LIB, "%4d %5u %5u", i, this->u[i], this->r[i]);
+       }
+
+       /* allocate space for public output value */
+       *value = chunk_alloc(poly_len + rec_len);
+
+       /* pack coefficients of polynomial u */
+       pack_poly(this, value->ptr, this->u);
+
+       /* pack coefficients of polynomial r */
+       pack_rec(this, value->ptr + poly_len, this->r);
+
+       return TRUE;
+}
+
+METHOD(qske_t, get_shared_secret, bool,
+       private_qske_newhope_t *this, chunk_t *secret)
+{
+       if (this->shared_secret.len == 0)
+       {
+               *secret = chunk_empty;
+               return FALSE;
+       }
+       *secret = chunk_clone(this->shared_secret);
+
+       return TRUE;
+}
+
+METHOD(qske_t, set_public_key, bool,
+       private_qske_newhope_t *this, chunk_t value)
+{
+       qske_newhope_reconciliation_t * rec;
+       qske_newhope_noise_t *noise = NULL;
+       uint32_t *a = NULL, *b = NULL, *e1 = NULL, *e2 = NULL, *v = NULL, t;
+       uint16_t n, q;
+       uint8_t *rbits = NULL;
+       uint8_t noise_seed_buf[seed_len];
+       int i;
+       chunk_t noise_seed = { noise_seed_buf, seed_len };
+       chunk_t a_seed;
+       rng_t *rng = NULL;
+       bool success = FALSE;
+
+       /* Define some often-used constants */
+       n = this->params->n;
+       q = this->params->q;
+
+       if (value.len != poly_len + seed_len)
+       {
+               DBG1(DBG_LIB, "received %N QSKE payload of incorrect size",
+                                          qske_mechanism_names, QSKE_NEWHOPE);
+               return FALSE;
+       }
+       a_seed = chunk_create(value.ptr + poly_len, seed_len);
+
+       a = derive_a_poly(this, a_seed);
+       if (a == NULL)
+       {
+               return FALSE;
+       }
+
+       b = unpack_poly(this, value.ptr);
+       if (b == NULL)
+       {
+               goto end;
+       }
+
+       /* debug output of polynomials a and b */
+       DBG3(DBG_LIB, "   i  a[i]  b[i]");
+       for (i = 0; i < n; i++)
+       {
+               DBG3(DBG_LIB, "%4d %5u %5u", i, a[i], b[i]);
+       }
+
+       /* generate random seed for the derivation of noise polynomials */
+       rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+       if (!rng)
+       {
+               DBG1(DBG_LIB, "could not instatiate random source");
+               goto end;
+       }
+       if (!rng->get_bytes(rng, seed_len, noise_seed.ptr))
+       {
+               DBG1(DBG_LIB, "could not generate seed for noise polynomials");
+               goto end;
+       }
+
+       /* create noise polynomial generator */
+       noise = qske_newhope_noise_create(noise_seed);
+       if (!noise)
+       {
+               goto end;
+       }
+
+       /* create noise polynomial s' from seed with nonce = 0x00 */
+       this->s = noise->get_binomial_words(noise, 0x00, n, q);
+       if (this->s == NULL)
+       {
+               goto end;
+       }
+
+       /* create noise polynomial e' from seed with nonce = 0x01 */
+       e1 = noise->get_binomial_words(noise, 0x01, n, q);
+       if (e1 == NULL)
+       {
+               goto end;
+       }
+
+       /* create noise polynomial e'' from seed with nonce = 0x02 */
+       e2 = noise->get_binomial_words(noise, 0x02, n, q);
+       if (e2 == NULL)
+       {
+               goto end;
+       }
+
+       /* compute u = a * NTT(s') + NTT(e') */
+       this->u = multiply_add_poly(this, a, e1);
+
+       /* compute v = NTT_inv( b * NTT(s') ) */
+       v = multiply_ntt_inv_poly(this, b);
+
+       /* compute v = v + e'' */
+       for (i = 0; i < n; i++)
+       {
+               t = v[i] + e2[i];
+               v[i] = (t < q) ? t : t - q;
+       }
+       memwipe(e2, n * sizeof(uint32_t));
+
+       /* create uniform noise bytes from seed with nonce = 0x02 */
+       rbits = noise->get_uniform_bytes(noise, 0x03, n/(4*8));
+
+       rec = qske_newhope_reconciliation_create(n, q);
+       this->r = rec->help_reconcile(rec, v, rbits);
+       free(rbits);
+       this->shared_secret = rec->reconcile(rec, v, this->r);
+       rec->destroy(rec);
+
+       DBG4(DBG_LIB, "key: %B", &this->shared_secret);
+       success = TRUE;
+
+end:
+       DESTROY_IF(rng);
+       DESTROY_IF(noise);
+       free(a);
+       free(b);
+       free(e1);
+       free(e2);
+       free(v);
+
+       return success;
+}
+
+METHOD(qske_t, set_ciphertext, bool,
+       private_qske_newhope_t *this, chunk_t value)
+{
+       qske_newhope_reconciliation_t * rec;
+       uint16_t n, q;
+       uint32_t *v;
+       int i;
+
+       /* Define some often-used constants */
+       n = this->params->n;
+       q = this->params->q;
+
+       /* We are the initiator */
+       if (value.len != poly_len + rec_len)
+       {
+               DBG1(DBG_LIB, "received %N QSKE payload of incorrect size",
+                                          qske_mechanism_names, QSKE_NEWHOPE);
+               return FALSE;
+       }
+
+       this->u = unpack_poly(this, value.ptr);
+       if (this->u == NULL)
+       {
+               return FALSE;
+       }
+
+       this->r = unpack_rec(this, value.ptr + poly_len);
+       if (this->r == NULL)
+       {
+               return FALSE;
+       }
+
+       DBG3(DBG_LIB, "   i  u[i]  r[i]");
+       for (i = 0; i < n; i++)
+       {
+               DBG3(DBG_LIB, "%4d %5u %5u", i, this->u[i], this->r[i]);
+       }
+
+       /* compute v' = NTT_inv( u * NTT(s) ) */
+       v = multiply_ntt_inv_poly(this, this->u);
+
+       rec = qske_newhope_reconciliation_create(n, q);
+       this->shared_secret = rec->reconcile(rec, v, this->r);
+       free(v);
+       rec->destroy(rec);
+
+       DBG4(DBG_LIB, "key: %B", &this->shared_secret);
+
+       return TRUE;
+}
+
+METHOD(qske_t, get_qske_mechanism, qske_mechanism_t,
+       private_qske_newhope_t *this)
+{
+       return QSKE_NEWHOPE;
+}
+
+METHOD(qske_t, set_nist_drbg_mode, bool,
+       private_qske_newhope_t *this, bool enable, chunk_t seed)
+{
+       return FALSE;
+}
+
+METHOD(qske_t, destroy, void,
+       private_qske_newhope_t *this)
+{
+       chunk_clear(&this->shared_secret);
+       memwipe(this->s, this->params->n * sizeof(uint32_t));
+       free(this->s);
+       free(this->u);
+       free(this->r);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+qske_newhope_t *qske_newhope_create(qske_mechanism_t mechanism)
+{
+       private_qske_newhope_t *this;
+
+       INIT(this,
+               .public = {
+                       .qske = {
+                               .get_qske_mechanism = _get_qske_mechanism,
+                               .get_public_key = _get_public_key,
+                               .set_public_key = _set_public_key,
+                               .get_ciphertext = _get_ciphertext,
+                               .set_ciphertext = _set_ciphertext,
+                               .get_shared_secret = _get_shared_secret,
+                               .set_nist_drbg_mode = _set_nist_drbg_mode,
+                               .destroy = _destroy,
+                       },
+               },
+               .params = &ntt_fft_12289_1024,
+
+       );
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope.h b/src/libstrongswan/plugins/qske_newhope/qske_newhope.h
new file mode 100644 (file)
index 0000000..5fd36a2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup qske_newhope qske_newhope
+ * @{ @ingroup newhope_p
+ */
+
+#ifndef QSKE_NEWHOPE_H_
+#define QSKE_NEWHOPE_H_
+
+typedef struct qske_newhope_t qske_newhope_t;
+
+#include <library.h>
+
+/**
+ * Quantum-safe key encapsulation implementation using the NewHope mechanism
+ */
+struct qske_newhope_t {
+
+       /**
+        * Implements qske_t interface.
+        */
+       qske_t qske;
+};
+
+/**
+ * Creates a new qske_newhope_t object.
+ *
+ * @param mechanism            QSKE mechanism number
+ * @return                             qske_newhope_t object, NULL if not supported
+ */
+qske_newhope_t *qske_newhope_create(qske_mechanism_t mechanism);
+
+#endif /** QSKE_NEWHOPE_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.c b/src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.c
new file mode 100644 (file)
index 0000000..c4cd720
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann,
+ * and Peter Schwabe.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "qske_newhope_noise.h"
+
+typedef struct private_qske_newhope_noise_t private_qske_newhope_noise_t;
+
+static const int seed_len =   32;  /* 256 bits */
+static const int nonce_len =  12;  /*  96 bits */
+
+/**
+ * Private data of an newhope_noise_t object.
+ */
+struct private_qske_newhope_noise_t {
+
+       /**
+        * Public newhope_noise_t interface.
+        */
+       qske_newhope_noise_t public;
+
+       /**
+        * 256 bit seed and 96 bit nonce (44 bytes)
+        */
+       chunk_t seed;
+
+       /**
+        * ChaCha20 stream
+        */
+       xof_t *xof;
+
+};
+
+METHOD(qske_newhope_noise_t, get_uniform_bytes, uint8_t*,
+       private_qske_newhope_noise_t *this, uint8_t nonce, uint16_t n)
+{
+       uint8_t *bytes;
+
+       this->seed.ptr[seed_len] = nonce;
+       if (!this->xof->set_seed(this->xof, this->seed))
+       {
+               DBG1(DBG_LIB, "could not set seed of CHACHA20 XOF");
+               return NULL;
+       }
+
+       /* allocate dynamic memory for the noise polynomial */
+       bytes = (uint8_t*)malloc(n);
+
+       if (!this->xof->get_bytes(this->xof, n, bytes))
+       {
+               DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF");
+               free(bytes);
+               return NULL;
+       }
+
+       return bytes;
+}
+
+METHOD(qske_newhope_noise_t, get_binomial_words, uint32_t*,
+       private_qske_newhope_noise_t *this, uint8_t nonce, uint16_t n, uint16_t q)
+{
+       uint32_t *np, a, b, d, t;
+       uint8_t x[4];
+       int i = 0, j;
+
+       this->seed.ptr[seed_len] = nonce;
+       if (!this->xof->set_seed(this->xof, this->seed))
+       {
+               DBG1(DBG_LIB, "could not set seed of CHACHA20 XOF");
+               return NULL;
+       }
+
+       /* allocate dynamic memory for the noise polynomial */
+       np = (uint32_t*)malloc(n * sizeof(uint32_t));
+
+       for (i = 0; i < n; i++)
+       {
+               if (!this->xof->get_bytes(this->xof, sizeof(x), x))
+               {
+                       DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF");
+                       free(np);
+                       return NULL;
+               }
+
+               /* Treat x as a 32 bit unsigned little endian integer */
+               t = uletoh32(x);
+
+               /* Compute Psi_16 distribution */
+               d = 0;
+               for (j = 0; j < 8; j++)
+               {
+                       d += (t >> j) & 0x01010101;
+               }
+               a = ((d >>  8) & 0xff) + (d & 0xff);
+               b = ((d >> 16) & 0xff) + (d >> 24);
+               np[i] = (a >= b) ? a - b : a + q - b;
+       }
+
+       return np;
+}
+
+METHOD(qske_newhope_noise_t, destroy, void,
+       private_qske_newhope_noise_t *this)
+{
+       this->xof->destroy(this->xof);
+       chunk_free(&this->seed);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+qske_newhope_noise_t *qske_newhope_noise_create(chunk_t seed)
+{
+       private_qske_newhope_noise_t *this;
+       xof_t *xof;
+
+       if (seed.len != seed_len)
+       {
+               DBG1(DBG_LIB, "seed for ChaCha20 stream must be 256 bits");
+               return NULL;
+       }
+
+       xof = lib->crypto->create_xof(lib->crypto, XOF_CHACHA20);
+       if (!xof)
+       {
+               DBG1(DBG_LIB, "could not instantiate ChaCha20 stream");
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .get_uniform_bytes = _get_uniform_bytes,
+                       .get_binomial_words = _get_binomial_words,
+                       .destroy = _destroy,
+               },
+               .xof = xof,
+               .seed = chunk_alloc(seed_len + nonce_len),
+       );
+
+       /* initialize seed for ChaCha 20 stream */
+       memcpy(this->seed.ptr, seed.ptr, seed_len);
+       memset(this->seed.ptr + seed_len, 0x00, nonce_len);
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.h b/src/libstrongswan/plugins/qske_newhope/qske_newhope_noise.h
new file mode 100644 (file)
index 0000000..87794ae
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup qske_newhope_noise qske_newhope_noise
+ * @{ @ingroup qske_newhope_p
+ */
+
+#ifndef QSKE_NEWHOPE_NOISE_H_
+#define QSKE_NEWHOPE_NOISE_H_
+
+typedef struct qske_newhope_noise_t qske_newhope_noise_t;
+
+#include <library.h>
+
+/**
+ * Generate pseudo random noise using a ChaCha20 stream
+ * initialized with a 256 bit seed and an 8 bit nonce
+ */
+struct qske_newhope_noise_t {
+
+       /**
+        * Return n pseudo random bytes with a uniform distribution
+        *
+        * @param nonce         Nonce determining the pseudo random stream
+        * @param n                     Number of pseudo random bytes to be returned
+        * @return                      Return array with n peudo random bytes
+        */
+       uint8_t* (*get_uniform_bytes)(qske_newhope_noise_t *this, uint8_t nonce,
+                                                                 uint16_t n);
+
+       /**
+        * Return n pseudo random 32-bit words with a Psi16 binomial distribution
+        *
+        * @param nonce         Nonce determining the pseudo random stream
+        * @param n                     Number of pseudo random Psi16 words to be returned
+        * @param q                     Prime number q determining the ring
+        * @return                      Return array with n pseudo random 32 bit words
+        */
+       uint32_t* (*get_binomial_words)(qske_newhope_noise_t *this, uint8_t nonce,
+                                                                       uint16_t n, uint16_t q);
+
+       /**
+        * Destroy a qske_newhope_noise_t object
+        */
+       void (*destroy)(qske_newhope_noise_t *this);
+};
+
+/**
+ * Creates a new qske_newhope_noise_t object.
+ *
+ * @param seed                 256 bit seed (32 byte chunk)
+ * @return                             qske_newhope_noise_t object, NULL if not supported
+ */
+qske_newhope_noise_t *qske_newhope_noise_create(chunk_t seed);
+
+#endif /** QSKE_NEWHOPE_NOISE_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.c b/src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.c
new file mode 100644 (file)
index 0000000..2a1fb81
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "qske_newhope_plugin.h"
+#include "qske_newhope.h"
+
+#include <library.h>
+
+typedef struct private_qske_newhope_plugin_t private_qske_newhope_plugin_t;
+
+/**
+ * private data of qske_newhope_plugin
+ */
+struct private_qske_newhope_plugin_t {
+
+       /**
+        * public functions
+        */
+       qske_newhope_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+       private_qske_newhope_plugin_t *this)
+{
+       return "qske_newhope";
+}
+
+METHOD(plugin_t, get_features, int,
+       private_qske_newhope_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               PLUGIN_REGISTER(QSKE, qske_newhope_create),
+                       PLUGIN_PROVIDE(QSKE, QSKE_NEWHOPE),
+                               PLUGIN_DEPENDS(XOF, XOF_SHAKE_128),
+                               PLUGIN_DEPENDS(XOF, XOF_CHACHA20),
+       };
+       *features = f;
+
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_qske_newhope_plugin_t *this)
+{
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *qske_newhope_plugin_create()
+{
+       private_qske_newhope_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+       );
+
+       return &this->public.plugin;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.h b/src/libstrongswan/plugins/qske_newhope/qske_newhope_plugin.h
new file mode 100644 (file)
index 0000000..8fcd737
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup qske_qske_newhope_p qske_newhope
+ * @ingroup plugins
+ *
+ * @defgroup qske_newhope_plugin qske_newhope_plugin
+ * @{ @ingroup qske_newhope_p
+ */
+
+#ifndef QSKE_NEWHOPE_PLUGIN_H_
+#define QSKE_NEWHOPE_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct qske_newhope_plugin_t qske_newhope_plugin_t;
+
+/**
+ * Plugin implementing New Hope-based key exchange
+ */
+struct qske_newhope_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** QSKE_NEWHOPE_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.c b/src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.c
new file mode 100644 (file)
index 0000000..aa8bc01
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann,
+ * and Peter Schwabe.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ */
+
+#include "qske_newhope_reconciliation.h"
+
+typedef struct private_qske_newhope_reconciliation_t private_qske_newhope_reconciliation_t;
+
+/**
+ * Private data of an newhope_reconciliation_t object.
+ */
+struct private_qske_newhope_reconciliation_t {
+
+       /**
+        * Public newhope_reconciliation_t interface.
+        */
+       qske_newhope_reconciliation_t public;
+
+       /**
+        * Array sizes
+        */
+       int n, n4;
+
+       /**
+        * Multiples of modulus q
+        */
+       int32_t q, q2, q4, q8, q16;
+};
+
+
+static inline int32_t rec_abs(int32_t v)
+{
+  int32_t mask = v >> 31;
+
+  return (v ^ mask) - mask;
+}
+
+/**
+ * Auxiliary function used by help_reconcile() method
+ */
+static int32_t rec_f(private_qske_newhope_reconciliation_t *this,
+                                        int32_t v, uint8_t r, int32_t *v0, int32_t *v1)
+{
+       int32_t x, xit, t, b;
+
+       x = 8 * v + 2 * r;
+
+       /* compute t = x/q */
+       b = x * 2730;
+       t = b >> 25;
+       b = x - t * this->q;
+       b = this->q - 1 - b;
+       b >>= 31;
+       t -= b;
+
+       r = t & 0x01;
+       xit = (t >> 1);
+       *v0 = xit + r ; /* v0 = round(x/(2q)) */
+
+       t -= 1;
+       r = t & 0x01;
+       *v1 = ( t>> 1) + r;
+
+       return rec_abs(x - (*v0) * this->q2);
+}
+
+/**
+ * Auxiliary function used by reconcile() method
+ */
+static int32_t rec_g(private_qske_newhope_reconciliation_t *this, int32_t x)
+{
+       int32_t t, r, b;
+
+       /*  t = x/(4*q) */
+       b = x * 2730;
+       t = b >> 27;
+       b = x - t * this->q4;
+       b = this->q4 - 1 - b;
+       b >>= 31;
+       t -= b;
+
+       r = t & 0x01;
+       t = (t >> 1) + r; /* t = round(x/(8q)) */
+       t *= this->q8;
+
+  return abs(t - x);
+}
+
+METHOD(qske_newhope_reconciliation_t, help_reconcile, uint8_t*,
+       private_qske_newhope_reconciliation_t *this, uint32_t *v, uint8_t *rbits)
+{
+       int32_t v0[4], v1[4], v_tmp[4], k;
+       int i, i0, i1, i2, i3, j;
+       uint8_t *r, rbit;
+
+       /* allocate output vector */
+       r = (uint8_t*)malloc(this->n);
+
+       for (i = 0; i < this->n4/8; i++)
+       {
+               for (j = 0; j < 8; j++)
+               {
+                       i0 = 8*i  + j;
+                       i1 = i0 + this->n4;
+                       i2 = i1 + this->n4;
+                       i3 = i2 + this->n4;
+
+                       /* iterate through all 256 random bits */
+                       rbit = (rbits[i] >> j) & 0x01;
+
+                       k  = rec_f(this, v[i0], rbit, &v0[0], &v1[0]);
+                       k += rec_f(this, v[i1], rbit, &v0[1], &v1[1]);
+                       k += rec_f(this, v[i2], rbit, &v0[2], &v1[2]);
+                       k += rec_f(this, v[i3], rbit, &v0[3], &v1[3]);
+
+                       k = (this->q2 - 1 - k) >> 31;
+
+                       v_tmp[0] = ((~k) & v0[0]) ^ (k & v1[0]);
+                       v_tmp[1] = ((~k) & v0[1]) ^ (k & v1[1]);
+                       v_tmp[2] = ((~k) & v0[2]) ^ (k & v1[2]);
+                       v_tmp[3] = ((~k) & v0[3]) ^ (k & v1[3]);
+
+                       r[i0] = (v_tmp[0] -     v_tmp[3]) & 0x03;
+                       r[i1] = (v_tmp[1] -     v_tmp[3]) & 0x03;
+                       r[i2] = (v_tmp[2] -     v_tmp[3]) & 0x03;
+                       r[i3] = (v_tmp[3] - k + v_tmp[3]) & 0x03;
+               }
+       }
+
+       return r;
+}
+
+METHOD(qske_newhope_reconciliation_t, reconcile, chunk_t,
+       private_qske_newhope_reconciliation_t *this, uint32_t *v, uint8_t *r)
+{
+       size_t key_len;
+       uint8_t *key;
+       int32_t tmp[4], t;
+       int i, i0, i1, i2, i3, j;
+
+       key_len = this->n4 / 8;
+       key = (uint8_t*)malloc(key_len);
+       memset(key, 0x00, key_len);
+
+       for (i = 0; i < key_len; i++)
+       {
+               for (j = 0; j < 8; j++)
+               {
+                       i0 = 8*i + j;
+                       i1 = i0 + this->n4;
+                       i2 = i1 + this->n4;
+                       i3 = i2 + this->n4;
+
+                       tmp[0] = this->q16 + 8 * (int32_t)v[i0] -
+                                        this->q  * (2*r[i0] + r[i3]);
+                       tmp[1] = this->q16 + 8 * (int32_t)v[i1] -
+                                        this->q  * (2*r[i1] + r[i3]);
+                       tmp[2] = this->q16 + 8 * (int32_t)v[i2] -
+                                        this->q  * (2*r[i2] + r[i3]);
+                       tmp[3] = this->q16 + 8 * (int32_t)v[i3] -
+                                        this->q *  (          r[i3]);
+
+                       t = rec_g(this, tmp[0]) + rec_g(this, tmp[1]) +
+                               rec_g(this, tmp[2]) + rec_g(this, tmp[3]) - this->q8;
+
+                       key[i] |= ((t >> 31) & 0x01) << j;
+               }
+       }
+
+       return chunk_create(key, key_len);
+}
+
+METHOD(qske_newhope_reconciliation_t, destroy, void,
+       private_qske_newhope_reconciliation_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+qske_newhope_reconciliation_t *qske_newhope_reconciliation_create(int n, int32_t q)
+{
+       private_qske_newhope_reconciliation_t *this;
+
+       INIT(this,
+               .public = {
+                       .help_reconcile = _help_reconcile,
+                       .reconcile = _reconcile,
+                       .destroy = _destroy,
+               },
+               .n   =  n,
+               .n4  =  n / 4,
+               .q   =      q,
+               .q2  =  2 * q,
+               .q4  =  4 * q,
+               .q8  =  8 * q,
+               .q16 = 16 * q,
+       );
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.h b/src/libstrongswan/plugins/qske_newhope/qske_newhope_reconciliation.h
new file mode 100644 (file)
index 0000000..f1f9807
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup qske_newhope_reconciliation qske_newhope_reconciliation
+ * @{ @ingroup qske_newhope_p
+ */
+
+#ifndef QSKE_NEWHOPE_RECONCILIATION_H_
+#define QSKE_NEWHOPE_RECONCILIATION_H_
+
+typedef struct qske_newhope_reconciliation_t qske_newhope_reconciliation_t;
+
+#include <library.h>
+
+/**
+ * Class assisting the error reconciliation
+ * resulting in a key exchange error rate < 2^(-60)
+ */
+struct qske_newhope_reconciliation_t {
+
+       /**
+        * Generate reconciliation polynomial
+        *
+        * @param v                     polynomial v
+        * @param rbits         pseudo random bit array
+        * @return                      return array with reconciliation polynomial
+        */
+       uint8_t* (*help_reconcile)(qske_newhope_reconciliation_t *this,
+                                                          uint32_t *v, uint8_t *rbits);
+
+       /**
+        * Use reconciliation polynomial r to derive shared secret
+        *
+        * @param v                     polynomial v or v'
+        * @param r                     reconciliation polynomial r
+        * @return                      Return shared secret
+        */
+       chunk_t (*reconcile)(qske_newhope_reconciliation_t *this,
+                                               uint32_t *v, uint8_t *r);
+
+       /**
+        * Destroy a qske_newhope_reconciliation_t object
+        */
+       void (*destroy)(qske_newhope_reconciliation_t *this);
+};
+
+/**
+ * Creates a new qske_newhope_reconciliation_t object.
+ *
+ * @param n                            array size
+ * @param q                            prime modulus
+ * @return                             qske_newhope_reconciliation_t object
+ */
+qske_newhope_reconciliation_t *qske_newhope_reconciliation_create(int n, int32_t q);
+
+#endif /** QSKE_NEWHOPE_RECONCILIATION_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/.gitignore b/src/libstrongswan/plugins/qske_newhope/tests/.gitignore
new file mode 100644 (file)
index 0000000..bbecbbc
--- /dev/null
@@ -0,0 +1 @@
+qske_newhope_tests
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/Makefile.am b/src/libstrongswan/plugins/qske_newhope/tests/Makefile.am
new file mode 100644 (file)
index 0000000..8a1c758
--- /dev/null
@@ -0,0 +1,25 @@
+TESTS = qske_newhope_tests
+
+check_PROGRAMS = $(TESTS)
+
+qske_newhope_tests_SOURCES = \
+       suites/test_qske_newhope.c \
+       suites/test_qske_newhope_noise.c \
+       suites/test_qske_newhope_reconciliation.c \
+       qske_newhope_tests.h qske_newhope_tests.c
+
+qske_newhope_tests_CFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libstrongswan/tests \
+       -I$(top_srcdir)/src/libstrongswan/math/libnttfft \
+       -I$(top_srcdir)/src/libstrongswan/plugins/qske_newhope \
+       -DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+       -DPLUGINS=\""${s_plugins}\"" \
+       @COVERAGE_CFLAGS@
+
+qske_newhope_tests_LDFLAGS = @COVERAGE_LDFLAGS@
+qske_newhope_tests_LDADD = \
+       $(top_builddir)/src/libstrongswan/libstrongswan.la \
+       $(top_builddir)/src/libstrongswan/tests/libtest.la \
+       $(top_builddir)/src/libstrongswan/math/libnttfft/libnttfft.la \
+       ../libqske-newhope.la
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.c b/src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.c
new file mode 100644 (file)
index 0000000..b3dd5d6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <test_runner.h>
+
+#include <library.h>
+
+/* declare test suite constructors */
+#define TEST_SUITE(x) test_suite_t* x();
+#include "qske_newhope_tests.h"
+#undef TEST_SUITE
+
+static test_configuration_t tests[] = {
+#define TEST_SUITE(x) \
+       { .suite = x, },
+#include "qske_newhope_tests.h"
+       { .suite = NULL, }
+};
+
+static bool test_runner_init(bool init)
+{
+       if (init)
+       {
+               char *plugins, *plugindir;
+
+               plugins = lib->settings->get_str(lib->settings,
+                                                                               "tests.load", PLUGINS);
+               plugindir = lib->settings->get_str(lib->settings,
+                                                                               "tests.plugindir", PLUGINDIR);
+               plugin_loader_add_plugindirs(plugindir, plugins);
+               if (!lib->plugins->load(lib->plugins, plugins))
+               {
+                       return FALSE;
+               }
+       }
+       else
+       {
+               lib->processor->set_threads(lib->processor, 0);
+               lib->processor->cancel(lib->processor);
+               lib->plugins->unload(lib->plugins);
+       }
+       return TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+       return test_runner_run("qske_newhope", tests, test_runner_init);
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.h b/src/libstrongswan/plugins/qske_newhope/tests/qske_newhope_tests.h
new file mode 100644 (file)
index 0000000..f2a52d1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+TEST_SUITE(qske_newhope_suite_create)
+TEST_SUITE(qske_newhope_noise_suite_create)
+TEST_SUITE(qske_newhope_reconciliation_suite_create)
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope.c b/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope.c
new file mode 100644 (file)
index 0000000..775a738
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <qske_newhope.h>
+
+#include <library.h>
+
+#include <time.h>
+
+const int count = 1000;
+
+START_TEST(test_qske_newhope_good)
+{
+       chunk_t i_msg, r_msg, i_shared_secret, r_shared_secret;
+       qske_t *i_nh, *r_nh;
+       struct timespec start, stop;
+       int i;
+
+       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
+
+       for (i = 0; i < count; i++)
+       {
+               i_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+               ck_assert(i_nh != NULL);
+               ck_assert(i_nh->get_qske_mechanism(i_nh) == QSKE_NEWHOPE);
+
+               ck_assert(i_nh->get_public_key(i_nh, &i_msg));
+               ck_assert(i_msg.len == 1824);
+
+               r_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+               ck_assert(r_nh != NULL);
+
+               ck_assert(r_nh->set_public_key(r_nh, i_msg));
+               ck_assert(r_nh->get_ciphertext(r_nh, &r_msg));
+               ck_assert(r_msg.len == 2048);
+
+               ck_assert(r_nh->get_shared_secret(r_nh, &r_shared_secret));
+               ck_assert(r_shared_secret.len == 32);
+
+               ck_assert(i_nh->set_ciphertext(i_nh, r_msg));
+               ck_assert(i_nh->get_shared_secret(i_nh, &i_shared_secret));
+               ck_assert(i_shared_secret.len == 32);
+               ck_assert(chunk_equals(i_shared_secret, r_shared_secret));
+
+               /* cleanup */
+               chunk_clear(&i_shared_secret);
+               chunk_clear(&r_shared_secret);
+               chunk_free(&i_msg);
+               chunk_free(&r_msg);
+               i_nh->destroy(i_nh);
+               r_nh->destroy(r_nh);
+       }
+
+       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &stop);
+
+       DBG0(DBG_LIB, "%d Newhope DH loops in %d ms\n", count,
+                                 (stop.tv_nsec - start.tv_nsec) / 1000000 +
+                                 (stop.tv_sec - start.tv_sec) * 1000);
+}
+END_TEST
+
+START_TEST(test_qske_newhope_wrong)
+{
+       chunk_t i_msg, r_msg, i_shared_secret, r_shared_secret;
+       qske_t *i_nh, *r_nh;
+
+       i_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+       ck_assert(i_nh != NULL);
+       ck_assert(i_nh->get_public_key(i_nh, &i_msg));
+
+       r_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+       ck_assert(r_nh != NULL);
+       ck_assert(r_nh->set_public_key(r_nh, i_msg));
+       ck_assert(r_nh->get_ciphertext(r_nh, &r_msg));
+
+       /* destroy 1st instance of i_nh */
+       i_nh->destroy(i_nh);
+       chunk_free(&i_msg);
+
+       /* create 2nd instance of i_nh */
+       i_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+       ck_assert(i_nh != NULL);
+       ck_assert(i_nh->get_public_key(i_nh, &i_msg));
+       ck_assert(i_nh->set_ciphertext(i_nh, r_msg));
+
+       ck_assert(r_nh->get_shared_secret(r_nh, &r_shared_secret));
+       ck_assert(i_nh->get_shared_secret(i_nh, &i_shared_secret));
+       ck_assert(!chunk_equals(i_shared_secret, r_shared_secret));
+
+       /* cleanup */
+       chunk_clear(&i_shared_secret);
+       chunk_clear(&r_shared_secret);
+       chunk_free(&i_msg);
+       chunk_free(&r_msg);
+       i_nh->destroy(i_nh);
+       r_nh->destroy(r_nh);
+}
+END_TEST
+
+START_TEST(test_qske_newhope_fail_i)
+{
+       qske_t *i_nh;
+       char buf_ff[2048];
+       int i;
+
+       chunk_t i_msg;
+
+       chunk_t r_msg[] = {
+               chunk_empty,
+               chunk_from_chars(0x00),
+               chunk_create(buf_ff, 2047),
+               chunk_create(buf_ff, 2048),
+       };
+
+       memset(buf_ff, 0xff, sizeof(buf_ff));
+
+               for (i = 0; i < countof(r_msg); i++)
+       {
+               i_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+               ck_assert(i_nh != NULL);
+               ck_assert(i_nh->get_public_key(i_nh, &i_msg));
+               ck_assert(!i_nh->set_ciphertext(i_nh, r_msg[i]));
+               chunk_free(&i_msg);
+               i_nh->destroy(i_nh);
+       }
+}
+END_TEST
+
+START_TEST(test_qske_newhope_fail_r)
+{
+       qske_t *r_nh;
+       char buf_ff[1824];
+       int i;
+
+       chunk_t i_msg[] = {
+               chunk_empty,
+               chunk_from_chars(0x00),
+               chunk_create(buf_ff, 1823),
+               chunk_create(buf_ff, 1824),
+       };
+
+       memset(buf_ff, 0xff, sizeof(buf_ff));
+
+       for (i = 0; i < countof(i_msg); i++)
+       {
+               r_nh = lib->crypto->create_qske(lib->crypto, QSKE_NEWHOPE);
+               ck_assert(r_nh != NULL);
+               ck_assert(!r_nh->set_public_key(r_nh, i_msg[i]));
+               r_nh->destroy(r_nh);
+       }
+}
+END_TEST
+
+Suite *qske_newhope_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("qske_newhope");
+
+       tc = tcase_create("good");
+       test_case_set_timeout(tc, 30);
+       tcase_add_test(tc, test_qske_newhope_good);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("wrong");
+       tcase_add_test(tc, test_qske_newhope_wrong);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("fail_i");
+       tcase_add_test(tc, test_qske_newhope_fail_i);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("fail_r");
+       tcase_add_test(tc, test_qske_newhope_fail_r);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_noise.c b/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_noise.c
new file mode 100644 (file)
index 0000000..ee4b88d
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <qske_newhope_noise.h>
+
+#include <library.h>
+
+static const uint16_t n = 1024;
+static const uint16_t q = 12289;
+
+static const size_t seed_len = 32;
+
+typedef struct {
+       uint8_t key;
+       uint8_t nonce;
+       uint8_t uniform[64];
+       uint32_t poly[1024];
+} noise_t;
+
+static noise_t noises[] = {
+       { 0x00, 0x00,   /* polynomial s */
+         { 0x9f, 0x07, 0xe7, 0xbe, 0x55, 0x51, 0x38, 0x7a, 0x98, 0xba,
+               0x97, 0x7c, 0x73, 0x2d, 0x08, 0x0d, 0xcb, 0x0f, 0x29, 0xa0,
+               0x48, 0xe3, 0x65, 0x69, 0x12, 0xc6, 0x53, 0x3e, 0x32, 0xee,
+               0x7a, 0xed, 0x29, 0xb7, 0x21, 0x76, 0x9c, 0xe6, 0x4e, 0x43,
+               0xd5, 0x71, 0x33, 0xb0, 0x74, 0xd8, 0x39, 0xd5, 0x31, 0xed,
+               0x1f, 0x28, 0x51, 0x0a, 0xfb, 0x45, 0xac, 0xe1, 0x0a, 0x1f,
+               0x4b, 0x79, 0x4d, 0x6f },
+         { 12286, 12288, 12287,     5,     4, 12288, 12286, 12287,     2,     2,
+                   2, 12288,     2, 12284,     1, 12288, 12288, 12288,     6, 12288,
+                   0,     4,     1, 12285, 12286,     2, 12284, 12287,     1,     5,
+                   5, 12286, 12288,     2, 12286,     0,     3,     1,     0,     2,
+                   0,     0,     4, 12283, 12284,     4,     0, 12288,     3, 12288,
+                   0,     4,     1, 12288, 12286,     0,     3,     1, 12286, 12287,
+               12285,     3,     2,     3, 12286,     0,     6,     6, 12288, 12284,
+                   0, 12282,     1,     0,     4,     1,     0,     3,     2,     2,
+                   3,     3,     2, 12288,     3,     1, 12287, 12285,     0, 12288,
+                   0,     0, 12288, 12287, 12284, 12286,     0, 12288,     4,     4,
+               12288,     5, 12286,     2, 12288,     5,     1, 12283,     1, 12288,
+                   1, 12288, 12287, 12285,     2,     2, 12285, 12284,     0, 12285,
+               12287,     0,     1,     0,     2, 12288, 12288, 12287,     0,     4,
+               12288, 12285, 12288,     0,     2,     1, 12287,     3,     1,     3,
+                   5, 12286,     1,     0, 12286,     0,     4,     0, 12288,     1,
+               12288,     4,     5, 12283, 12288,     1,     3, 12283, 12286,     5,
+                   1, 12286, 12287, 12286,     0, 12287, 12285,     1,     0,     0,
+                   1,     3,     0,     0,     0, 12284, 12286,     2,     4, 12288,
+                   6,     1,     2, 12288,     1, 12287, 12286, 12284, 12287,     1,
+                   3, 12284,     0,     0,     6, 12286,     7,     5,     2,     3,
+               12285, 12287, 12285,     2,     3, 12283,     2, 12284, 12288,     3,
+               12288,     1,     4, 12287,     2, 12288, 12288,     1, 12286, 12284,
+                   2,     1,     5, 12286,     0, 12288,     0,     0,     0, 12287,
+                   1,     0,     3,     0,     0,     6,     2, 12283,     1,     3,
+                   3, 12284,     3,     1, 12286,     2, 12288,     0,     6,     1,
+                   1, 12285, 12287, 12288,     4,     2, 12288,     3, 12286, 12288,
+               12287,     3,     3,     2,     7,     4, 12287, 12286, 12287,     2,
+                   2, 12287,     1, 12288,     1, 12287, 12283, 12287, 12288,     1,
+               12283,     0, 12286, 12288,     4, 12287, 12286, 12286,     2,     2,
+               12287,     5, 12288,     4,     0, 12287,     1,     3, 12286,     2,
+                   1,     1, 12288, 12287,     5, 12288,     0,     0,     1,     0,
+               12286,     6,     2,     1,     2,     5, 12286,     6, 12286, 12288,
+                   0, 12286,     3, 12283, 12288, 12284,     0,     7,     2,     6,
+                   1, 12288, 12285, 12284,     1,     0,     0,     2, 12288, 12288,
+               12288,     3,     3,     1,     3, 12286,     4,     3, 12284,     4,
+                   1, 12287, 12287, 12285,     0, 12287, 12287, 12287, 12286, 12288,
+                   1, 12287,     1,     0, 12288,     2,     0,     4,     0, 12287,
+               12285, 12285,     5,     3, 12282,     0, 12287,     5, 12287,     1,
+               12283, 12288, 12288,     3,     1,     1,     3, 12288, 12283,     5,
+               12288, 12288,     5,     5,     1, 12286, 12286, 12288,     1,     2,
+                   1,     3, 12287, 12288, 12284, 12287,     1, 12287,     0, 12286,
+               12285,     1, 12287, 12282, 12286, 12287,     0, 12285,     4,     2,
+                   1, 12282,     0,     1, 12288, 12285, 12284, 12286, 12286, 12287,
+               12288,     1, 12288,     4, 12287,     4, 12287, 12287,     0,     1,
+               12287,     3,     1, 12286, 12286,     4,     6, 12288,     1, 12285,
+               12286, 12287,     0, 12287, 12287,     1, 12286,     5,     0,     2,
+               12283, 12284,     1, 12286,     0, 12287, 12286, 12288,     1,     4,
+                   4, 12283,     2,     6,     1, 12288, 12286,     2,     7,     2,
+                   1, 12288,     5, 12284, 12288, 12288,     1,     7,     3, 12283,
+                   1, 12286,     2, 12288, 12287,     1, 12286,     1, 12286, 12288,
+               12287,     3,     2,     2,     0, 12284, 12287,     1,     1, 12284,
+               12286,     1,     2,     1,     0, 12285,     1,     0,     1,     2,
+                   2,     4, 12288,     1, 12288,     5,     0, 12287, 12288,     2,
+                   0, 12288, 12287,     0, 12288, 12288,     0,     0, 12285,     4,
+                   2, 12288,     0,     2,     0, 12288,     1,     3, 12287, 12288,
+               12288, 12288, 12286,     0, 12285, 12286, 12287,     3,     0, 12286,
+                   2,     1, 12285,     2, 12288,     0,     5,     0,     1, 12288,
+               12288,     4,     3,     3, 12286,     2, 12288,     4, 12288,     6,
+                   2, 12286,     4, 12287,     2, 12287,     0, 12284, 12288,     0,
+               12286, 12288,     3,     4, 12286, 12288,     1,     3, 12286,     3,
+                   4,     1,     1,     6,     3,     1,     1,     0, 12288,     4,
+                   0, 12288,     0,     0,     0, 12288,     2,     4,     2, 12287,
+                   0,     0,     3,     2,     3,     4,     0,     3,     2, 12288,
+                   2,     4,     6, 12286, 12284, 12287,     1,     0,     0,     4,
+                   1,     3, 12282,     1,     2,     2,     0,     3, 12282,     2,
+               12287,     2, 12288,     4, 12288,     3,     3, 12283, 12288, 12288,
+               12286, 12287,     5,     4,     3,     3, 12288, 12284,     2,     2,
+                   0, 12288,     1,     3,     3,     4, 12284, 12288,     0,     1,
+               12284,     0, 12286, 12287,     0,     0, 12287,     0,     1,     6,
+               12288,     1, 12284, 12287, 12282, 12288,     4, 12287,     1, 12286,
+                   1, 12286, 12286,     1,     4,     0, 12288,     1, 12288,     1,
+               12285,     3,     1,     0,     1,     0, 12288, 12287,     2,     2,
+                   0, 12288,     3, 12284,     2, 12288, 12288, 12288, 12287,     3,
+                   3,     0, 12286, 12286,     1,     2, 12286, 12287,     0,     1,
+               12288, 12287, 12287, 12288, 12288,     1,     9,     1, 12288, 12287,
+                   2,     1,     1,     0, 12287, 12287,     2,     2, 12288, 12285,
+                   1, 12287,     4,     0,     2,     1,     1,     3, 12284, 12286,
+                   1,     2, 12288, 12287,     4,     1, 12285,     0,     1,     2,
+               12288,     1,     3,     0, 12286,     0, 12288, 12286, 12287, 12286,
+                   1, 12284,     1,     2,     2, 12288,     0, 12288,     1, 12284,
+                   2,     3, 12287,     1, 12285, 12288,     0,     1, 12284,     2,
+               12288, 12286, 12286,     3, 12288, 12282,     3, 12287, 12288, 12287,
+                   4, 12287,     1,     2,     9, 12283, 12286, 12286,     0,     4,
+               12288, 12288,     4,     0,     1,     1,     2, 12284,     1,     1,
+                   0, 12288,     1,     0, 12287,     1,     1,     5,     2,     1,
+               12288,     3, 12287,     5,     4,     1,     4, 12287, 12285,     3,
+               12286,     1,     3,     0, 12287,     0, 12286, 12287, 12287, 12287,
+                   3,     2, 12286, 12284,     2, 12288,     1,     1, 12288,     3,
+                   1,     3, 12284,     3, 12282, 12288,     3,     0,     2, 12288,
+                   0,     5,     0,     2,     0, 12281, 12285,     4,     3,     4,
+                   2, 12284,     0,     0,     2,     2, 12287, 12284,     2, 12286,
+                   1, 12288,     1, 12286, 12286, 12287,     4,     0,     6,     3,
+                   0,     3, 12288, 12288, 12288, 12287,     3,     1,     1,     1,
+                   2, 12287, 12284,     3, 12286, 12280,     3, 12284, 12287, 12288,
+                   5, 12288, 12284,     2, 12285,     4,     3, 12286,     6,     2,
+                   1, 12287,     0,     1,     2, 12286,     1,     0, 12287,     0,
+                   1,     1, 12286,     2, 12285,     0,     1, 12288,     0,     1,
+               12288,     1, 12288, 12287, 12287, 12285, 12282, 12288,     2, 12288,
+                   2, 12284,     1, 12284, 12287, 12286, 12288,     0, 12288,     1,
+               12283, 12286,     5,     3,     0, 12286, 12286,     3,     1,     0,
+                   1, 12288, 12288,     4,     1, 12286, 12287, 12285,     2,     0,
+                   2, 12287,     1, 12285, 12288, 12286, 12288,     2,     2, 12285,
+                   3, 12286, 12285, 12287 }
+       },
+       { 0x00, 0x01,   /* polynomial e */
+         { 0x46, 0xf0, 0xf6, 0xef, 0xee, 0x15, 0xc8, 0xf1, 0xb1, 0x98,
+               0xcb, 0x49, 0xd9, 0x2b, 0x99, 0x08, 0x67, 0x90, 0x51, 0x59,
+               0x44, 0x0c, 0xc7, 0x23, 0x91, 0x6d, 0xc0, 0x01, 0x28, 0x26,
+               0x98, 0x10, 0x39, 0xce, 0x17, 0x66, 0xaa, 0x25, 0x42, 0xb0,
+               0x5d, 0xb3, 0xbd, 0x80, 0x9a, 0xb1, 0x42, 0x48, 0x9d, 0x5d,
+               0xbf, 0xe1, 0x27, 0x3e, 0x73, 0x99, 0x63, 0x7b, 0x4b, 0x32,
+               0x13, 0x76, 0x8a, 0xaa },
+         { 12283,     1, 12288,     4,     0, 12285,     5,     1,     1,     2,
+                   3,     4, 12288,     0,     3,     1,     1,     0, 12286,     6,
+                   1,     0,     1,     0,     4,     2, 12288,     3,     0,     5,
+                   1,     5,     2, 12285,     4, 12288,     3,     2, 12288,     2,
+               12288, 12285, 12287,     6, 12282,     1, 12286,     7, 12287,     4,
+                   2,     2, 12288, 12285,     0,     2,     0, 12288,     1, 12287,
+               12287,     2,     1,     2,     1, 12285, 12288, 12286,     1,     2,
+               12287, 12288, 12288,     1,     0, 12287,     0,     4,     2,     6,
+               12287, 12285, 12283, 12285,     5, 12283, 12286,     1, 12283,     2,
+                   3, 12286, 12285,     2,     5, 12286,     3,     0,     3, 12286,
+                   5, 12285, 12287, 12288,     1,     5,     3,     5,     1,     1,
+                   1, 12288,     5,     0, 12288,     3,     2, 12288, 12285, 12288,
+                   5,     6,     0,     2,     1, 12287, 12288, 12287,     3, 12284,
+                   2,     0,     3,     0,     0, 12288,     0,     2,     2,     2,
+                   0,     1,     2,     2,     0,     0, 12287, 12285,     0,     4,
+                   1, 12283,     3,     5, 12288, 12286, 12287,     6,     2,     0,
+                   0, 12287,     2,     2, 12288,     0,     2, 12288, 12287, 12288,
+               12288,     1, 12288,     1, 12288,     2,     4,     2,     1,     1,
+                   0, 12287,     3,     2,     6,     2,     1, 12288, 12285,     6,
+                   0,     1, 12284, 12287, 12287, 12286,     5,     4,     0,     5,
+               12287, 12286, 12288, 12286,     0,     3,     1, 12287, 12287, 12288,
+               12288, 12286,     1,     0,     3, 12287,     3,     1, 12283,     1,
+               12288,     5,     1,     4, 12286, 12287,     2,     0,     0,     0,
+               12281, 12286,     0,     8,     5,     0,     4,     0, 12287,     5,
+                   1,     3,     2, 12286, 12286, 12288, 12285, 12285, 12287,     0,
+               12284, 12287,     1,     0,     2,     1, 12286, 12288,     2, 12285,
+                   0,     0,     0,     1,     0,     6,     1, 12288, 12287, 12287,
+                   0,     3, 12288, 12288, 12287,     0, 12287,     1,     3,     0,
+                   0, 12286, 12286,     4,     4, 12287,     1,     3,     4, 12287,
+               12284,     2, 12288, 12286, 12283, 12285,     1,     3,     1, 12288,
+                   0,     3,     3, 12284, 12285,     5,     3, 12288,     3,     4,
+                   3,     1, 12288,     0, 12288,     1,     0,     0,     3,     0,
+                   3,     2, 12287, 12288,     0, 12288,     0,     2, 12285,     4,
+                   0, 12287, 12287,     1,     1,     1, 12287, 12285,     4, 12282,
+                   3,     1,     1, 12288,     2,     4, 12285, 12286,     3,     1,
+                   0, 12287, 12283, 12285,     2,     5,     1,     1, 12288, 12288,
+                   0,     8,     3, 12287, 12285, 12287, 12286, 12284,     1, 12286,
+                   1, 12288,     2,     3, 12288, 12288,     2, 12288, 12284, 12285,
+                   0,     3, 12288, 12288,     2,     3,     7, 12287,     3,     3,
+                   3, 12284,     0,     0,     1, 12283,     5,     0,     1, 12288,
+                   3, 12286, 12287, 12286,     0,     0, 12287, 12283,     4, 12283,
+                   0,     0,     3, 12285,     5, 12286, 12282, 12288,     1, 12287,
+               12288,     1,     5,     2, 12287,     2, 12288,     7, 12288,     3,
+                   5,     1,     0, 12287,     1, 12287,     3,     2,     4,     2,
+               12287, 12286, 12288,     2,     5,     1, 12286,     4,     0,     2,
+                   6, 12286,     2, 12286,     3, 12288,     5, 12285,     0,     2,
+               12287,     5, 12286, 12284,     7, 12285, 12286, 12284, 12287,     1,
+               12288, 12284, 12286,     2,     4,     2,     2, 12283, 12286,     2,
+                   2, 12283,     1, 12286,     1,     0, 12284,     3,     0,     4,
+                   1,     0,     4, 12288,     0, 12287, 12287, 12287, 12286, 12284,
+               12288,     3,     1, 12285,     0,     3,     8,     4,     2, 12288,
+                   3, 12287, 12287,     2,     3, 12288, 12286,     2, 12286, 12288,
+                   0,     1, 12287, 12285,     0, 12285, 12288, 12287,     1, 12287,
+                   0, 12284,     0,     1,     1, 12285,     0,     0,     0, 12287,
+               12287,     3,     0,     4, 12288,     1, 12288, 12285, 12283,     0,
+               12286, 12286, 12285, 12285, 12287,     1,     0,     2,     3,     1,
+                   2, 12286, 12288,     3, 12286, 12288, 12288,     6,     2,     2,
+                   0, 12288,     2,     5, 12288,     0, 12284, 12282, 12286,     1,
+               12288, 12288, 12286, 12288,     3, 12286,     2,     0, 12283,     0,
+                   4,     2, 12288,     0, 12286,     0,     4,     3, 12286, 12287,
+                   4, 12288,     3,     2, 12283,     1,     1,     1,     3, 12286,
+                   4,     0, 12288, 12285, 12287,     0,     0, 12286,     4,     0,
+               12286,     2, 12288, 12288, 12285, 12283,     5,     3, 12286, 12288,
+                   4,     1, 12283,     0, 12288,     0, 12287, 12287,     0,     3,
+               12287, 12287,     2,     2,     3,     0,     1,     4, 12288,     3,
+                   3,     0, 12284, 12285,     4, 12288,     1, 12287,     0,     1,
+               12283,     1, 12284, 12287, 12286, 12285,     0,     0,     3, 12285,
+                   3,     1, 12288, 12287, 12284, 12282,     5,     3,     3,     2,
+               12285,     4, 12288,     0,     3, 12288,     4,     0, 12283, 12288,
+                   2, 12285, 12288, 12282,     0,     2, 12285,     3,     1, 12284,
+                   1,     5,     7, 12286,     5, 12285,     1,     2,     0,     4,
+               12283, 12287, 12286,     2, 12280, 12287, 12288,     2, 12285, 12286,
+                   2,     1,     2,     1,     2,     2,     3,     3,     0,     0,
+                   4,     2, 12288, 12286,     4,     0,     1, 12288,     2, 12287,
+               12288, 12288,     1,     3, 12283, 12288,     1, 12287,     1,     1,
+                   3, 12288, 12288,     1,     2,     1,     1, 12283,     7, 12286,
+               12288,     1, 12288, 12287, 12284,     7,     2, 12285, 12286,     0,
+                   0,     0,     2,     4, 12288,     0, 12284, 12285, 12286,     2,
+               12284,     2,     4,     6,     3, 12287, 12288, 12285,     1,     2,
+               12286,     0,     0, 12287, 12288,     0, 12286,     2,     1,     1,
+                   1,     3,     1, 12285,     4,     0, 12287, 12288, 12287,     0,
+               12288, 12287, 12288, 12287, 12288, 12288,     0, 12287, 12284,     0,
+               12288, 12285,     3,     2,     4,     2, 12284,     3,     1,     3,
+                   4, 12288, 12285, 12284, 12287,     1,     4,     0,     2, 12288,
+                   4, 12288, 12287,     3,     1,     0,     0, 12284, 12287,     2,
+                   4, 12287,     2, 12288,     0,     2,     2,     3, 12287, 12286,
+                   8, 12286, 12285,     0, 12285,     2,     3,     5, 12287, 12288,
+                   6, 12288, 12284,     0,     0,     3,     1,     2, 12284,     2,
+                   1,     3,     2,     0,     0, 12288, 12287, 12288,     1, 12288,
+                   4,     3, 12284,     1,     3, 12288, 12283, 12288,     1,     1,
+                   2,     1,     1,     3,     1, 12288,     0, 12288,     2,     0,
+                   0, 12284, 12283,     3, 12288,     0,     2, 12287,     0,     0,
+               12286, 12286,     0,     0,     2,     4, 12288,     1,     2,     3,
+                   2, 12286, 12286,     1,     2,     4, 12288, 12288, 12284, 12287,
+                   6,     2, 12288, 12286,     0,     0,     3, 12286, 12288, 12287,
+               12286, 12287,     3,     1, 12286,     0,     4,     3, 12286,     5,
+                   2,     1, 12287, 12286,     4, 12287,     0,     5, 12288,     0,
+               12288,     2,     2,     1,     1,     0,     0, 12288, 12288, 12288,
+                   0,     0, 12288, 12287,     5,     1, 12288,     1,    10,     1,
+                   0,     0,     2,     2,     2,     0, 12288,     4,     2, 12283,
+                   3,     1,     1, 12285,     2, 12285,     5,     7,     5, 12288,
+                   0, 12287,     5,     1, 12288, 12286, 12287,     0,     0,     0,
+               12287,     1,     3, 12288 }
+       },
+       { 0x01, 0x00,   /* polynomial s' */
+         { 0x3a, 0xeb, 0x52, 0x24, 0xec, 0xf8, 0x49, 0x92, 0x9b, 0x9d,
+               0x82, 0x8d, 0xb1, 0xce, 0xd4, 0xdd, 0x83, 0x20, 0x25, 0xe8,
+               0x01, 0x8b, 0x81, 0x60, 0xb8, 0x22, 0x84, 0xf3, 0xc9, 0x49,
+               0xaa, 0x5a, 0x8e, 0xca, 0x00, 0xbb, 0xb4, 0xa7, 0x3b, 0xda,
+               0xd1, 0x92, 0xb5, 0xc4, 0x2f, 0x73, 0xf2, 0xfd, 0x4e, 0x27,
+               0x36, 0x44, 0xc8, 0xb3, 0x61, 0x25, 0xa6, 0x4a, 0xdd, 0xeb,
+               0x00, 0x6c, 0x13, 0xa0 },
+         {     5,     4,     4, 12288, 12286,     1, 12287, 12288,     2, 12288,
+               12288, 12287,     2,     2, 12284, 12288, 12288,     3,     2,     3,
+               12287,     2,     2,     0,     0,     2,     5, 12285,     5, 12287,
+                   2, 12282, 12286,     2,     1,     2,     1,     1, 12288, 12285,
+               12287, 12286,     2,     0,     0, 12285,     0,     0, 12287, 12286,
+               12285, 12286,     2, 12288, 12288,     0,     1,     2, 12286,     2,
+                   1,     0,     0,     2,     1, 12288,     1, 12287,     1,     0,
+                   0,     2, 12285,     2,     2, 12288, 12286,     3, 12287,     0,
+                   1,     1,     0,     2, 12287,     2,     1,     2,     3,     0,
+                   0,     1, 12288, 12288,     2, 12287, 12286, 12286,     6, 12288,
+                   0,     0,     4,     0, 12286,     0,     4, 12288, 12288,     5,
+               12287, 12288, 12285,     2, 12285, 12288,     1,     0,     2, 12288,
+               12286,     1,     3, 12285,     2,     2,     1,     1, 12288, 12288,
+               12287,     1, 12288,     3,     0, 12285,     4, 12285, 12287,     2,
+                   2, 12287, 12287, 12286, 12288, 12284,     2, 12286,     4,     1,
+                   0, 12286, 12284,     3, 12286,     3, 12286,     3,     4,     1,
+               12288, 12282,     2,     2, 12284,     0, 12286, 12283,     3,     0,
+                   4,     2,     4,     2, 12285,    10, 12288,     8,     3,     2,
+                   2,     0,     1,     0,     0, 12286,     2, 12284,     4,     1,
+               12287, 12287,     1,     1, 12286,     1,     0, 12285, 12288, 12286,
+               12287,     2,     1, 12284, 12288, 12285, 12285,     3,     0,     1,
+                   4,     4,     1,     0,     2,     1, 12288,     1, 12287,     0,
+               12286,     4,     2,     3,     3, 12285, 12288, 12288,     5,     2,
+                   0,     4,     3, 12287, 12287,     5,     2,     3, 12284,     0,
+                   8,     1,     1,     0,     5, 12288, 12288, 12288, 12286,     6,
+                   3, 12288, 12286, 12287,     4, 12288,     2, 12288, 12284, 12287,
+                   4, 12288,     0,     0,     3,     0,     4,     4, 12287,     0,
+                   3,     0, 12285, 12287, 12288, 12288,     0,     0, 12287, 12288,
+               12286,     0,     0, 12285, 12288,     4, 12287,     1,     2, 12288,
+               12285,     5,     4, 12283,     2,     0, 12288,     2,     0,     0,
+               12286, 12284,     3,     3,     3, 12287,     1,     1,     0,     1,
+                   3, 12288,     4,     4,     0,     2,     0,     1, 12286, 12284,
+                   2,     2, 12287,     3,     2, 12288,     3, 12286,     2, 12286,
+               12288,     4,     3, 12288,     2, 12288,     2,     1, 12288, 12288,
+                   7, 12288, 12288,     0, 12288,     1, 12284, 12288, 12288, 12287,
+               12287,     1, 12285, 12287, 12287,     1,     0,     2, 12286,     3,
+               12288, 12288, 12287,     3,     5,     0,     0, 12287,     2, 12287,
+               12288,     8, 12287,     1,     2, 12288, 12284,     3,     0, 12287,
+               12284,     3,     0,     2,     1,     3,     4, 12287, 12286, 12288,
+               12286,     0,     0, 12287, 12285,     0, 12286,     2,     1, 12287,
+               12288,     5, 12287, 12287, 12286,     2, 12283,     0,     0, 12286,
+                   2, 12284,     5,     0,     1, 12287,     0,     3,     1, 12285,
+               12288,     0,     3, 12287,     2, 12286,     0,     1, 12288,     1,
+               12284, 12281, 12284, 12288, 12285,     2,     5,     4, 12286,     0,
+               12287, 12288, 12286, 12285,     3, 12282,     1, 12287,     2,     0,
+                   6, 12288,     4, 12286,     3, 12288, 12286, 12284,     3,     1,
+                   6,     3,     2,     1,     2,     1,     1, 12288, 12287,     1,
+                   3,     3,     1,     0,     0, 12288,     3, 12284, 12285, 12284,
+                   1,     3, 12286,     0,     1, 12285, 12287,     1, 12285,     2,
+                   0,     1, 12287,     1,     4,     3,     1, 12287,     0,     5,
+                   1, 12288,     2,     1,     1,     4,     3, 12286,     3,     3,
+                   2, 12287,     3, 12286,     0, 12288, 12285,     2,     3, 12286,
+                   0, 12287,     5,     4,     1,     1, 12287, 12288,     2,     0,
+                   0,     0,     2,     0, 12286,     4, 12288, 12288, 12285, 12286,
+                   2, 12288, 12288,     0, 12288, 12286, 12284, 12287,     1,     5,
+                   0, 12285, 12287,     2,     4,     3, 12285, 12287, 12288,     0,
+               12288, 12287, 12286,     2, 12288, 12286, 12284,     1,     2, 12287,
+                   4,     1,     4,     4, 12284,     2,     0, 12288,     3,     1,
+                   0,     4,     1,     6,     0, 12286, 12288, 12287, 12287,     0,
+               12284, 12285,     2, 12286,     1,     0,     3, 12288,     1,     2,
+               12284, 12286, 12285, 12283, 12285,     0, 12285,     2,     0,     2,
+                   1,     3,     1, 12286, 12288,     1,     4,     0,     0, 12287,
+               12287, 12286,     0,     1, 12286,     0,     2, 12288,     2, 12287,
+                   0,     0, 12286, 12287,     4,     6, 12286,     0, 12288,     0,
+                   0, 12287,     2,     3,     4,     1,     3, 12286,     4,     0,
+               12288, 12286, 12287, 12287, 12288,     4, 12285,     1, 12286, 12286,
+                   2, 12288,     0,     0,     1,     5, 12285,     1, 12281,     3,
+               12281,     2,     3,     0, 12284, 12288,     5,     0,     0, 12288,
+                   0,     0, 12288, 12286,     3, 12287,     0,     2, 12288,     0,
+                   3, 12288, 12286,     0, 12286, 12287, 12284,     0, 12286,     1,
+               12287, 12282, 12287, 12288,     0,     5, 12288,     2,     1, 12288,
+                   1, 12285,     5,     2, 12286, 12285, 12287,     0,     2, 12288,
+                   1, 12288,     1, 12286,     0,     2, 12287, 12287,     6, 12286,
+               12288,     0, 12286,     4,     6, 12287, 12287,     2,     2, 12285,
+                   1, 12288, 12285, 12286,     5, 12288,     1,     2,     1,     7,
+               12286,     5, 12288, 12287, 12286, 12284,     1,     2, 12287,     4,
+                   1,     1,     0,     1,     2, 12285,     2, 12288, 12284,     1,
+                   1, 12287, 12286, 12285, 12287,     1, 12287,     3,     1, 12286,
+                   0, 12286,     3,     3, 12288,     2, 12288,     5, 12288,     1,
+                   2,     0, 12287,     1, 12287,     7,     2,     3,     0, 12287,
+                   2, 12284, 12284, 12281, 12286, 12285, 12287, 12287,     0, 12288,
+                   3,     4,     3,     2,     3,     1, 12288, 12286,     0, 12288,
+               12286,     1, 12286,     6, 12287,     1,     6,     5,     3,     1,
+               12286,     2,     1,     3,     1, 12286, 12285,     3,     2,     0,
+                   0, 12284,     1,     1,     3,     3,     1,     1, 12288,     0,
+               12284,     1, 12288,     0,     0, 12287,     0,     4, 12285,     0,
+                   4, 12283,     1,     1,     0, 12285,     0, 12286,     0,     0,
+                   1,     0, 12286,     0, 12288,     3,     4,     0,     2,     1,
+               12287,     2, 12288,     1,     0, 12288,     0, 12288,     6, 12288,
+               12287, 12286,     3, 12284,     0, 12288, 12284, 12286, 12287, 12288,
+               12288, 12288,     4,     0,     2,     6, 12286,     1,     4, 12288,
+                   2,     1,     0,     5,     2,     1, 12285,     0,     0, 12285,
+                   4, 12286,     5,     1,     3,     2, 12287,     2,     0,     2,
+                   7, 12283, 12288, 12288,     3,     0,     3, 12288,     3, 12286,
+               12288, 12287, 12288,     3,     0,     2,     4,     1, 12284,     2,
+               12288, 12286, 12287,     1,     1, 12288,     0, 12288, 12283,     6,
+                   2,     1, 12288,     3, 12287, 12288,     1,     1, 12285,     0,
+               12286, 12287, 12288,     1,     2, 12287,     0,     4,     0, 12286,
+                   2,     1, 12288, 12285, 12287,     0,     2, 12287,     6,     2,
+                   0, 12287, 12288,     2, 12288, 12284, 12288, 12285,     4,     1,
+               12288, 12284, 12287,     4, 12284,     1,     3, 12284, 12282,     0,
+               12286, 12287,     2, 12286,     3,     4,     2, 12288,     3,     3,
+                   1,     3, 12287, 12283 }
+       },
+       { 0x01, 0x01,   /* polynomial e' */
+         { 0x58, 0xd8, 0x6a, 0xcd, 0xe2, 0x79, 0x61, 0x98, 0xfd, 0xea,
+               0xcf, 0x2a, 0xc0, 0xfd, 0xf0, 0x72, 0x86, 0x32, 0xdc, 0xe9,
+               0xc6, 0x45, 0x81, 0x80, 0x67, 0x06, 0x72, 0x28, 0xa6, 0xfe,
+               0x41, 0x2b, 0x78, 0x88, 0x58, 0x6d, 0x58, 0x47, 0x3e, 0xb7,
+               0x46, 0x60, 0xd8, 0x2f, 0xa0, 0x83, 0xe4, 0xbc, 0x81, 0xdd,
+               0xc6, 0x29, 0x8b, 0xee, 0xf9, 0xec, 0x90, 0x39, 0x9d, 0x46,
+               0xbf, 0x2d, 0x7c, 0xdf },
+         { 12287,     3,     3,     1, 12285,     4,     1,     5, 12287, 12285,
+               12285, 12285,     1, 12288, 12287, 12288,     2,     3, 12283, 12288,
+               12285,     0,     0, 12286, 12287, 12288, 12288, 12288, 12288,     1,
+               12288,     2,     2,     5,     5,     0, 12287, 12286,     3,     3,
+                   2,     2,     1,     0,     2, 12287, 12285,     3,     1,     3,
+                   5,     2, 12287, 12287,     2,     0,     4,     2,     0,     0,
+                   1,     5, 12288,     6,     4, 12287,     1,     0, 12283,     0,
+                   1, 12286,     2,     0,     2,     1, 12284, 12282,     0,     6,
+                   1,     2,     5, 12288,     6, 12288, 12284,     2,     1,     2,
+               12288, 12283, 12288,     3, 12288, 12288,     2, 12286, 12283,     1,
+               12285,     0,     0, 12286, 12288, 12286, 12288, 12286,     4,     0,
+                   1, 12285,     3,     1,     2, 12285, 12287, 12284, 12287, 12285,
+               12286,     1, 12288,     3,     5,     5,     3, 12285, 12286, 12288,
+                   0,     1, 12287, 12284,     2,     4, 12288, 12287,     0, 12288,
+               12288, 12285, 12288, 12284,     3,     0,     2,     0,     2,     0,
+                   1,     1,     1, 12287,     1, 12284, 12285,     0, 12284,     1,
+               12284,     2, 12288,     5,     4,     1,     1, 12284,     1,     3,
+                   2,     6,     3,     2,     3, 12284,     0,     0,     4,     2,
+                   6,     2,     2,     2,     6, 12288,     0,     1, 12286,     1,
+                   5,     1, 12283,     2,     0, 12284,     1, 12286,     4,     1,
+                   2,     4,     6, 12288, 12288, 12284,     1,     0,     3, 12286,
+                   1,     0,     3, 12288, 12287,     2,     2,     0, 12285, 12286,
+                   0, 12288,     4,     2, 12282, 12287,     1, 12288, 12287, 12286,
+               12284,     1,     4,     2,     7, 12288, 12283, 12288,     5, 12288,
+               12288, 12287,     3,     2, 12287,     5, 12287, 12286, 12288, 12287,
+                   0, 12282, 12288, 12288,     0,     3, 12287,     2, 12287, 12284,
+                   6, 12285,     2,     3,     3, 12284,     2,     4, 12286,     5,
+                   0,     2, 12287,     3,     0, 12284, 12286,     0,     2, 12286,
+               12287,     3,     1,     4,     1, 12286, 12288,     1,     2,     0,
+               12285, 12287,     2,     0,     0,     0,     3, 12286, 12287,     2,
+                   0,     0,     0, 12286,     4,     1, 12287,     0,     0,     2,
+                   5,     0, 12284,     1,     1, 12288,     2, 12286, 12288,     2,
+                   2, 12282,     1, 12286,     4, 12286,     3, 12287, 12287, 12286,
+                   5,     5,     0, 12288,     3, 12285,     1, 12287,     7, 12286,
+                   2, 12287,     1, 12285,     2, 12287, 12288,     0,     4, 12281,
+                   0, 12286,     3,     1, 12285,     2,     2, 12285,     5,     0,
+               12285,     2, 12288,     1,     3, 12287,     1, 12288,     1,     5,
+               12287,     1,     0,     3,     2, 12286, 12286, 12288,     3,     0,
+               12287, 12288,     0, 12286, 12285,     0, 12286, 12288,     3, 12287,
+               12288,     2,     6,     0,     2, 12285,     1,     1,     7,     7,
+               12284, 12284,     5,     0, 12288, 12288,     4,     3,     1,     2,
+               12287,     0, 12288, 12284,     2,     5,     1,     2,     0, 12288,
+                   1, 12284,     2,     3,     0, 12287, 12285,     2, 12288, 12288,
+                   7,     1, 12287,     1, 12286,     2,     3,     4, 12288, 12288,
+               12286, 12286,     3, 12288,     1, 12286, 12286,     0, 12283, 12288,
+                   2,     0,     7,     2, 12287,     0,     0, 12286,     4,     1,
+               12288, 12288,     1,     2, 12287, 12282,     3,     5,     0, 12288,
+               12288, 12286, 12286, 12286,     4,     2,     0,     1, 12284,     3,
+               12283,     5, 12287,     2,     2, 12288,     1, 12284,     1,     0,
+                   1,     3, 12288,     2, 12287,     1, 12286, 12288,     0, 12287,
+               12288,     2,     2, 12286,     0, 12287, 12288, 12284,     0,     2,
+                   2,     2,     1,     3, 12285, 12285,     1, 12285,     2,     6,
+                   2,     0, 12288,     0,     0,     3,     2, 12287,     1, 12286,
+                   0, 12287,     0,     1, 12285, 12287,     6, 12288,     2,     0,
+               12286,     2,     4, 12288,     2,     5, 12285, 12286,     0, 12284,
+               12288,     3,     3,     3, 12287,     4,     2,     0, 12283,     2,
+               12287,     0,     1, 12287,     2, 12288, 12287,     3,     2,     7,
+                   7,     1, 12287, 12288,     2,     6,     1,     3,     2,     0,
+                   2,     2,     3, 12288,     3,     4,     2,     0,     5, 12285,
+                   3, 12285,     3, 12285,     1,     1, 12287, 12285,     2, 12285,
+                   5,     0,     7,     2, 12284,     0, 12285,     7,     1, 12288,
+               12288,     0, 12288, 12287,     5,     0,     2,     0,     2, 12286,
+                   1, 12286,     0, 12286, 12285,     4, 12286,     2, 12288, 12287,
+               12287,     1, 12286, 12287, 12287, 12286, 12287, 12288,     6,     5,
+                   2,     5, 12283, 12286, 12286, 12288,     1,     0,     3, 12286,
+                   5,     0, 12287, 12288, 12288, 12287, 12286,     2,     1,     0,
+                   1,     2,     3,     1, 12286,     2,     1,     6, 12288,     1,
+               12286,     1, 12288,     0,     1,     0, 12283,     0,     2, 12288,
+                   3,     1, 12287, 12288,     4,     0,     3, 12286,     0,     1,
+               12283,     4,     1,     4, 12287,     5,     0, 12287, 12288,     3,
+                   3, 12282,     1,     4,     2,     3,     0,     2,     6, 12282,
+               12285, 12288, 12287, 12288,     2, 12285,     1,     0, 12287, 12288,
+               12286,     0,     0,     4, 12288, 12287,     1,     0,     2,     5,
+                   2, 12287,     1,     7, 12284,     0, 12287, 12286,     2,     1,
+               12287,     0,     1, 12284, 12287, 12287, 12285, 12285,     3, 12282,
+               12286,     1,     1, 12288, 12282, 12287,     1,     1,     2,     2,
+                   3,     1, 12287,     5, 12282,     0,     0, 12287,     1,     3,
+               12288,     3, 12285, 12286,     2,     0, 12288, 12288,     5, 12285,
+                   4, 12288, 12287,     0,     1,     4,     1,     2, 12288,     0,
+                   2,     1, 12288,     4,     6, 12288,     1, 12287,     4,     1,
+               12285, 12288,     3,     0, 12288, 12285,     2,     0, 12286,     2,
+                   1, 12288,     1, 12288, 12284,     3,     0,     2,     2, 12288,
+               12287, 12286,     4, 12288,     2,     0,     0,     3,     4,     0,
+               12288, 12282,     6,     2, 12283, 12287,     2,     6,     1,     2,
+               12288,     2, 12283,     3, 12287,     3,     4,     0,     0, 12285,
+                   0, 12288, 12287, 12284, 12286,     3,     1, 12286,     2,     0,
+               12287, 12286, 12286, 12288,     5,     2, 12288, 12286,     0, 12287,
+                   0,     3,     2, 12287, 12286,     0,     1, 12287,     2,     0,
+               12286,     5, 12285, 12288, 12288, 12288, 12286,     4,     1, 12285,
+               12284, 12288, 12286,     1,     1, 12287,     2, 12286,     3,     2,
+               12283, 12283,     4,     2, 12283,     5,     0,     1,     0,     5,
+               12287,     1,     1,     0,     3,    10, 12287,     3, 12288, 12288,
+               12287,     2,     2,     0,     4, 12288, 12283, 12288,     1, 12287,
+                   3,     0,     0,     1, 12288, 12284,     0, 12286, 12287,     0,
+               12287,     2,     1,     7, 12288, 12287,     0,     4, 12287, 12286,
+                   3,     4, 12287, 12288, 12285, 12287, 12288, 12285, 12286,     7,
+                   1,     1, 12288,     3, 12287,     3,     1,     4,     2,     5,
+               12282,     3,     0, 12286, 12288,     0, 12285,     0,     2,     3,
+                   0, 12286,     3,     2, 12285,     0,     0, 12287,     1,     0,
+                   0,     6,     2, 12287, 12284,     7,     5,     0,     1,     6,
+                   2,     4,     1, 12286, 12288,     2, 12287,     3,     4, 12283,
+                   0, 12288,     2,     2, 12286,     0,     2,     2, 12288, 12285,
+               12287, 12285, 12288,     0 }
+       },
+       { 0x01, 0x02,   /* polynomial e'' */
+         { 0x20, 0x37, 0x77, 0x8a, 0x9c, 0x19, 0xde, 0xf0, 0x65, 0x9e,
+               0x0f, 0xa5, 0xfc, 0x0e, 0x78, 0xfe, 0x55, 0x89, 0xc9, 0x88,
+               0x41, 0xa2, 0x5a, 0x1e, 0xa4, 0x66, 0xcd, 0x3a, 0x29, 0x42,
+               0xd1, 0x25, 0xf2, 0x84, 0xd7, 0xee, 0xd5, 0x53, 0x86, 0x5b,
+               0xa3, 0x93, 0x4e, 0xee, 0xc7, 0x5b, 0xe5, 0x52, 0x68, 0x19,
+               0xdf, 0x63, 0xfb, 0x91, 0x3d, 0xe9, 0x5d, 0xd6, 0xeb, 0x81,
+               0x3d, 0xac, 0xf1, 0xad },
+         { 12286, 12286,     1, 12287,     1, 12286, 12287, 12287, 12284,     1,
+               12287,     2, 12284,     0,     2, 12288,     0,     1,     0, 12285,
+               12288,     4,     2, 12287, 12282, 12288, 12285, 12288,     2, 12288,
+                   6,     7, 12286, 12286,     1,     4, 12287, 12287,     3,     1,
+                   3,     3,     2, 12285,     0,     1, 12288,     1,     1, 12287,
+                   0,     0,     1,     0, 12287, 12283, 12283, 12288, 12287,     0,
+                   0,     2, 12286,     3,     3,     0, 12286, 12282,     3,     6,
+                   3,     3, 12285,     1,     1, 12288,     1,     0, 12288,     0,
+               12287,     4,     1,     0, 12285, 12288,     1,     1,     1,     3,
+               12286,     0, 12288,     0, 12287, 12287,     3,     5,     1, 12287,
+               12287,     0,     0,     0, 12283,     0,     0, 12288,     0, 12287,
+               12286, 12284, 12286,     0, 12286,     3,     5, 12287,     0, 12287,
+                   1,     3,     2,     6,     1, 12287,     1,     1, 12285,     4,
+               12282, 12288, 12288,     3,     2, 12287,     3,     3, 12288, 12286,
+                   2,     5, 12288, 12287, 12288,     3,     0, 12283,     3,     3,
+                   1,     0, 12288,     2,     2, 12287, 12286,     4, 12287, 12288,
+                   0,     0, 12286,     1,     4,     4, 12286, 12287,     4, 12288,
+                   2,     1,     1, 12288, 12287,     3, 12287, 12286, 12285, 12288,
+                   4,     1,     0, 12287,     3, 12286, 12287,     4,     0, 12287,
+               12286, 12287,     3,     1,     1, 12285, 12287,     0, 12285,     2,
+                   5,     2, 12285,     3,     2, 12285, 12287,     2,     0, 12288,
+                   2,     5,     2, 12283,     1,     1,     0, 12286, 12288,     3,
+                   1, 12286, 12283,     0,     1,     2,     2,     1, 12287, 12287,
+                   4,     4,     1,     0,     0, 12288, 12287, 12284, 12284,     7,
+                   0, 12288,     5,     4, 12288, 12288,     1,     0,     1,     1,
+                   2, 12288, 12288,     5,     1,     0, 12287,     3,     3,     0,
+                   1, 12288, 12288,     3, 12285, 12288,     3,     5,     4,     1,
+               12285, 12285, 12288, 12285, 12288, 12285,     4,     1,     3, 12285,
+                   4,     0, 12288, 12286,     5, 12287, 12285, 12288,     4, 12288,
+                   0, 12287, 12286,     0, 12286, 12283,     0, 12287, 12284,     1,
+               12288, 12288,     3, 12286,     1,     2, 12286,     3,     1, 12285,
+               12286, 12285,     0, 12285, 12288,     0,     2, 12283,     0,     1,
+                   2,     1,     2,     3,     3, 12285,     0,     0,     0, 12288,
+               12283,     4, 12286,     2,     1,     3,     3, 12284,     2,     4,
+                   3, 12286, 12282, 12286,     0, 12286, 12287,     3, 12288, 12288,
+                   2, 12287, 12286,     3,     0, 12286,     1,     1,     0, 12287,
+                   2,     0,     0,     1, 12286,     1,     0, 12283,     0, 12288,
+                   2,     5, 12288, 12287,     2,     1, 12288,     2,     2,     5,
+                   2, 12286, 12286,     2, 12284, 12287,     0, 12284,     0, 12284,
+               12286, 12286, 12288, 12287, 12287,     2,     1, 12287, 12287,     1,
+                   5,     0,     0, 12288,     2, 12285,     6,     2, 12288, 12288,
+               12286,     2, 12285,     0,     0,     0, 12288,     3, 12286,     1,
+                   1,     0,     3,     0, 12286, 12288, 12287,     3,     2, 12287,
+               12288,     1, 12288, 12282,     2,     0, 12288, 12286, 12285, 12281,
+                   4,     1,     7, 12283, 12287, 12288,     1,     6,     0, 12288,
+                   5,     1,     1, 12286, 12286,     0, 12287, 12285, 12287,     1,
+               12288, 12286, 12286, 12288,     2, 12287, 12287, 12288, 12286, 12288,
+               12282, 12284, 12286,     0, 12285, 12285,     3, 12288, 12287, 12288,
+                   2,     0,     2,     0, 12288, 12286,     3, 12288, 12286, 12287,
+                   1,     1,     1,     0,     5,     5, 12285, 12288,     3, 12286,
+                   1,     2, 12285,     1,     4, 12288,     1,     4,     1,     3,
+                   4, 12286,     0,     7,     2, 12288,     2, 12287,     0,     2,
+               12283, 12286,     0, 12288, 12286,     4,     1, 12284,     7, 12285,
+                   0, 12284, 12287,     0,     0,     3,     4, 12284,     0,     1,
+                   0,     1, 12285,     1, 12286, 12284, 12287,     0,     7,     1,
+                   4, 12282, 12288,     0,     2, 12285, 12288, 12287, 12287, 12283,
+                   0,     1,     3, 12285, 12286,     3, 12288, 12288, 12284, 12286,
+               12288,     1,     0,     2, 12287,     0, 12286,     4, 12288,     0,
+               12284,     0,     0,     2, 12286,     0,     0, 12286, 12287,     1,
+               12288,     0, 12284,     1, 12288, 12288,     1,     1, 12282, 12284,
+               12288, 12285, 12285, 12288,     1, 12286,     2,     0,     0, 12284,
+                   2, 12288,     0,     0, 12285,     0,     3,     0,     0, 12285,
+               12286,     5,     3, 12287,     5,     2, 12287,     0,     1, 12286,
+               12287,     1, 12286,     1, 12288,     0,     0, 12282,     5, 12282,
+               12287, 12288, 12287,     1,     0,     3,     4,     6,     1,     1,
+               12287, 12284, 12286, 12287, 12286,     2,     1, 12288,     3,     0,
+                   3,     0, 12286,     1,     0, 12288,     1, 12284,     4,     0,
+                   4, 12288,     1,     4,     1, 12286,     4,     0,     2,     1,
+                   1,     4, 12287,     2,     1, 12288,     4,     3,     2, 12287,
+                   0,     1, 12287,     1, 12285, 12286,     2,     2,     0, 12286,
+               12287,     0, 12288, 12285,     5, 12288,     0,     0, 12288,     3,
+               12288,     0,     4,     0, 12288, 12286, 12287,     0,     0,     2,
+               12283,     0, 12281,     1,     1,     3,     4,     2, 12284,     5,
+               12288,     2,     3,     4, 12287,     3, 12288, 12287, 12288,     2,
+               12286,     2,     0, 12286, 12286,     5, 12288,     2, 12288,     7,
+               12286, 12286,     4, 12288, 12288, 12288,     5, 12287,     7, 12286,
+               12282,     2, 12284,     0, 12288,     0,     2, 12283,     2,     5,
+                   4,     1, 12288, 12283,     5, 12288, 12288,     0,     0,     0,
+                   6,     1, 12286,     6,     4, 12287,     2, 12288, 12287, 12286,
+                   4,     5,     0,     1,     2,     1,     4, 12286,     1,     2,
+                   1,     1,     0, 12288, 12282,     1,     1,     3, 12284, 12288,
+                   0, 12287,     1, 12286, 12288,     6,     1,     5, 12287, 12285,
+                   2, 12288, 12288, 12284,     0, 12287,     2,     3,     5,     1,
+               12286,     1, 12287,     0, 12284,     1,     5, 12283,     1,     1,
+               12287, 12283, 12288,     0, 12287,     3,     0, 12288, 12286, 12287,
+                   8,     0,     0, 12288,     1,     3,     2,     3, 12287,     9,
+                   2,     3,     4, 12288,     3,     0, 12288, 12283,     0,     0,
+                   2,     4, 12287,     2, 12287, 12286, 12287,     2, 12287,     2,
+                   3,     1,     3,     1,     0,     1,     1,     5,     3, 12285,
+                   1, 12281, 12287, 12286,     1,     4, 12287, 12286, 12285,     4,
+                   2,     0, 12288, 12288, 12286, 12287, 12288,     1,     3,     4,
+                   0,     1, 12285,     4,     3, 12284,     1, 12288, 12285, 12288,
+                   0, 12281, 12288, 12285, 12285,     1, 12284, 12286, 12287,     0,
+                   0, 12287,     1, 12282,     4,     4, 12288,     1,     4, 12286,
+                   5,     4,     1,     5,     3,     1,     0,     6, 12288,     0,
+               12288,     2, 12286, 12287,     6,     0, 12288,     0, 12287,     1,
+                   4,     0, 12282,     4,     1, 12286,     1, 12282,     3, 12285,
+               12283, 12286, 12288,     4, 12284, 12286, 12286,     0, 12286,     0,
+                   0,     1, 12286,     1,     1,     4, 12284,     0,     3,     2,
+               12288,     1,     2, 12287,     2,     1, 12288,     0,     1,     2,
+               12286,     0,     6, 12285,     0,     1,     4,     0,     0,     3,
+                   2, 12287, 12285,     7,     1,     3,     1,     0, 12286, 12288,
+                   0, 12287,     1, 12286 }
+       }
+};
+
+START_TEST(test_qske_newhope_noise_uniform)
+{
+       qske_newhope_noise_t *noise;
+       uint8_t seed_buf[seed_len], *uniform;
+       chunk_t seed = { seed_buf, seed_len };
+
+       memset(seed_buf, 0x00, seed_len - 1);
+       seed_buf[seed_len - 1] = noises[_i].key;
+
+       noise = qske_newhope_noise_create(seed);
+       ck_assert(noise != NULL);
+       uniform = noise->get_uniform_bytes(noise, noises[_i].nonce, 64);
+       ck_assert(uniform != NULL);
+       ck_assert(memeq(uniform, noises[_i].uniform, 64));
+       free(uniform);
+       noise->destroy(noise);
+}
+END_TEST
+
+START_TEST(test_qske_newhope_noise_poly)
+{
+       qske_newhope_noise_t *noise;
+       uint8_t seed_buf[seed_len];
+       uint32_t *poly;
+       int i;
+       chunk_t seed = { seed_buf, seed_len };
+
+       memset(seed_buf, 0x00, seed_len - 1);
+       seed_buf[seed_len - 1] = noises[_i].key;
+
+       noise = qske_newhope_noise_create(seed);
+       ck_assert(noise != NULL);
+       poly = noise->get_binomial_words(noise, noises[_i].nonce, n, q);
+       ck_assert(poly != NULL);
+       for (i = 0; i < n; i++)
+       {
+               ck_assert(poly[i] == noises[_i].poly[i]);
+       }
+       free(poly);
+       noise->destroy(noise);
+}
+END_TEST
+
+static size_t seed_lengths[] = { 0, 1, 31, 33 };
+
+START_TEST(test_qske_newhope_noise_fail)
+{
+       qske_newhope_noise_t *noise;
+       chunk_t seed;
+
+       seed = chunk_alloc(seed_lengths[_i]);
+       memset(seed.ptr, 0x00, seed.len);
+
+       noise = qske_newhope_noise_create(seed);
+       ck_assert(noise == NULL);
+       chunk_free(&seed);
+}
+END_TEST
+
+Suite *qske_newhope_noise_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("qske_newhope_noise");
+
+       tc = tcase_create("noise_uniform");
+       tcase_add_loop_test(tc, test_qske_newhope_noise_uniform, 0, countof(noises));
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("noise_poly");
+       tcase_add_loop_test(tc, test_qske_newhope_noise_poly, 0, countof(noises));
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("noise_fail");
+       tcase_add_loop_test(tc, test_qske_newhope_noise_fail, 0, countof(seed_lengths));
+       suite_add_tcase(s, tc);
+
+       return s;
+}
diff --git a/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_reconciliation.c b/src/libstrongswan/plugins/qske_newhope/tests/suites/test_qske_newhope_reconciliation.c
new file mode 100644 (file)
index 0000000..94e7c60
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <qske_newhope_reconciliation.h>
+
+#include <library.h>
+
+static const uint16_t n = 1024;
+static const uint16_t q = 12289;
+
+static uint32_t r_v[] = {
+        7832,  2714,  1942, 12135,  6869, 11272, 11601,  1783,  9639,  1465,
+        4603,  8158,  1418,  6162,  3907,  6653,  1091,  3026,  4540,  4797,
+        2751,    29,   768,  5580,  1304,  5262,  1644, 11294, 12257, 10466,
+         170,  8458,  7185,  6850,  8790, 11277, 10980,  5507, 10693,  9766,
+        7230,  3980,   796, 11125,  8042,  9022, 10207,  7577,  5041,   192,
+       10308,  7905,  8520,  3814,  3372, 11772, 11290,   418,  2744,  4782,
+        3072, 10921, 10721,  6100,  1021,  7943,  7426,  2142,  6618,   757,
+        5033,  9336,  9332,  3410,  6613, 11776,  1525,  9567,  5371,  1290,
+        3685, 11054, 11228, 10703,    70, 11215,  8992,  2855,  2962, 10104,
+       10083,  8146,  7599,  3428,  4316, 10056,  1245,  9776,  7867,  1381,
+        6540, 11273,  6626,  3708,  5348,  4521,  3760,  1771, 12037,  2681,
+        3044, 10226,  5133,  5013,  7851,  7187,  1965,  6776,   223,  3003,
+        4800, 10128,  9592,  8917, 10664,  7076,  2081,  5621,  2694,  8245,
+       10979,   929, 10593, 10429,  6890,  6222,  5891,  6633, 12124,  1508,
+         508,  9650,  2480, 10302,  3958,  4519,  5309,  8675,  6963,  5281,
+        8265,  4851,  7173,  2537,  1176,   259,  6422,  6782,  1429,  7231,
+        4948,  8137, 11341, 12090,  5395,  8087,  3098,  6724,  7462,  9973,
+         149,  7331,   562,  9753,  1227,   768,  7520, 12107,  6199,  6503,
+        9876,   306,  3876,  1903,  6306, 10288, 10184,  9401,    68,  5246,
+         630, 10136,   133, 12082,   648,  8537,  3896,  4482, 12011,  5407,
+        5305,  4301,  6551,   714,  5902, 11915,  3121,  5428,  5441,  5140,
+       10139,  2091,   875,  9478, 11576,  8663, 10514,  1018,  8780,  6445,
+        2501,  4204,  1276,  7474, 10594,  3808,  4367, 11469,  4875,  1899,
+        9136,  1507,  6235,  6367,  3851,  7341,  9925,  4629,  9588,  3150,
+        4739,  6109,  4850,  9944, 11565,  4995,  8383,  9623,  6248,  3020,
+        1730,  3368,  3431,  8617,  6478,  7182,  8720,  1927,  6493,  9285,
+        9779,  2800,  3730,  1754,  3772,  3124,  7569, 10008,  9240,  2493,
+        4402,  5851,  2050,  8630,  5054,  8421,  1536,  7671,  5467,  9075,
+        5881,  4355,  4554, 11354,  4048, 10335, 11033,  4252,  2558,  4363,
+       10448,   327,  1675,  4755,  8227,  7705,   398, 10398,  9913,  4129,
+        6571, 10743,   280,  6634,   796,  7264,  3916, 11349,  1415,  1187,
+         692,  9980,  1647,  4267,  1001, 12229,  6040,   268,  1308,   531,
+        3141,  7209,  1941,  4684, 10261,  1415,  8381,  4919, 11450,  1494,
+        8237, 11023,  3380,  4448, 10101,  9232, 11040,  7799,  4958,   741,
+        2234, 10436, 11442,  5073,  2908,  2355,    31,  7222,  5457,  3746,
+        8920,   122,  8960,  5708,  1750, 11161,  4847,  3199,  7954,  2151,
+        9419, 11678,  8997, 12016,  9690,  9605, 10718,  3735,  1617,  9574,
+       10384, 11604,  9311,   687,  7145, 11891,  6529,  5052,  1342,  8735,
+        7644,  6062,  6338,  8563,  2502,  5284,   220,  5224,  3771, 11067,
+       11609,  2972,  3799,  2566,  7488,  6369,  7704,  6095,  3598, 12112,
+        8545,  2026,   746,  3206,  2814,  8740,  1491,  5950,  8413,  4043,
+       12036,  6082,  4131,  1941,  6942,  9396, 11267,  8912,  7344, 10371,
+        9205,  9520, 12038,  4345,  8024, 10999,  8408,  4673,  6682,  8893,
+        8668, 10099,  7658, 11896,  4276,  2042, 10707,  9793,  3152, 11961,
+        3269,  5512,  5736,  5938,  9457, 10439, 10777,  6656,  3174,  9043,
+        6046,  2519, 11912,  5244,  6214,  2071, 11317,  5285,   891,  6184,
+        3819,  1563,  1474,   654,  5147,  2380, 10760,  4816,  3378,  1414,
+        7784, 10067,  1809,  6320,  4789,  9359,  2747,  9424,  9074,  9473,
+        3300,  6244,   104,  7612,  1105,  4276,   573,  1988,   923, 12047,
+        7948,  4860,  3949,  4971,  6956,  2831,  2034,   289, 10946,  6970,
+        3191,  5122,  2175,  1300,  6198,   256,  6433, 11646,  9119,  9723,
+        1046,  5967,  1124,  6449,  2817,   692,  4649,  3089,  5050, 11261,
+        2220,  3052, 12012, 10110,  1394,  2877, 10089, 11696,  4462,  5504,
+          66,  2500,  5384,  7461,  5712,  8649,  9536,  7670,  2385,  3469,
+         782,  2876,  7772,  6118,   142,  5396, 10951, 10556,  3450, 10602,
+        1604,  7909,  3323,    39, 10258,  2262,  7113, 11313, 10203, 10846,
+        9275,  4316,   965,  6006,  4458,  7926,  3171,  1797,  4659,  5336,
+        5543,   250,  9230, 10720, 11970,  4511,  4311, 11763,  1283,  4044,
+        2643,  3744,  4490,  5984,  8868,  8760, 11738,  6037,  9164,  7601,
+        7544, 11117,  7322,  2081,  4034, 10791, 11491,  7027,  1615,  5338,
+        8528,  3424,  2126,   927,  1650,  6068,  3812, 10958,  7574, 11032,
+        6954,  6132,  2598,  9458, 11346,  1974,  3273,  1040, 10331,  8587,
+       11017,  6864,  8246,  5328, 11330,  6779,  8761,  4342,  4595,  8610,
+         161,  4622,  6411, 10708,  7896, 11431, 12097,  9500,  3376,  9561,
+       10730,  2248,  3069,  1434,  8838,   566,  6397,  5881,  4956,  4203,
+        8362,  6047,  3484,  4784,  9901,  8989,   862,  8817, 12186,  9876,
+        9748,  1905,  5696,  9028,  5721,  2940, 10235,  2326,  2134,  6167,
+        1019, 10851,  1253,  5588,  9149,  6532,  3959, 11598,  4068,  3299,
+        8264,  9787,  7089,  2829,  6755,  6156,   455,  5900,  2839,  5921,
+        2140,  7428,  2688, 11175,  9247,  6727, 11711,  1762,  6244,  3336,
+        2308,  9922,  7883,  7007, 10890,  7013,  8452,  2743,  1482,  6927,
+        7846,  6128,  5114,  4868,  7487,  4584,  6785,   460,  6747,  8894,
+        9855, 12242,  3365,  1450,  6614,  3974,  5200,  3247,  2779,  8695,
+         828, 10940,  2304,   376,  3027,  3898, 10351,  1879, 10262,  2512,
+        5487,  4280, 10297,  8480,  9481,  7905,   197,  8361,  4927,   705,
+        9671,  6722,  2589,  8772,  1078,   333,  8696,  6267,  7420,  4471,
+        8994,  5038,  5318,  1846,  2574,  8779, 10724,   825,  7399,  7073,
+        4422,  8385,  5171,  8849, 11344, 10735,  8483,  2241, 11738,  6581,
+       10699,  2777,  6531,  4678,  7608, 10871,  3501,  9239,  7252, 11828,
+        7873,  9606,  4526,  5958,  8505, 11233,  9638,  2421,  5652,  3095,
+        9049, 11347,  6274,  1405, 11114, 11208,  5703, 10774,  3011, 11633,
+        5741,  9601,  5507,  4527,  3501,  5707,  8698,   178, 12091,   325,
+        6056,   635,  3772, 12169, 10509,  6528,  3573,  3675,  3389,  3161,
+        1148,  2687,  3509,  6639, 10452, 11804,  5355,  1085,  9580,  7106,
+        1396,  8279,  4881,  3402,  7803,  8801,  6142,  7623,  4386,  9291,
+        1502,   500, 11809,  6655,  2674, 10061,  1650,  5422,  8936, 10011,
+        1193,  9619,  1435,  8285,  4038,  9984,  9732,  4477,  1251,  7106,
+        7817, 10062,  3378,  5608,  2395,  2563,  1957,  3768,  4160,  7267,
+       11631,  2171,  4771,  6927,  4330, 10482,  6204, 11022,  7895,  1924,
+        3648,  1991,  6628, 10136,  2916,  5416,  7827,  1479,  2312,  9991,
+        7915,  5431, 10911, 10979,  4527,   436, 10521,  5725,  2201, 10198,
+         662,  1691,  8867, 10008,  9359,  5291,   567,  5725, 10329,  4772,
+        2813,  7323,  5646,  1861,  9922,  1831,  9356,  1219,  4107,  9999,
+        4569,  9092,   833,  1602,  4258,  1443,  1484,  4036,  5415,  3767,
+        9992,   412,  9343,  2251, 10513,  9067,  1494, 11893,   744,  1978,
+       11259,  3614,  7459,  5254,  4232,  5148,  4119, 11550,  6425,  4933,
+        4292, 10521,  9657,  9632,  4613,  7738,  5561,  8806,  3501,  3731,
+       11329,  2693, 11581,  6393, 10176, 10773,  1790,  1809,  9186, 12085,
+        5418,  7223,  1077,  1527, 10917,  4236,  7668, 11754,  6655,  7696,
+        1809, 11512,  3618,  5857,  7512,  1044,  7970,  6825,  4897,  2870,
+         126,  8619, 10445,  3883,  4238,  4051,   399,  1580,  9893, 11046,
+        2955,  6520,  5435,  1891,  1254, 12135,  4122, 10512, 11960,  6196,
+        3443, 10118,  1689, 10877
+};
+
+static uint32_t i_v[] = {
+        8355,  2010,  1416, 12110,  6361, 11296, 11668,  1446,  9822,   947,
+        5422,  8211,  1824,  6158,  3458,  6435,   685,  2707,  4804,  4929,
+        3204, 12158,   674,  5703,  1125,  5085,  1358, 10956, 12216, 11164,
+       12112,  8359,  7018,  7038,  9099, 11789, 10574,  5991, 10736,  9335,
+        7898,  4429,   587, 11156,  7912,  9063,  9673,  6792,  5530,   648,
+       10203,  7284,  7935,  4177,  3514, 11488, 10998, 12254,  2913,  4827,
+        2446, 10965, 10718,  5569,  1023,  8150,  7440,  1928,  6384,   802,
+        4726,  9738, 10374,  3842,  6761, 11788,  1133,  9413,  5818,  1099,
+        3710, 11315, 11667, 10285, 12431, 11195,  9193,  2842,  2267,  9902,
+       10076,  7409,  6751,  3748,  4487,  9961,  1547, 10060,  7443,  1276,
+        6827, 10798,  6323,  4038,  5508,  4006,  3300,  1774,   255,  2688,
+        3238, 10275,  4911,  5648,  7842,  7506,  1769,  6425,   195,  3176,
+        4455, 10337,  9451,  8912, 10445,  7646,  2837,  5109,  3033,  8668,
+       10295,   744, 10869, 10204,  6825,  6326,  6299,  7208, 11886,  1246,
+         704,  9626,  2538, 10932,  3903,  4545,  5111,  9006,  6698,  5008,
+        8464,  4679,  7230,  2223,   707,   705,  6592,  6207,  1114,  7645,
+        5374,  7595, 11064,   746,  5585,  8248,  2921,  7004,  6595,  9985,
+         506,  7147,   793,  9605,   596,   962,  8223, 11771,  6438,  6663,
+        9519, 12013,  4302,  2216,  6633, 10351, 10096,  9645,   347,  4601,
+         596, 10448, 12051, 12376,  1544,  8939,  5114,  4052, 11408,  5947,
+        5368,  4270,  6747,   423,  6283, 11211,  2574,  5974,  5533,  5143,
+        9757,  2155,   729,  9776, 11989,  8808, 11057,  1519,  9187,  5996,
+        2966,  3865,  1409,  8023, 10648,  4397,  5082, 10832,  4769,  2068,
+        9226,  1790,  5911,  6534,  3780,  7312,  9388,  5014,  9054,  3445,
+        4659,  6203,  5234,  9490, 11060,  4214,  8978,  9789,  6201,  3088,
+        1988,  3057,  3762,  8725,  7322,  7583,  8233,  1394,  6534,  9221,
+        9736,  2738,  3837,  2595,  4012,  3674,  7505, 10231,  8080,  2402,
+        3977,  5928,  1942,  8421,  5507,  8422,  1238,  6909,  5800,  9613,
+        6083,  4382,  4669, 11670,  4032, 10762, 11623,  4387,  3728,  4656,
+        9701,   722,  1255,  4495,  8158,  7762,   792, 10307,  9813,  3904,
+        6081, 11003, 12045,  6718,  1089,  7327,  4381, 11188,   943,  1740,
+         563, 10251,   756,  5027,   848,   325,  6547, 12288,  1222, 12189,
+        3641,  7314,  2049,  5254, 10043,  1068,  7906,  4741, 11639,  1981,
+        7660, 10911,  2746,  4536, 10068,  9700, 11057,  8114,  5556,   253,
+        2292, 10686, 11848,  5306,  3092,  2570, 12167,  7101,  5245,  3463,
+        8627, 12513,  9010,  5356,  1633, 10462,  4545,  3614,  7245,  1887,
+        9738, 11902,  8716, 12035,  9958,  9421, 11063,  3759,   883,  9754,
+       10730, 11706,  9132,   540,  6726, 11382,  7038,  4407,  1225,  8606,
+        7689,  5894,  6553,  7908,  2454,  4939,   613,  5811,  3580, 11792,
+       11364,  3153,  3698,  2604,  7470,  6053,  7699,  6018,  4289, 11497,
+        8580,  2249,   718,  2444,  2972,  8812,  1710,  6317,  8718,  4194,
+       12288,  5837,  3698,  2216,  7402,  9045, 11194,  8500,  7238, 10686,
+        9409,  9867, 12264,  3859,  7673, 11659,  8496,  4618,  6465,  8811,
+        9114, 10740,  7738, 11850,  4142,  2493, 11136,  9623,  3071, 11701,
+        2925,  5043,  6151,  6221,  9642, 10846, 11145,  6315,  3741,  9123,
+        5131,  2585, 11337,  4786,  5844,  1485, 11505,  5205,   797,  5955,
+        3717,  1756,  1551,  1122,  5057,  2585, 10857,  5129,  3557,  1254,
+        7750,  9688,  2462,  6415,  4345,  9460,  2957,  8793,  9210,  9242,
+        3487,  6506, 11888,  7563,  1078,  4486,   406,  2261,   867, 11965,
+        7979,  4533,  3654,  4747,  6636,  3166,  2114,   380,  9715,  7132,
+        2982,  5024,  1817,  1231,  6210, 12377,  6280, 10882,  9937,  9587,
+         633,  5668,   899,  6176,  2431,   956,  5022,  3094,  4658, 11168,
+        2989,  2654, 11990, 10494,  1691,  3017, 10044, 11882,  4020,  5342,
+       11911,  2426,  5748,  7592,  6340,  9214,  9357,  7169,  2109,  3210,
+         415,  3024,  7791,  5684,   246,  5134, 11335, 10092,  3133, 10427,
+        1502,  7739,  3272,   169,  9521,  2550,  7327, 11309, 10815, 10146,
+        9157,  4579,  1022,  6447,  4233,  8488,  2958,  1715,  4215,  4965,
+        5728,   551,  8942, 10845, 11881,  4472,  4331,   304,  1183,  3798,
+        1968,  3993,  4889,  6145,  8841,  8816, 11283,  6578,  9212,  8161,
+        7003, 11574,  7764,  1678,  4138, 10444, 11880,  7101,  1390,  4743,
+        8320,  3026,  2338,  1203,  1562,  6502,  3103, 10770,  7608, 11097,
+        6745,  6037,  2926,  9489, 10782,  1853,  3482,   524, 11063,  8299,
+       11092,  6838,  7779,  4598, 11245,  7274,  8908,  3886,  4440,  8651,
+       11949,  5344,  6954, 11015,  8333, 11347, 12677,  8716,  3514,  9892,
+       10366,  2029,  2875,  1540,  9013,   250,  6393,  5618,  4565,  3687,
+        8340,  6420,  3632,  5032,  9408,  9738,   961,  8653, 12315, 10459,
+        9883,  2074,  5357,  9341,  4850,  2514,  9746,  2605,  2394,  5928,
+         808, 10443,  1589,  5673,  9176,  6593,  3404, 12254,  4230,  3630,
+        7958, 10065,  7471,  2432,  6626,  6517,   382,  6131,  2888,  5440,
+        1571,  7341,  2841, 11202,  9462,  7180, 11206,  1433,  6183,  3882,
+        2105,  9906,  8076,  7074, 10572,  7262,  8456,  2979,  1095,  6891,
+        8025,  5914,  5380,  4300,  7363,  4989,  6788,  1043,  6836,  8710,
+       10099, 12310,  3997,  2102,  7002,  4041,  4948,  2601,  2958,  8665,
+         984, 10820,  1940,   541,  3377,  3533,  9357,  2049, 10721,  2732,
+        5355,  4280, 10281,  8056,  9557,  7749,   611,  8255,  4854,   708,
+        9199,  7033,  2582,  8343,   820,   944,  8651,  5547,  7052,  4723,
+        8972,  5594,  5314,  1938,  2539,  8789, 10341, 12368,  7475,  6903,
+        4436,  8346,  5391,  8336, 10864, 10397,  8517,  2078, 12127,  6612,
+       10511,  2970,  6576,  5166,  7744, 10934,  3186,  9515,  6831, 12085,
+        7284,  9791,  4755,  6341,  8713, 11526,  9392,  2122,  5743,  2776,
+        9581, 11396,  7006,  1465, 11235, 10997,  5776, 10401,  2929, 11732,
+        5847,  9512,  6068,  3934,  3730,  5813,  9195,   410, 11698,   896,
+        6321,  1310,  3478, 11649, 10201,  6850,  3612,  3451,  3569,  3266,
+         747,  3151,  3352,  6497, 10445, 11501,  5306,  1026,  9712,  7294,
+         813,  8005,  5090,  2905,  7903,  8358,  6290,  7756,  3955,  9471,
+        1858,   699, 11847,  7292,  2165, 10556,  1038,  5289,  8693,  9698,
+        1702, 10228,  1412,  8681,  3330, 10042,  8888,  4257,  1201,  7422,
+        7956, 10019,  3011,  5956,  2188,  2407,  1986,  3847,  4345,  7427,
+       12091,  1763,  3885,  6731,  4172, 10828,  6129, 10972,  7878,  2189,
+        3988,  2125,  6536, 10663,  3100,  5129,  7656,  1053,  2303, 10149,
+        8087,  5666, 11151, 10962,  4905,   779, 10113,  5451,  1509,  9590,
+         735,  1626,  8419, 10607,  9293,  5778,   907,  5527, 10408,  5454,
+        2266,  7131,  6332,  2055, 10105,  1188,  9842,  2059,  4417, 10026,
+        4339,  9779,   680,  1731,  4958,  1589,  1866,  3797,  5058,  3735,
+        9899,   543,  9330,  2436, 10757,  9010,  1270, 12232,  1122,  2222,
+       10945,  3733,  7454,  5251,  4185,  5118,  4331, 12022,  5900,  4767,
+        4393, 10252,  9957,  9653,  4674,  7705,  5694,  9123,  3882,  3137,
+       11627,  2712, 11985,  6346,  9990, 10760,  1869,  1778,  8899, 12168,
+        5207,  7250,  1088,  1131, 11567,  4337,  8286, 11660,  7152,  8010,
+        2286, 11335,  2984,  5740,  7114,   806,  7579,  7119,  5122,  2917,
+         541,  7913, 10555,  3684,  4720,  3954,   517,  1526,  9712, 10854,
+        1921,  6897,  4704,  2141,  1602, 11880,  4548, 10569, 11521,  6408,
+        3609,  9752,  1960, 10934
+};
+
+static uint8_t rbits[] = {
+       0x3f, 0xff, 0xaf, 0x0f, 0x6b, 0xb2, 0xb8, 0x46, 0x53, 0x44,
+       0x95, 0x98, 0x0a, 0x85, 0x0c, 0xfc, 0xc4, 0x86, 0xcc, 0x69,
+       0xc6, 0xd9, 0xfa, 0xee, 0x19, 0xa6, 0x34, 0x0f, 0x35, 0xc4,
+       0xdc, 0x08
+};
+
+static uint8_t r_ref[] = {
+       0, 3, 3, 1, 1, 1, 0, 1, 0, 3, 2, 0, 1, 1, 3, 0, 2, 1, 0, 3,
+       2, 1, 2, 3, 3, 0, 2, 0, 1, 3, 3, 2, 3, 3, 0, 3, 0, 2, 2, 0,
+       1, 1, 2, 0, 1, 1, 2, 1, 3, 0, 0, 3, 1, 1, 0, 0, 0, 2, 0, 1,
+       0, 2, 3, 1, 3, 0, 3, 1, 0, 0, 2, 1, 3, 3, 1, 3, 2, 1, 0, 2,
+       0, 0, 3, 3, 0, 1, 2, 2, 0, 1, 0, 3, 2, 2, 1, 1, 3, 0, 3, 3,
+       2, 2, 0, 2, 1, 0, 0, 0, 3, 0, 3, 1, 2, 1, 1, 0, 3, 3, 2, 1,
+       3, 3, 2, 2, 1, 3, 0, 0, 2, 2, 3, 1, 1, 2, 2, 2, 0, 2, 0, 2,
+       0, 0, 1, 2, 2, 2, 3, 1, 2, 0, 3, 0, 1, 3, 2, 3, 3, 1, 1, 2,
+       0, 0, 2, 1, 2, 2, 0, 2, 2, 2, 2, 1, 1, 3, 1, 3, 3, 1, 2, 2,
+       3, 0, 1, 0, 0, 2, 2, 1, 3, 2, 2, 2, 3, 1, 1, 0, 0, 3, 2, 3,
+       0, 0, 3, 3, 2, 2, 2, 2, 1, 1, 0, 1, 2, 1, 3, 2, 0, 3, 0, 2,
+       3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 1, 0, 2, 3, 2, 1, 2, 0, 3, 0,
+       2, 2, 1, 1, 2, 1, 2, 0, 1, 2, 1, 3, 0, 0, 2, 3, 0, 3, 1, 0,
+       2, 2, 2, 1, 2, 0, 3, 1, 0, 0, 3, 0, 2, 3, 1, 0, 2, 3, 3, 0,
+       0, 0, 3, 0, 2, 3, 2, 0, 2, 2, 1, 0, 1, 2, 1, 3, 3, 3, 1, 2,
+       1, 2, 3, 1, 1, 2, 2, 0, 3, 0, 3, 3, 1, 3, 3, 3, 1, 3, 0, 3,
+       0, 0, 1, 2, 1, 0, 3, 0, 0, 2, 1, 3, 3, 3, 1, 1, 2, 3, 1, 0,
+       1, 1, 3, 3, 0, 3, 1, 3, 1, 2, 2, 2, 1, 3, 1, 2, 1, 3, 0, 1,
+       2, 2, 2, 3, 3, 2, 2, 3, 1, 2, 2, 1, 2, 1, 0, 0, 0, 1, 3, 2,
+       0, 3, 1, 1, 2, 1, 3, 2, 3, 2, 0, 1, 0, 1, 3, 0, 2, 3, 1, 3,
+       0, 1, 1, 3, 1, 1, 1, 0, 2, 3, 2, 1, 2, 0, 3, 3, 2, 0, 1, 0,
+       3, 3, 3, 1, 2, 2, 1, 0, 3, 3, 0, 2, 3, 1, 1, 1, 3, 3, 1, 3,
+       3, 0, 1, 0, 2, 0, 1, 1, 0, 0, 3, 2, 2, 3, 0, 2, 2, 0, 1, 1,
+       1, 3, 1, 1, 1, 0, 1, 2, 3, 2, 2, 3, 1, 1, 3, 3, 3, 1, 2, 0,
+       0, 0, 2, 2, 2, 3, 2, 0, 0, 1, 3, 0, 0, 0, 2, 0, 1, 0, 3, 0,
+       3, 1, 0, 1, 1, 1, 2, 2, 2, 0, 0, 2, 2, 0, 3, 1, 0, 2, 2, 0,
+       2, 0, 0, 1, 1, 0, 1, 2, 3, 2, 3, 2, 3, 3, 3, 0, 2, 1, 2, 2,
+       1, 0, 1, 1, 1, 2, 1, 3, 2, 0, 3, 3, 0, 0, 1, 1, 1, 2, 2, 2,
+       0, 1, 1, 2, 0, 2, 0, 1, 2, 0, 1, 3, 2, 2, 3, 0, 0, 1, 1, 2,
+       3, 1, 2, 0, 3, 0, 2, 1, 0, 0, 0, 1, 1, 1, 1, 3, 0, 0, 0, 3,
+       2, 3, 2, 1, 0, 3, 1, 1, 1, 1, 3, 0, 0, 1, 1, 1, 0, 3, 2, 2,
+       3, 1, 1, 3, 0, 1, 1, 3, 0, 3, 2, 2, 0, 3, 1, 3, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 3, 2, 2, 0, 1, 3, 0, 1, 3, 3, 2, 1, 3, 1, 1,
+       3, 3, 2, 1, 1, 3, 1, 0, 2, 1, 1, 3, 3, 3, 1, 3, 1, 3, 0, 1,
+       2, 2, 0, 3, 3, 2, 1, 1, 1, 3, 0, 2, 0, 3, 3, 1, 2, 3, 1, 3,
+       0, 0, 0, 1, 3, 3, 0, 2, 3, 0, 1, 3, 0, 0, 3, 0, 2, 2, 3, 3,
+       3, 3, 2, 1, 0, 3, 1, 1, 1, 2, 2, 0, 3, 2, 0, 2, 2, 3, 1, 0,
+       3, 3, 1, 2, 3, 0, 1, 1, 0, 3, 3, 1, 1, 3, 0, 2, 1, 2, 2, 2,
+       2, 3, 2, 3, 0, 0, 3, 1, 1, 0, 3, 2, 3, 2, 3, 3, 2, 2, 3, 1,
+       3, 2, 1, 0, 1, 0, 2, 2, 1, 3, 1, 2, 3, 3, 1, 3, 2, 1, 3, 2,
+       2, 3, 1, 1, 3, 3, 3, 3, 2, 0, 0, 3, 3, 3, 2, 3, 2, 0, 3, 0,
+       3, 1, 2, 0, 3, 0, 2, 2, 2, 3, 1, 2, 2, 1, 3, 3, 0, 1, 3, 0,
+       0, 1, 3, 2, 1, 1, 0, 1, 3, 3, 1, 1, 0, 1, 2, 2, 2, 0, 2, 3,
+       1, 2, 1, 1, 3, 2, 3, 3, 1, 0, 1, 3, 2, 3, 2, 2, 1, 2, 3, 1,
+       3, 2, 3, 1, 3, 3, 0, 3, 1, 1, 3, 2, 1, 2, 2, 0, 1, 1, 2, 3,
+       1, 3, 0, 0, 3, 0, 3, 0, 1, 2, 0, 2, 2, 3, 2, 0, 0, 0, 3, 0,
+       2, 0, 0, 2, 2, 2, 3, 1, 3, 2, 3, 2, 0, 1, 2, 1, 1, 3, 0, 3,
+       2, 0, 2, 2, 3, 2, 1, 0, 1, 1, 0, 2, 0, 3, 2, 0, 2, 3, 1, 3,
+       2, 2, 2, 2, 3, 1, 0, 2, 3, 3, 3, 2, 0, 0, 3, 3, 1, 2, 2, 3,
+       0, 1, 1, 1, 3, 2, 1, 0, 0, 1, 2, 3, 3, 0, 1, 1, 1, 1, 0, 1,
+       0, 2, 3, 3, 3, 3, 0, 2, 3, 0, 1, 0, 0, 1, 1, 3, 2, 2, 0, 0,
+       2, 2, 1, 3
+};
+
+static chunk_t shared_secret = chunk_from_chars(
+       0x14, 0x22, 0x06, 0xe3, 0x48, 0xf3, 0xfa, 0xfc, 0x21, 0x0d,
+       0x5d, 0x51, 0x19, 0x7f, 0x16, 0x4e, 0xe6, 0xd3, 0x10, 0xa9,
+       0xf5, 0xab, 0xfc, 0x96, 0x11, 0x1b, 0xc3, 0x4a, 0x89, 0xf9,
+       0x66, 0x55
+);
+
+START_TEST(test_qske_newhope_rec_good)
+{
+       qske_newhope_reconciliation_t *rec;
+       chunk_t i_shared_secret, r_shared_secret;
+       uint8_t *r;
+
+       rec = qske_newhope_reconciliation_create(n, q);
+       ck_assert(rec != NULL);
+
+       r = rec->help_reconcile(rec, r_v, rbits);
+       ck_assert(memeq(r, r_ref, n));
+
+       r_shared_secret = rec->reconcile(rec, r_v, r);
+       ck_assert(chunk_equals(r_shared_secret, shared_secret));
+
+       i_shared_secret = rec->reconcile(rec, i_v, r);
+       ck_assert(chunk_equals(i_shared_secret, shared_secret));
+
+       /* cleanup */
+       rec->destroy(rec);
+       chunk_free(&i_shared_secret);
+       chunk_free(&r_shared_secret);
+       free(r);
+}
+END_TEST
+
+Suite *qske_newhope_reconciliation_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("qske_newhope_reconciliation");
+
+       tc = tcase_create("rec_good");
+       tcase_add_test(tc, test_qske_newhope_rec_good);
+       suite_add_tcase(s, tc);
+
+       return s;
+}