/*
 * Test code for Falcon implementation.
 *
 * ==========================(LICENSE BEGIN)============================
 *
 * Copyright (c) 2017-2019  Falcon Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * ===========================(LICENSE END)=============================
 *
 * @author   Thomas Pornin <thomas.pornin@nccgroup.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>

#include "inner.h"
#include "falcon.h"

/*
 * If using ChaCha20 during keygen, then we don't generate the same
 * outputs from the same seeds, and we don't faithfully reproduce the
 * NIST test vectors (implementation is still safe, but the tests would
 * fail).
 */
#if FALCON_KG_CHACHA20
#define DO_NIST_TESTS   0
#else
#define DO_NIST_TESTS   1
#endif

static void *
xmalloc(size_t len)
{
	void *buf;

	if (len == 0) {
		return NULL;
	}
	buf = malloc(len);
	if (buf == NULL) {
		fprintf(stderr, "memory allocation error\n");
		exit(EXIT_FAILURE);
	}
	return buf;
}

static void
xfree(void *buf)
{
	if (buf != NULL) {
		free(buf);
	}
}

static size_t
hextobin(uint8_t *buf, size_t max_len, const char *src)
{
	size_t u;
	int acc, z;

	u = 0;
	acc = 0;
	z = 0;
	for (;;) {
		int c;

		c = *src ++;
		if (c == 0) {
			if (z) {
				fprintf(stderr, "Lone hex nibble\n");
				exit(EXIT_FAILURE);
			}
			return u;
		}
		if (c >= '0' && c <= '9') {
			c -= '0';
		} else if (c >= 'A' && c <= 'F') {
			c -= 'A' - 10;
		} else if (c >= 'a' && c <= 'f') {
			c -= 'a' - 10;
		} else if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
			continue;
		} else {
			fprintf(stderr, "Not an hex digit: U+%04X\n",
				(unsigned)c);
			exit(EXIT_FAILURE);
		}
		if (z) {
			if (u >= max_len) {
				fprintf(stderr,
					"Hex string too long for buffer\n");
				exit(EXIT_FAILURE);
			}
			buf[u ++] = (unsigned char)((acc << 4) + c);
		} else {
			acc = c;
		}
		z = !z;
	}
}

static void
check_eq(const void *a, const void *b, size_t len, const char *banner)
{
	size_t u;

	if (memcmp(a, b, len) == 0) {
		return;
	}
	fprintf(stderr, "%s: wrong value:\n", banner);
	fprintf(stderr, "a: ");
	for (u = 0; u < len; u ++) {
		fprintf(stderr, "%02x", ((const unsigned char *)a)[u]);
	}
	fprintf(stderr, "\n");
	fprintf(stderr, "b: ");
	for (u = 0; u < len; u ++) {
		fprintf(stderr, "%02x", ((const unsigned char *)b)[u]);
	}
	fprintf(stderr, "\n");
	exit(EXIT_FAILURE);
}

/*
 * tmp[] must have length at least ilen + 2*olen.
 */
static void
test_SHAKE256_KAT(const char *hexsrc, const char *hexout,
	uint8_t *tmp, size_t tlen)
{
	uint8_t *in, *out, *ref;
	size_t ilen, olen;
	inner_shake256_context sc;
	size_t u;

	in = tmp;
	ilen = hextobin(in, tlen, hexsrc);
	ref = in + ilen;
	olen = hextobin(ref, tlen - ilen, hexout);
	out = ref + olen;
	if (tlen < ilen + 2 * olen) {
		fprintf(stderr, "Temporary buffer too short\n");
		exit(EXIT_FAILURE);
	}

	memset(out, 0, olen);
	inner_shake256_init(&sc);
	inner_shake256_inject(&sc, in, ilen);
	inner_shake256_flip(&sc);
	inner_shake256_extract(&sc, out, olen);
	check_eq(ref, out, olen, "SHAKE KAT 1");

	memset(out, 0, olen);
	inner_shake256_init(&sc);
	for (u = 0; u < ilen; u ++) {
		inner_shake256_inject(&sc, in + u, 1);
	}
	inner_shake256_flip(&sc);
	for (u = 0; u < olen; u ++) {
		inner_shake256_extract(&sc, out + u, 1);
	}
	check_eq(ref, out, olen, "SHAKE KAT 2");
}

static void
test_SHAKE256(void)
{
	uint8_t *tmp;
	size_t tlen;

	printf("Test SHAKE256: ");
	fflush(stdout);
	tlen = 1000;
	tmp = xmalloc(tlen);
	test_SHAKE256_KAT("", "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be", tmp, tlen);
	test_SHAKE256_KAT("dc5a100fa16df1583c79722a0d72833d3bf22c109b8889dbd35213c6bfce205813edae3242695cfd9f59b9a1c203c1b72ef1a5423147cb990b5316a85266675894e2644c3f9578cebe451a09e58c53788fe77a9e850943f8a275f830354b0593a762bac55e984db3e0661eca3cb83f67a6fb348e6177f7dee2df40c4322602f094953905681be3954fe44c4c902c8f6bba565a788b38f13411ba76ce0f9f6756a2a2687424c5435a51e62df7a8934b6e141f74c6ccf539e3782d22b5955d3baf1ab2cf7b5c3f74ec2f9447344e937957fd7f0bdfec56d5d25f61cde18c0986e244ecf780d6307e313117256948d4230ebb9ea62bb302cfe80d7dfebabc4a51d7687967ed5b416a139e974c005fff507a96", "2bac5716803a9cda8f9e84365ab0a681327b5ba34fdedfb1c12e6e807f45284b", tmp, tlen);
	test_SHAKE256_KAT("8d8001e2c096f1b88e7c9224a086efd4797fbf74a8033a2d422a2b6b8f6747e4", "2e975f6a8a14f0704d51b13667d8195c219f71e6345696c49fa4b9d08e9225d3d39393425152c97e71dd24601c11abcfa0f12f53c680bd3ae757b8134a9c10d429615869217fdd5885c4db174985703a6d6de94a667eac3023443a8337ae1bc601b76d7d38ec3c34463105f0d3949d78e562a039e4469548b609395de5a4fd43c46ca9fd6ee29ada5efc07d84d553249450dab4a49c483ded250c9338f85cd937ae66bb436f3b4026e859fda1ca571432f3bfc09e7c03ca4d183b741111ca0483d0edabc03feb23b17ee48e844ba2408d9dcfd0139d2e8c7310125aee801c61ab7900d1efc47c078281766f361c5e6111346235e1dc38325666c", tmp, tlen);
	xfree(tmp);
	printf("done.\n");
	fflush(stdout);
}

static const int8_t ntru_f_16[] = {
	7, -7, 12, 18, 19, 6, 18, -18, 18, -17, -14, 51, 24, -17, 2, 31
};

static const int8_t ntru_g_16[] = {
	-2, -35, 3, 28, -21, 10, 4, 20, 15, -28, 31, -26, 5, 33, 0, 5
};

static const int8_t ntru_F_16[] = {
	16, 65, -6, 15, 26, -10, 14, -9, 22, 48, 26, -14, 15, 21, -23, 4
};

static const int8_t ntru_G_16[] = {
	37, -57, 27, 31, -45, -49, -11, 46, -14, 26, 0, 3, -33, -33, -3, 54
};

static const uint16_t ntru_h_16[] = {
	7768, 1837, 4498, 1226, 9594, 8992, 2227, 6132,
	2850, 7612, 4314, 3834, 2585, 3954, 6198,  589
};

static const char *ntru_pkey_16 = "04796072d46484ca95ea32022cd7f42c89dbc4368efa2864f7260d824d";

static const int8_t ntru_f_512[] = {
	4, -4, 0, -6, 6, -6, 2, 1, -8, 0, -2, 0, -1, -1, -4, 8, -5, 3,
	-2, 2, 0, -5, -2, -1, 3, -4, -5, -1, 8, 1, 1, 7, 5, 1, 6, 2, -1,
	-13, 1, -4, 9, -4, -2, 4, -4, 0, -1, -1, -3, 2, 1, 1, 1, 3, -3,
	2, -1, -1, -5, 9, 4, -7, -3, -8, -3, -2, -3, -6, -6, -3, -2, -2,
	2, 1, -10, -2, -2, 4, 2, 0, -2, -2, 4, -3, 5, 2, -2, 3, 8, 1, 8,
	-3, -4, 2, 7, -5, -4, -2, -2, -3, 5, -5, 0, -3, -5, 3, -6, -2,
	3, 0, 3, 1, 2, -2, 1, 6, -1, -7, 0, -5, 3, -5, 9, 0, 1, 5, -4,
	0, 5, -1, 4, 3, 5, -6, 2, 0, -7, 1, 0, 0, 2, 4, 1, -7, -3, 4, 4,
	-2, -7, -5, 6, 3, 2, -5, 6, -1, -1, -4, 1, 2, 1, 2, -10, -9, -9,
	-1, 3, -2, -2, -6, 1, -2, -4, -1, 2, 3, 8, 2, 1, -1, 8, 0, 7, 3,
	1, 5, 0, -7, 1, -6, -4, 4, 2, 0, 0, -3, 2, 0, -3, 0, 7, -1, -1,
	-7, 2, 5, 3, 0, 1, 6, -2, -1, 2, 0, -1, -3, -6, -5, -5, -4, 0,
	1, 7, 1, -3, 2, 2, -5, 0, -4, 3, -4, 5, 3, 4, 7, -2, 15, -3, 1,
	1, 4, 5, -9, -3, 4, 2, -4, -4, -3, -1, -4, 3, -1, 1, -8, -4, -1,
	0, -3, 1, -1, 3, 3, 3, -3, -6, -7, 7, 0, -6, 2, -1, 4, 7, 1, 4,
	0, 1, 6, -1, -2, -2, 5, 0, 6, -3, -2, -5, 3, -1, 0, 5, -2, 8,
	-5, -4, 1, -3, 8, 2, -4, 1, 6, 0, 0, -1, 0, -4, -5, -2, 3, -2,
	5, 1, 4, 5, -4, 4, -1, 4, -5, -2, 1, 3, -5, 1, 2, -2, 0, -5, 1,
	8, -3, -4, 3, -2, -3, -4, 4, 3, -2, 6, -3, -2, 4, 0, -2, 0, -5,
	1, -9, 5, 6, -2, -6, 1, 5, -1, -7, 1, 2, 5, 2, 0, -1, 0, -2, -4,
	-1, -8, 5, -5, 9, -4, -4, 2, -5, -1, 0, 1, 4, 3, 1, -2, -7, -8,
	-4, -4, 4, 3, -1, 4, -1, -1, 1, 0, 6, 1, 0, -6, -2, 0, -3, 0,
	-1, -1, 0, 3, -5, -2, -5, 6, 2, -4, -3, 4, -8, 1, -1, 4, -3, 5,
	-2, 8, 7, -1, -3, -3, -2, 0, -4, 4, 0, -6, -4, -2, 5, 8, -3, 3,
	-1, 0, -5, -5, 0, 2, -5, -2, -3, 1, 6, 3, 1, -3, 4, -3, 0, -7,
	-1, -3, 1, -5, 1, -4, -2, 2, 4, 0, 1, 5, 2, 2, -3, -5, -8, 4,
	-2, -3, 2, 2, 0, 8, -5, 2, -7, 0, 3, -1, 0, 4, -3, 1, -2, -4,
	-6, -5, 0, -4, 1, -3, 9, 1, -3, -2, -3, 5, -1, -4, -7, 1, 1
};

static const int8_t ntru_g_512[] = {
	-6, -2, 4, -8, -4, 2, 3, 4, 1, -1, 3, 0, 2, 3, -3, 1, -7, -5, 3,
	-3, -1, 3, -3, 8, -6, -6, 0, 6, 4, 7, 3, 5, 0, -5, -3, -5, 7, 3,
	-1, -4, 3, 4, -1, 1, 3, -3, -4, -4, 4, -5, -1, 3, 7, -2, -4, -2,
	-3, -1, -2, -1, -2, -6, -7, -3, -6, -3, -6, 4, -1, -5, 1, 4, -4,
	3, -1, -6, 6, -2, 2, -6, 5, -7, 8, -3, 0, -2, 0, 7, 1, 3, 6, 4,
	-5, 2, 2, 2, 4, -4, -5, -4, -3, 4, -7, 7, -6, -2, -7, 1, -2, -2,
	-3, 1, 3, 7, 0, -1, -5, 4, -8, -8, 0, 3, 6, -3, 2, 6, -1, 1, -5,
	-4, 2, -3, 8, -2, 2, 3, 0, 1, 6, 4, 4, -4, -1, -3, -2, -5, 3, 9,
	0, 4, -1, 1, -4, 0, 3, 0, -2, 8, 0, 1, 0, -1, 1, 9, -1, -4, -1,
	3, 5, -2, -2, 1, -1, 1, -1, 0, 1, 0, -6, -2, 0, 7, -3, -4, -1,
	-6, -2, 5, -2, 0, 4, -3, -5, 0, 1, -1, -3, 5, 5, -4, -4, -5, -1,
	9, -1, -5, -7, -1, -2, 4, 2, 5, -4, -1, -5, 8, -3, -6, -2, 1,
	-2, 1, 1, 4, -4, -1, 4, 1, 1, 0, -5, 1, 7, 2, -3, 3, -2, -4, 1,
	-6, -1, -3, 7, 6, 0, -2, 2, -6, -4, -3, 2, -7, 7, 0, -11, -1, 3,
	4, 0, 6, -8, -4, -1, 1, 0, -3, 7, 0, 0, -2, -1, -4, 0, -1, -3,
	7, -6, -2, -2, -1, 0, -2, 8, -6, 4, 4, 6, -2, -1, 0, -13, 1, 2,
	0, 5, -7, 3, -2, -6, -3, -4, 4, -1, 1, 3, -6, 1, -5, -8, 2, -11,
	-1, 2, -2, 0, 0, 1, 1, -4, -5, 0, 1, 0, 1, -6, -2, 2, 0, 7, 1,
	-1, 1, -2, 1, -3, 1, 2, 1, -7, -2, 2, -1, 4, 1, -2, -2, 0, 4,
	-3, -6, 2, 3, 1, 1, -4, 6, -2, -4, -3, 0, 4, -5, 0, 1, 8, 2, 2,
	-1, 1, -2, -4, -1, 4, 4, -1, 7, 2, -1, -3, -8, 3, 1, 1, 0, -1,
	1, -7, -8, 2, 1, -2, 1, 0, 4, 1, 1, -2, -1, -5, 3, -4, -1, -1,
	-8, 2, -4, 3, 2, -5, 0, 1, 5, 2, -5, -2, 3, 7, 5, 6, 5, -2, 1,
	3, -7, 7, -3, -8, -2, 2, 3, 3, 5, -2, -4, -1, 7, -2, 7, -3, -2,
	0, 3, 5, 0, 0, 4, 8, -1, -5, 3, -2, -2, -5, -5, -2, 2, 5, -8,
	-1, -2, -4, 6, 0, 6, -5, -1, -5, -6, 9, 5, -2, 4, -1, -8, -2,
	-2, 1, -8, -5, 6, -1, 0, 5, -6, -3, -3, -2, -6, -2, 0, -1, -3,
	7, -3, -1, 3, 6, 3, -2, -4, 2, 1, -1, 11, 3, 4, -1, -6, 1, 2, 3,
	3
};

static const int8_t ntru_F_512[] = {
	-3, -27, 4, 18, 39, 7, 20, -13, 33, -29, 3, 38, 30, 26, -6, 24,
	-26, 16, 24, -48, -18, -21, 3, -14, -2, 6, -9, 42, 22, 21, 33,
	-27, -14, -14, -56, -68, -2, -33, 6, -38, -43, 21, 13, 6, 2,
	-69, -10, -30, -27, 23, -1, 41, -21, 11, -20, 15, 39, 5, 41, 15,
	-28, -34, 9, -11, 9, -1, -8, 61, 8, 13, -23, 2, 7, -23, -21,
	-54, -11, -9, -19, 40, 37, -2, -16, 19, -16, 2, -78, -35, -19,
	11, 17, -46, -16, 25, 0, 22, 13, -15, -33, 13, -15, -34, 33,
	-13, 38, 39, 37, -29, 40, 7, 63, 35, 15, 21, -24, 16, -6, 30,
	12, 18, 61, 17, -11, -15, 11, 0, -15, -2, -14, -26, -1, -42,
	-10, -52, 64, 45, 22, 6, -22, 32, -50, -16, -12, -16, -8, 34,
	-17, -18, 7, 19, 37, 41, -5, -22, -12, -7, -17, -27, -17, 4, 36,
	0, 22, -4, -50, 24, 30, 5, 1, -50, 43, 0, 0, -6, -9, 34, 0, 14,
	-27, 17, 35, -30, -13, 3, -23, -46, 17, -34, 30, 24, 47, 31, -7,
	11, 10, 16, 30, 27, -4, 11, -4, -14, -28, 49, 0, 27, -5, -10,
	53, -50, -13, -15, 13, -10, -26, 2, -3, 88, 22, -27, 40, -23, 3,
	-42, 2, -27, -12, 35, 26, -33, 38, -42, -5, 17, -24, 6, -10, 13,
	-10, -30, -35, -17, 25, 49, -29, 48, 19, 37, 48, -25, -31, -41,
	-15, -1, 19, -17, -7, -16, 2, 5, 12, 0, -15, -19, -6, -32, -4,
	-56, 14, -6, -7, 17, 24, -1, 17, -35, 5, 3, -64, -15, 4, 0, -31,
	4, -10, -18, 55, 13, -13, 23, -30, -11, -29, -21, 15, -18, 30,
	39, 16, -27, 31, 4, 31, 39, -49, 11, -25, 37, -42, -72, 28, -57,
	13, 34, 6, 10, -17, -3, -19, -43, -1, -32, 9, -11, 9, 11, -23,
	6, 28, -34, -12, -42, -7, 42, -18, -2, 22, -30, -4, -42, 10, 54,
	-16, 19, -23, -4, 18, -58, 26, -3, -38, 20, 38, 23, 20, 0, 10,
	49, 47, 18, 27, -11, -10, -14, 0, 6, 6, -18, -6, 14, -38, -16,
	12, -17, 17, -21, -52, -3, -53, 9, 9, -4, 44, 9, -4, 17, 2, 10,
	-28, -13, 28, -12, 11, -33, -2, 33, 0, -51, 2, -33, 20, -47, 23,
	42, 2, 52, -18, -17, 35, 6, 27, 3, 11, 24, -8, 0, -35, -44, -22,
	-49, 61, 3, -15, -2, -14, 46, -24, -10, -24, -24, -21, -10, -51,
	-3, 31, 20, 1, -44, 18, 9, 38, 26, -17, -8, 2, 33, 24, -8, -9,
	-20, 32, 54, 47, -11, 40, 3, -58, 13, 17, 29, -21, 27, 4, -31,
	14, 14, 17, 19, -29, 19, -86, -29, -15, -35, 18, 53, -10, 9, 13,
	-38, 9, -4, 80, 0, 6, 1, 15, -14, 0, -5, 45, 26, 50, 28, 21, 1,
	-8, -6, 12, 32, 5, -21, -1, 54, 14, 22, 27, 6, 8, -18, 33, -5
};

static const int8_t ntru_G_512[] = {
	-58, -47, 36, 14, 2, -20, 24, 35, 38, -31, 20, -1, -17, -29, -6,
	25, 16, 4, -75, 32, 20, 17, -8, 24, 13, 7, -11, -2, 3, -2, 6,
	16, 22, 37, -25, -4, -32, -21, 57, 0, 20, 73, 20, -9, 6, -49,
	12, 14, 60, 15, 50, 15, 9, -2, 13, -8, 38, 12, -5, 9, -7, -1,
	-30, -2, -28, -6, 6, -18, 5, 1, -15, -15, -1, 15, -4, -12, -1,
	-37, -12, 33, -2, -17, -8, -57, -64, -7, 3, 3, -15, 1, 3, 15,
	-21, 67, -29, -4, 7, -21, -7, -8, 12, 38, 3, 45, -26, -37, 10,
	24, -15, -24, 23, -13, -27, 12, 14, -16, 22, -19, 15, 1, -7, 0,
	-6, 28, 2, -7, 0, -10, -19, 14, -13, -16, 22, 14, -7, -1, -17,
	31, -7, 12, 4, -8, -13, 18, -8, -38, 6, 49, 40, 1, -5, 1, 17,
	-21, -3, -9, 15, 27, 43, 60, 29, -1, -3, 2, -41, 18, -18, -26,
	29, 13, 12, 15, 38, -24, -25, 8, 17, 10, -32, -3, -39, -29, 23,
	30, 6, 3, 23, -15, -26, 34, -59, 3, -54, 37, 27, -26, 23, -40,
	-10, -15, 7, 9, -1, 24, -33, -36, 29, -7, 13, 29, 56, -13, 36,
	-37, -45, 13, -11, 43, -9, 24, 16, -13, 13, 13, 10, -18, 16, 3,
	-14, -27, -16, -5, -35, -25, -42, 51, -5, -41, 20, -27, 47, 14,
	75, 14, -74, 26, -18, 18, -12, -13, 8, -44, 6, 0, -16, 36, 32,
	-33, 6, 5, -23, -14, -32, 15, 27, 56, 10, -43, 8, 16, -63, 8,
	34, -24, -3, 15, 13, -3, -31, -14, -24, 28, 11, -41, -4, 14, 1,
	-11, 40, 32, -22, 19, -16, 27, -2, 36, 40, -11, -2, 2, -11, -2,
	35, -44, 6, 6, -40, 3, -8, -27, -28, 5, -6, -12, -2, -4, -19,
	-64, 36, -33, -16, -5, 20, -9, 10, 59, 16, -8, 27, 28, -6, 10,
	-8, 11, -35, 23, 35, 34, 47, 13, 2, 44, 8, 38, 4, 34, 41, 15,
	20, 28, 29, 35, 4, 23, 7, 8, -19, -17, 8, 5, 10, -21, -9, 15,
	-28, -4, -23, -17, 18, -15, -2, 9, -24, -7, 7, 51, -31, 40, -57,
	30, 23, -12, -18, -9, 37, -29, -4, 18, -10, 20, -54, -21, 23,
	56, 28, 30, -3, 15, -31, -41, 14, 66, 41, 15, 39, 34, -9, 4, 33,
	18, 25, 6, 38, -27, 63, -21, -24, 43, 11, -37, 16, 26, -31, -30,
	16, -20, -3, 10, 11, -58, 18, 13, 0, 22, -25, 13, -32, -14, 5,
	52, 31, 30, -3, 9, 18, -7, 4, -2, 1, 11, -8, 8, -9, -29, 28,
	-25, 51, 47, 24, -72, -4, 41, -15, 17, 50, 2, -1, 2, -41, -33,
	-20, 6, -19, -33, 23, 8, -19, 12, -19, -2, -61, -7, -19, 6, 8,
	-23, 27, 38, 12, -17, 39, 8, 23, -41, 14, 25, 16, -44, -46, 11,
	31, -6, 9, 24, 23, 37, -57, 22, 21, -22, 21, 44
};

static const uint16_t ntru_h_512[] = {
	3605, 11394, 3623, 9500, 11987, 4336, 3361, 1348, 6563, 8102,
	758, 8455, 5789, 7614, 797, 11215, 7518, 3116, 4556, 1762,
	11267, 9507, 4586, 5420, 4091, 6788, 1729, 6433, 4730, 1830,
	4200, 1416, 3705, 5380, 5767, 9261, 924, 6822, 8978, 2536, 8232,
	10530, 10137, 11653, 11704, 1887, 11653, 10218, 9207, 10699,
	3288, 1478, 7261, 10152, 3871, 10134, 7359, 9993, 9510, 8661,
	419, 1826, 978, 11037, 10899, 3311, 2064, 5939, 11072, 1748,
	9516, 5458, 7665, 4459, 5937, 5615, 7288, 3438, 6009, 3217, 264,
	3696, 608, 11576, 2774, 10976, 11146, 11188, 3237, 10913, 3541,
	11755, 9412, 5720, 4226, 1154, 9010, 9922, 3994, 11252, 11575,
	11077, 9308, 7784, 11086, 12047, 5310, 8524, 4117, 504, 3145,
	12216, 2718, 1181, 5446, 1818, 6156, 1945, 11240, 7398, 8307,
	8259, 10113, 11431, 10691, 2147, 2742, 8242, 12031, 8808, 7609,
	3657, 3567, 2485, 7669, 4388, 3255, 1395, 596, 9635, 6739,
	10284, 4910, 9410, 11788, 10978, 3877, 4006, 1860, 6225, 8834,
	11969, 11742, 9733, 8790, 7871, 10347, 2658, 4468, 947, 3384,
	9733, 6496, 382, 81, 7977, 7138, 8962, 10195, 2830, 10227, 5302,
	9974, 9157, 7442, 4931, 9761, 5759, 2115, 431, 12242, 2353,
	7529, 7822, 6343, 3370, 9369, 8491, 6742, 5681, 10973, 412,
	12105, 6913, 5565, 3760, 4378, 4454, 9070, 1289, 2596, 5355,
	12117, 2787, 3798, 4954, 9708, 2191, 2935, 4073, 7455, 11661,
	4170, 8782, 9611, 8647, 2318, 4779, 11339, 3962, 361, 9358,
	7727, 11723, 9018, 10552, 3025, 6852, 6028, 10603, 7147, 8434,
	5604, 4483, 5954, 426, 11403, 2643, 8294, 9504, 7268, 8958,
	2773, 7764, 5926, 8213, 2100, 8814, 7540, 4212, 7012, 353, 7166,
	5717, 9799, 10379, 7768, 9515, 2534, 4504, 5410, 5358, 1879,
	11581, 10692, 2614, 11002, 11667, 7333, 6932, 4254, 9503, 7386,
	2581, 4153, 6079, 6149, 5496, 2397, 11735, 6496, 9250, 11872,
	10842, 2934, 4022, 10681, 914, 4397, 7287, 9673, 4709, 4895,
	3770, 3146, 7254, 4953, 11018, 9062, 3817, 11979, 8723, 3091,
	2675, 8946, 7376, 3652, 6861, 8298, 5547, 11, 4758, 10734, 7434,
	11702, 6466, 9135, 11199, 10059, 503, 2510, 1730, 6101, 11965,
	10264, 6045, 11690, 11530, 761, 9270, 4531, 5482, 6951, 5776,
	10348, 2668, 5246, 8046, 7106, 11302, 3276, 6632, 12008, 6564,
	8465, 1953, 5904, 1036, 3109, 5020, 11945, 458, 11742, 5271,
	4474, 9918, 7963, 11786, 8318, 756, 560, 11377, 1084, 9634,
	9203, 1062, 8461, 1845, 3719, 6672, 6660, 4711, 11337, 10460,
	5367, 4072, 7043, 5567, 6356, 657, 8877, 3633, 11487, 10421,
	10877, 5052, 2174, 4711, 11853, 4461, 10942, 11619, 7591, 3424,
	3372, 4493, 11393, 7115, 9057, 7145, 2060, 9137, 707, 1968,
	7853, 645, 253, 2697, 9294, 8357, 7503, 6187, 7505, 8302, 4635,
	8899, 9258, 8559, 7988, 9571, 243, 6979, 8233, 11555, 5257,
	8361, 1836, 11185, 3771, 3517, 10585, 4756, 10212, 2035, 2778,
	6798, 11229, 11768, 8707, 7931, 3744, 10939, 5317, 6104, 11137,
	3936, 5418, 4368, 201, 3094, 8211, 6803, 2559, 3164, 6846, 8515,
	8894, 8556, 2219, 9593, 6391, 3374, 4868, 192, 2791, 4309, 62,
	20, 9968, 8831, 11185, 1365, 9722, 5623, 2398, 5049, 2241, 6060,
	998, 4233, 1455, 5324, 1053, 5626, 1726, 11569, 12033, 4897,
	859, 1676, 2097, 11147, 5155, 5187, 2026, 12050, 5615, 5450,
	260, 7526, 11923, 6346, 7221, 405, 882, 842, 4621, 4130, 3513,
	114, 3673, 4914
};

static const char *ntru_pkey_512 =
	"093856c82389e51cbb4d0f03484544668dfa60bda1075a75dbe0c76bcf7578c2"
	"c47306e2b00e52347a952c3feda841b0592149e872641a058839e55045a1e42d"
	"0e71aa68c489e880a29229e66d85b6e075fb6167ea8fde9cb33605c671767a83"
	"c7e79672fe709949a1d5068c7220f4ab1daa4ccef2041733ad006d494b155277"
	"c516b5cc55ef71e0d6e5de4c910420e700982d382b5aae0ae2abb43296aa1375"
	"6deb931165842084828cca6c23e6abf4b4deb459171e68ad3af0f52fa14c4054"
	"1f83126fb82a7849d551871a6030799afa1ce681ce0439e06ca7a70c8632ada0"
	"32bbfe26876e4e4937bc9b577d512432dc57309525a3694e82c4cba4c2b832ae"
	"23c94fa61d118518a0aec1b77a6058959ebfa1aca6245d03b334e2605658017e"
	"0145f296f8a3029f4cb0e9fcd4b69bda3c57449343988567f210c1afbf489317"
	"5a5e8e631cd2a926612b6959631ab7419cbd25b0156f4eb044691668db850928"
	"914ebbd54ae33b5935a97b088f2ddcfe9747ed8d412a24e962e1c724392abb12"
	"cf7a05a648e78bedcb8cea9382f45ac45e3296b6fae0f257911835d081aab22c"
	"a53819a52071922fe2b55e545c9a01520d226e75d10746d901616ff9655991e8"
	"8b796252b279919854894ee1d5ed3da710a36abead937295b14427a51f7368a1"
	"540e57bf60155782576dd76582422b982a5a2dd8fb6a6e439244b5c779725265"
	"4c7ceba3129c564d66b0a8d98ee9bb2e213304ca738bc9cd03911acd81a95ab0"
	"02d296a7b9d0ab6d99428ebebbf9d2c1f727386c25f56ebda06179db6aad0a0b"
	"e643646cd56a6c9d690a1b0a6c51f9f6e6f0ac2633319e8bba19a484447a15c4"
	"040c309539cbaa41cab77949745ea6be7c6ee0a81f82f408c2c7110f25a28fcc"
	"42684347353a1da106811267b1268dc53dcfe86e0d5bf63502918ab4e31b37e8"
	"b5a9f53bc21f9267b93516daafad63769cd6034b118db205bcb8d85be920323b"
	"10b0c7b07ab428503f4a89913a0a5753d82b754606e486e2c390aa16f7cd2563"
	"03cdb4380a6d2352260a91cb2bb13aecdbda5652949f907f32b69a8eaf76df88"
	"80defb3a82abb53157d8ae04f6054a91100324c16804da9327fcc5c6afa1438a"
	"fa16c22ae57963dcd2e4c100c02b9d0d500f80149bc227faec455597e95f7257"
	"93b923057ac0f9908916bd4cc10755fa1afad31bc053210d6c68c20c6b8b508d"
	"4431faaf1257bd54a0411d66ba4d8ca70d41950dc834a483502236e407239653"
	"32";

static const int8_t ntru_f_1024[] = {
	3, 2, -4, -3, 0, -5, 4, -3, -1, 1, -2, 2, 3, 0, -1, 0, 0, 0, 0,
	0, -2, -2, -3, 3, -4, -1, -1, 0, 2, -4, 0, -9, -3, 5, 3, -1, 1,
	-5, 1, -1, -6, 0, -1, -1, 5, -1, 4, -1, -2, 2, -3, -1, 1, -3, 1,
	1, -5, -2, -2, 0, 0, 5, -8, -1, -1, 0, 0, 2, 0, 4, -3, 4, 3, -3,
	-2, 6, -2, -2, 0, 3, 0, 0, -1, -2, 0, 1, -2, -1, 7, 0, -4, 1,
	-1, -2, 2, -1, -5, 5, -1, -4, -2, -1, 2, -1, 2, -1, -3, 3, 1, 2,
	1, -2, 3, 3, 1, 4, 2, 0, 3, 0, -3, 0, 7, -5, 4, -3, -1, 1, -6,
	0, -1, 0, -5, 1, -2, 2, -1, -1, -2, 3, 4, -1, 0, -1, 0, 1, 3,
	-2, 6, 4, 1, 1, 1, -1, 3, 1, -3, 0, 0, -1, 2, -3, 2, -4, 1, -1,
	-1, 1, -2, -1, -2, -6, -8, -3, 3, -2, 0, 3, -1, 1, 0, 5, -2, 0,
	-2, 1, 2, 1, -2, -5, -3, -2, 2, -1, 1, 1, 0, 1, 1, -9, 0, 1, -2,
	2, 5, 0, 3, 4, -1, -5, -2, -2, 0, 2, 0, -2, 3, 0, -1, -2, -3,
	-6, -2, 1, -7, -4, -2, 1, -1, -1, -3, -3, 2, -3, 2, 1, 2, -4,
	-2, 5, -1, 1, -2, 3, -5, 5, 1, 1, 1, 2, -4, 1, 2, -3, -5, -4, 2,
	-3, 3, -4, -4, 5, 2, 0, -4, 3, -3, -3, 3, 0, -2, -3, -2, 0, -3,
	5, 8, -2, 2, 2, -1, 10, -1, -1, 1, -4, 3, -1, 3, 1, -1, 3, -3,
	5, 0, 4, -3, 4, -5, 3, -3, -1, -4, 3, 1, 0, 2, -1, -4, -1, 4,
	-5, -6, 3, 5, 4, -2, 0, 5, 1, 1, -1, 1, -3, 6, -3, -3, 1, -6, 3,
	-3, 3, 1, 0, 0, -2, -4, -1, 1, 0, -1, -1, 4, -3, 2, 2, -5, 4, 3,
	-3, -2, -1, 1, 1, -3, 4, 6, 0, 4, -3, -1, 1, 6, 2, 3, -2, -3,
	-2, 3, -5, 3, 0, 0, -2, -1, -3, 2, 5, 0, 4, 2, 3, -2, -4, 3, 1,
	-5, -2, 2, -1, -1, -4, 5, 0, 0, 2, -2, -4, 3, 4, 1, 5, 0, 0, 1,
	0, 5, -2, -1, 1, -3, -1, -1, -1, 2, 2, -3, 0, 1, -3, 2, 0, -2,
	3, 2, 0, 3, -1, 0, 2, -4, 0, -3, 3, 3, -1, -1, -2, 3, 2, -1, -5,
	1, 2, 3, 3, 3, -2, 8, 6, -2, 1, 4, -3, 0, 4, 1, 1, 0, 0, 1, 0,
	-1, 5, 0, -5, 4, 3, 5, 2, 0, 0, 3, -2, 3, -4, 2, -3, -1, 3, -2,
	1, -1, 5, 1, 0, 5, -1, 0, -1, -2, -1, -4, -1, -2, 2, -6, -2, 5,
	0, -5, -2, 4, -1, -3, -3, -2, 2, -1, -2, 0, 0, -4, 2, -5, 1, -4,
	-1, 0, -1, -2, 5, -4, 4, -1, -2, 6, 3, 6, 3, -3, 1, 0, 1, 6, 3,
	1, -3, -1, -2, -1, 0, 0, -1, -1, -1, -2, -2, -1, -1, 2, 1, -4,
	-4, -5, -4, 3, 1, 1, 1, 4, -2, 0, 1, 2, 3, 0, 5, -5, 3, -1, 3,
	4, -3, -3, -4, -10, -1, -2, 2, -2, -3, 1, 2, 0, 1, 0, 2, -3, 2,
	1, 1, 0, -2, 1, 0, -3, -1, 0, -3, -1, -4, -5, 3, 3, -1, -5, -1,
	0, -1, 2, -3, 3, 1, 0, 0, -1, 2, 0, 6, -4, 5, -1, 1, 3, -2, -1,
	1, 0, 1, 2, -7, 2, 4, 2, 1, -3, -6, 2, -2, 0, 0, -2, 2, 2, 0,
	-2, 1, 0, 1, 0, 1, 2, -3, 2, 3, 1, 1, 2, 7, 0, 1, 0, 0, -1, 2,
	1, -1, -1, 0, 0, 3, 2, 1, 1, 0, -5, 5, 0, 3, 3, 5, 3, -3, 0, 3,
	1, 4, 0, 6, -1, 3, 4, -1, 5, 5, 4, -4, -2, 2, 3, -10, -3, 1, 1,
	4, 2, -3, 4, 2, -2, -4, -2, -4, 1, 0, 0, 2, -3, 1, -1, -4, 0,
	-1, 4, 1, -3, 0, -1, 1, 3, 2, 3, 1, 2, -3, -3, 0, 2, 4, 0, 0, 6,
	-2, -1, -2, -2, 4, -1, -1, -1, -2, -4, -6, 2, 1, 1, -6, -2, -2,
	1, 0, -3, -3, -3, 3, 3, -1, 1, -3, -1, -1, 1, -6, -1, 2, -1, -4,
	0, 0, -4, 2, 3, 0, -4, -1, 0, 2, 0, -1, 1, 3, 3, -1, -2, 5, 0,
	-1, 1, 0, 2, -5, -1, 0, 1, -5, -4, -4, 0, 1, 4, -6, -3, 1, 0, 2,
	-5, -1, 0, 1, -5, 1, 1, 0, 1, -1, 3, 4, 3, -1, -1, 1, 1, 0, -2,
	0, -1, -4, 0, 2, 1, 2, 4, 2, -1, -4, 2, 2, -1, 0, -1, 0, 0, -2,
	3, 0, -1, -4, 0, -2, -2, -2, 4, 3, 5, 4, 1, 4, -2, 3, 0, -4, -2,
	-3, 2, 2, 0, -6, 2, -7, -1, 3, 1, -2, 4, -2, 0, 1, 2, 4, 0, 1,
	1, 0, 0, 0, 1, 4, -10, -2, -3, -4, 7, -6, -2, -3, 4, 4, -4, -2,
	6, 2, -4, -1, 1, 1, 3, 0, 1, 0, -2, -4, 1, 4, 1, -5, 1, 1, 6,
	-3, 0, 1, -2, -4, 0, -1, -3, 2, 6, 5, 1, -1, 3, 1, 1, 1, -1, 4,
	-5, -3, -1, -2, -3, 0, 2, 2, 2, 2, -6, 7, 7, -1, 3, -1, -2, -2,
	5, 0, 1, 1, -3, 3, -6, 2, 1, 3, 3, 1, -1, 0, 2, 1, -5, -1, -4,
	1, -2, 5, -3, -2, 0, 3, 0, 1, -1, -1, 1, 0, 3, -1, 3, -1, 1, 2,
	0, -4, 2, -1, -3, -2, 0, -3, -2, 0, 1, 0, -5, -2, 4, 1, 7, -5,
	1, 1
};

static const int8_t ntru_g_1024[] = {
	3, -1, -7, -1, 4, -2, 3, -1, -3, -3, -5, 3, -1, -1, 2, -3, -5,
	0, 0, 1, -3, 3, 3, -2, -2, 0, -4, 2, 1, -1, 3, -5, 5, 0, -1, -3,
	-1, -2, 5, 3, 4, -2, -2, 0, -4, 0, 3, 3, 0, 1, 3, -1, -2, -3,
	-1, -2, 3, 1, 0, -2, 0, -2, 0, 0, 1, 3, -2, -3, 3, -3, -1, -2,
	-1, -3, -3, 1, 1, 8, 1, 4, -2, -1, -5, -4, 3, 5, 0, 0, 7, 4, 1,
	1, -4, -2, 4, 4, -3, -4, 5, 3, 2, 0, 1, -6, 2, -1, -3, -1, -1,
	1, 2, 5, 0, 3, 1, 3, 0, -4, -3, -3, -1, -1, 1, 1, 2, 0, -2, 0,
	3, 3, 3, -4, 1, -2, -4, 3, 3, 5, -4, -5, -1, -1, 3, -2, -4, -1,
	-5, 1, -1, 0, 2, -1, 1, 1, -3, -2, -1, -4, -4, -1, -1, 0, -1,
	-1, 3, -2, -2, 3, -6, 2, 2, 0, 2, -3, 0, 3, -2, -2, 2, -1, 1, 4,
	-2, 0, 0, 0, 0, 4, 0, 2, -4, -1, 5, -2, -6, 2, 1, 3, 1, 3, 0, 3,
	1, 2, 0, -4, -2, -3, 4, 2, 0, -8, -2, 2, 5, 2, 0, 1, -2, 0, -1,
	0, 3, 3, 1, 0, 0, 2, 2, -1, -3, 3, -2, 3, 1, -2, 5, 1, 4, -2, 3,
	-2, -3, -2, -1, 2, -5, -4, -2, -3, -6, -3, -2, -3, -3, -3, -1,
	1, -1, 4, -1, -5, -3, 0, 3, 6, 0, 2, -1, 5, -1, 0, 2, 7, 6, -1,
	2, -2, 4, 6, 0, 1, 4, 4, 0, 5, 1, -3, 4, 1, 3, 1, -1, -2, -4,
	-1, 0, 0, 3, -6, -1, 2, 4, -3, -1, 0, -3, 2, 1, 2, 4, 1, -1, -2,
	-1, -3, -2, -6, -1, 1, 2, -2, 0, 0, 0, -3, 1, -2, 5, 1, 1, -5,
	-4, 0, 0, -2, 0, 3, 4, 5, 2, -4, 0, -4, 3, -2, 0, -3, -4, -1, 4,
	0, -3, -2, 1, -1, 2, -3, 1, 0, 0, -3, 0, 5, 2, -2, -4, 2, 0, 0,
	-3, 0, -1, -1, -1, -1, 3, 7, -1, -2, -5, 2, 5, 1, 4, 2, -3, 0,
	-5, -4, 1, 0, 1, -3, 4, 2, -5, -1, 2, -4, 0, 1, 0, 1, 0, -1, 0,
	-2, -4, 4, -2, 0, 1, 1, 0, 2, 0, 0, -4, -5, -3, 0, -4, -5, 2, 1,
	0, -3, 4, -1, 3, -4, -5, -1, 4, -1, 0, 1, -4, 5, -1, 5, 1, -1,
	0, -3, -3, 3, -5, -3, 1, -1, 0, 4, -2, 2, 1, -2, -3, -1, -2, -3,
	-3, 1, -2, 8, -2, 0, 3, -2, 3, 3, 3, -2, 4, 0, 2, 3, 1, 3, 0,
	-1, -1, 3, 1, 1, -1, 5, 1, -1, 0, -3, 1, -4, 1, -1, -4, -1, 6,
	-4, 6, -2, 0, -2, 0, 4, -1, 1, 6, 7, 5, -1, 3, 3, 0, -1, 1, -6,
	-1, -4, 4, -1, 3, 4, 3, -3, -1, 2, 0, -3, 2, -1, -2, 1, -3, 0,
	-1, -5, -1, 4, -2, -6, 1, 0, 6, 2, 1, -3, 2, 1, -1, -1, 4, -4,
	-2, -2, 5, 1, 5, -2, -6, 1, 0, 1, 4, 4, -3, -1, -4, 1, 0, -1, 0,
	-3, 4, -2, 4, 3, 1, 4, 6, 2, 1, -1, 1, -5, -2, -3, 2, 0, -1, -1,
	-5, 3, -3, 2, 0, 1, -4, -1, 7, -1, 2, -2, 3, 0, 0, -4, 4, 2, 4,
	1, 1, 2, 3, -2, 3, 1, 0, 0, -4, 0, 2, 1, 1, -1, 4, 4, -4, -3, 5,
	-1, -1, 1, 3, 3, 1, -9, 0, -6, 5, 0, 0, -2, 3, 0, 2, -2, 3, -6,
	1, 1, -1, 3, 1, 2, 0, 3, -1, 0, -2, -3, 7, 1, -3, -1, -2, 3, -3,
	1, 4, 3, -3, -3, -4, -6, -5, -1, 6, -5, 3, 0, -1, 0, 4, -5, -2,
	1, -2, 3, 6, 2, -4, -5, -6, -3, 2, -3, -4, -2, 1, 1, 0, 1, -2,
	2, -2, -1, 1, 2, 2, -4, -3, -1, 0, -1, 2, -4, 1, -1, 0, -3, 1,
	2, -5, 4, 0, -3, 3, 5, 3, -4, -2, 2, 1, 1, -4, -2, 1, -1, 0, 0,
	3, 0, 1, 0, 1, 1, -1, -4, 3, 3, 1, 0, 1, -1, 1, -2, 3, 3, 5, -1,
	3, -3, -1, 1, -2, -1, 0, 1, 1, -2, 0, 3, -1, -3, -2, 1, 1, 2,
	-7, -2, 1, 5, 0, 0, 0, -4, -4, 0, 1, -1, 4, 0, 0, 3, 1, 3, -4,
	7, 4, -4, 0, 5, 4, -3, -1, 0, 0, -3, -4, 3, 0, -1, 2, -2, 0, 6,
	0, -2, 3, 1, 6, 3, -2, 2, 1, -1, -2, -4, -3, -2, -2, 0, 2, 0,
	-4, -3, -1, -3, 1, 0, -6, 2, 0, 4, 4, 1, -2, -1, -3, 3, -4, -4,
	-2, 1, -5, -1, 2, 1, -2, 0, -2, 2, -1, 0, 3, -2, 1, -6, -2, -1,
	0, -2, -2, 1, 0, 4, -1, 8, 3, 0, 1, 5, 1, -3, 0, 2, 1, 1, -1, 4,
	0, 4, 6, -2, 0, 0, -3, 5, -6, -3, 5, 2, -2, 1, -1, 6, 5, -3, -4,
	-3, 2, 3, -5, 2, 2, -2, -4, 6, -4, 2, 0, -4, 5, 2, -1, 1, 0, -2,
	2, 2, 0, -3, 0, -7, 0, -1, 1, 3, 3, 2, -5, -2, 0, 5, -4, 1, 2,
	2, -1, 4, 5, 2, 2, 2, 0, 0, 2, 1, 3, 2, -4, 4, -2, -1, 2, -2, 0,
	3, -2, -1, 6, 1, 3, 0, 4, 0, -2, -1, 1, 0, -3, 3, 2, 3, -1, -3,
	-3, 3, -2, 3, -2, 0, -1, 3, -3, -2, 1, 4, -4, 2, 5, -7, 1, 0,
	-5, 1, 2, -1, 3, -2, 3, -1, -2, 2, 0, 0, 0, -3, -2, 4, 7, 1
};

static const int8_t ntru_F_1024[] = {
	36, -13, 88, 1, 13, -66, 9, -2, -12, 30, 23, -18, -15, 8, -2, 5,
	19, 13, 14, -22, -22, 29, -18, 8, -45, 28, -4, -46, 30, 40, -26,
	-3, -1, -2, -54, 4, 34, -38, -32, 55, -25, -24, 4, -35, -9, 8,
	23, 24, 35, 17, 29, 7, 41, -3, -13, 39, 25, 24, -34, 18, -55,
	22, -61, -23, 18, 3, 1, -3, 32, -20, -2, -63, 19, 21, -13, 3,
	-7, -17, 5, -40, -29, 8, 6, -43, 27, 31, 3, -28, -46, 76, 31,
	-16, -4, 59, 38, -6, -6, -3, 34, -19, -10, -39, -20, -15, -3,
	-11, -41, 9, -90, 21, -26, 24, -2, -18, -36, 18, -2, -4, -18,
	-67, 14, 7, -22, -22, -28, 42, -57, 32, 7, 25, 7, 30, -45, -9,
	-2, 8, 28, -14, 19, -19, -47, 37, -34, 45, -32, -8, -35, 52,
	-31, 35, -14, -10, 36, -65, -16, -21, -5, 4, 21, -61, 22, 13,
	-55, -5, -22, 14, -10, -35, 8, -5, 27, -31, -32, 3, 0, -12, -25,
	27, -5, -22, 3, -6, 0, 21, -5, 45, 36, -42, 16, -2, -9, -16,
	-44, 0, 44, 3, -9, -51, -32, 11, -4, -7, 33, 15, -9, 13, -6, 15,
	15, -30, 10, 14, -8, 27, 20, -3, -10, 22, 14, 7, -15, 31, -17,
	-20, -14, 4, -2, 26, 27, -7, 32, 49, 27, -40, -4, -35, 11, 3,
	17, 35, 11, -14, 35, -6, 7, 10, -38, 12, 43, -42, 44, -20, -3,
	33, 35, 14, 1, 10, -9, -11, -20, 31, 30, -2, -2, -6, 17, -10,
	-10, -10, 49, -23, -18, -3, -1, 12, 19, -44, -21, -13, -19, 25,
	4, -23, -20, 6, -15, -2, 21, 19, -6, -4, 43, -24, 31, 22, -15,
	55, -5, -3, -8, -6, -14, 23, 0, 32, -28, 48, 55, 43, 2, 17, -4,
	56, 58, 32, 3, -6, 43, 11, -3, -9, -26, -17, -6, 23, 29, 30,
	-31, 5, 27, 11, 9, 30, 32, 66, 10, 33, -40, -26, 19, 38, -11, 4,
	12, -57, 30, -14, 29, -5, 12, -9, -17, 20, 40, -1, -19, -5, -16,
	-38, -25, -24, -1, 21, -21, -47, -1, -8, -53, 39, 7, -36, -19,
	4, 0, 2, 16, 6, 20, 8, 8, -7, -42, -1, 4, -17, -7, -10, -24, 0,
	-29, -1, -15, -2, 3, 9, -21, -2, -20, -15, -68, -42, 21, -40,
	-23, -3, -5, -18, -2, -17, -20, 17, 10, 16, -54, 27, 5, -21, 21,
	4, -54, -25, 2, 61, 39, -25, 47, -5, 20, 12, 8, -21, -12, 16,
	-13, 23, -4, -47, -12, -15, 5, 20, -4, -22, 37, -43, -14, -30,
	-21, 15, -24, 1, -13, 25, -3, -8, -4, 9, -13, -1, -14, 39, 19,
	-8, -11, 45, 32, -25, 18, 77, 13, 14, 21, 38, -42, 15, 28, -17,
	6, -2, 17, -36, 21, -33, 13, 12, -6, 36, -5, 9, 7, 1, -17, 30,
	-16, -3, -39, -12, -6, -21, -28, 3, -13, -17, 29, 23, -12, 17,
	35, -18, -10, 1, 26, -33, 69, 57, -12, -15, 43, 18, 27, -31,
	-29, 37, -5, 50, -56, -22, -57, -1, 21, -15, -27, -48, -20, -28,
	-4, -31, -20, 9, 10, 15, 12, -7, -38, 23, 0, 9, 3, 15, 28, 31,
	-8, 4, 19, 3, -7, 30, -14, 27, -7, -25, -20, -10, -20, 27, -6,
	-30, -8, 27, -5, -23, 52, -44, -33, 48, -20, 10, -21, 7, -34,
	-1, 26, 40, -11, 4, 46, -30, -13, -9, 27, 13, -13, 13, -4, 11,
	34, -32, -3, 51, 24, -45, 39, 14, 15, -55, 12, -28, -21, -14, 3,
	-16, -25, -13, 35, 18, -7, -27, 51, -16, 29, -28, 5, 1, -32, 3,
	-25, -7, -15, 33, 8, 37, -20, 26, 25, 12, 13, 15, 8, 4, 11, 8,
	-31, -1, 8, 13, -31, 22, -7, -3, 7, 12, 10, -12, -62, -49, -12,
	-5, -3, -53, -30, -7, -56, 20, 45, 6, -46, -32, -15, -13, 9,
	-18, 11, -5, 12, -6, 10, -62, 8, 11, -18, 27, 16, -5, -6, 4,
	-28, -6, -30, -58, 11, -8, -40, -51, 20, 27, 17, 12, -9, -28,
	-11, -8, -22, -18, -16, -36, 14, 17, -44, 2, 42, 16, -9, -31,
	-16, -3, -14, 41, -22, 16, -1, 32, 12, 4, -36, 18, -41, 13, 31,
	-35, 14, 8, -10, 19, -9, -4, -36, -15, -62, 0, 16, -28, -54, 4,
	20, -9, 14, 18, -26, -30, 19, 10, 10, -5, -10, 7, 23, -7, -31,
	-2, 19, -63, -14, 0, -18, -3, -21, -33, 11, -52, -21, -4, -48,
	-35, -6, -4, -14, -13, -1, 14, -16, -21, 9, -37, -31, -16, 4,
	-17, 2, -4, -17, 2, -51, -16, -16, 3, 59, 13, -16, -30, 17, 9,
	35, -11, -31, 32, -7, -26, 28, 7, 19, 28, -17, -49, -30, -9, 23,
	19, -2, 1, -3, 9, 48, 11, -54, 9, -22, 25, 8, 22, -52, 37, -14,
	-10, -30, 20, 52, 3, 10, 17, 56, 33, -3, 41, 53, 41, 4, -7, -25,
	8, -45, 29, -11, 5, 29, 60, -15, -8, 14, -7, -33, -14, 6, -12,
	-2, -2, -10, -12, -16, -21, 2, 5, -14, 53, 41, 61, 12, 31, 4,
	22, -16, 36, -4, -42, 38, -29, -10, 20, 20, 35, 66, 16, 12, -50,
	-5, 1, -16, 32, 33, 46, -3, 11, 11, -19, 28, 5, 38, 15, -35, -6,
	1, -6, -17, 2, -28, 25, 42, 8, -2, -11, 14, -33, -42, 23, 21,
	-31, 63, -8, 15, 26, -16, 13, -3, 39, -16, 58, -14, -14, -22,
	-30, -26, -51, 4, -9, -18, -5, -56, -48, -60, 10, -52, -28, -6,
	-12, -35, 31, -22, -31, -13, 8, -14, -8, 23, -20, -45, -12, 30,
	8, 7, 9, -12, -13, -2, -29, 18, -1, 30, -17, -26, -41, 58, -66,
	-6, 8, -78, 25, 29, 0, -40, -27, 16, 40, -15, -28, 18, -54, 16,
	-12, 1, -4, 17, -21, 12, 30, -7, 45, -8, -28, 8, -41, -1, 42, 3,
	-6, -47, 22, 44, -78, -45, 41, 12, -30, -23, 13
};

static const int8_t ntru_G_1024[] = {
	56, -4, -28, 13, 4, 26, -14, -10, -21, -32, 21, -21, 0, 59, 26,
	-6, -81, -7, -42, -1, 8, 20, 37, -33, 36, 1, -6, 14, -1, -73,
	15, 18, 7, 34, -45, 7, 19, -30, 8, 8, -56, -13, 7, 20, -20, 14,
	4, 11, -36, 21, 19, -16, -17, 10, -45, -4, -12, 18, -9, 23, 20,
	1, -27, -7, 1, 1, 33, -27, -23, 56, 35, -5, 16, 43, -1, 11, -18,
	5, 59, 14, -39, 11, -34, -59, 6, -18, 43, -25, 22, -7, 9, -28,
	-9, -40, 47, 0, -12, -22, -12, -44, -17, -12, -10, -5, 4, -20,
	-10, 25, 38, 2, 0, -17, 14, -16, 6, 9, 7, -29, 11, 48, 14, 10,
	0, 24, 4, -5, 56, 20, 1, 35, 62, 7, -31, 36, 36, 24, -19, -33,
	19, 9, -13, -16, 2, 1, -29, 3, -3, 42, 8, 27, -19, 51, 16, 14,
	28, -1, 24, 3, 1, 47, -13, -43, 9, 17, 3, 21, 26, -19, -6, 4,
	-36, 7, 26, 19, 40, -44, 27, -20, 9, -1, 19, -1, 0, -51, 5, -5,
	-45, 11, 26, -1, 1, 39, -6, 14, -14, -34, -29, -6, -15, -23, 24,
	-7, 16, -51, 55, -30, 2, 13, 1, -37, 33, -29, 11, 14, -44, 46,
	40, -45, 59, -6, 3, 18, -46, 20, 17, -2, 0, 27, -20, 1, -7, -16,
	-29, 0, -2, -19, 19, -10, 16, -15, -2, 2, -10, 4, 27, -4, 2, 0,
	15, 35, 19, 25, 21, 32, -9, 26, -28, -23, -2, 7, -24, 75, -3, 6,
	21, 45, -8, -12, 21, -12, -29, -7, 34, -13, -22, 28, 32, 20, 18,
	-22, 2, 17, -12, 37, 37, -33, 5, 28, 27, 55, -30, -9, 10, 23,
	12, -9, -26, 30, 5, 2, 24, -37, 9, -25, -50, 33, 3, -21, -38,
	-19, 44, 41, 9, 1, 34, 6, -26, -44, -26, 15, -3, -21, -24, 40,
	-43, 28, 2, -30, -13, -8, -40, 1, 31, -2, -16, -16, -25, 33, 1,
	-23, -51, -40, -37, -12, -38, 78, 15, -31, 32, 41, 26, 26, -25,
	-60, 15, -43, 27, -54, 0, 25, -7, -27, 15, -18, 20, 20, -76, -3,
	35, -39, 20, 28, 21, 10, 6, -41, -29, -31, -55, -41, 0, -8, 4,
	-17, 21, -21, -12, 11, 4, -17, 6, 26, 11, 9, -13, -41, 29, -7,
	-4, 21, 12, 2, -1, -23, 3, -5, 1, 30, -10, 9, 40, -63, -27, 51,
	-29, 4, -1, -7, 30, 30, -21, 32, -17, -51, 28, 34, 22, -5, -5,
	42, 7, -1, -16, -15, -23, 10, -9, -3, 1, 26, -12, 16, 5, 18, 13,
	-1, 28, 8, -52, -42, 12, -3, -28, 30, -3, 11, -14, -3, 34, -75,
	-13, 6, -39, 14, 72, -16, 18, -17, -36, -3, 5, -9, -38, -42, 4,
	7, 3, 74, 2, 9, -23, -32, -43, -59, -15, -4, 31, 12, -16, -24,
	35, -7, 0, -8, -3, -8, 6, 1, -57, 13, -8, 22, 31, 40, -16, 35,
	34, -32, -60, -21, 8, -1, -13, -39, 14, 17, -7, 33, -35, -6,
	-18, 0, 29, -5, -9, 40, -19, -45, 24, -41, -7, 32, 19, 28, 28,
	-17, 10, 18, 6, 29, 1, -1, 17, 28, 18, -22, -16, 20, 51, 8, 2,
	18, 16, -9, 40, -8, -20, -31, 11, -5, 34, -25, -40, -48, -9,
	-36, 4, 17, 15, 8, -18, 27, -24, -25, -13, 22, 21, -21, -25, -2,
	-32, 7, 20, -8, -26, -23, 21, -3, 34, -15, 0, -17, -21, 56, -38,
	-2, 18, -44, -14, 31, -2, -24, 3, -18, 18, 16, -24, -35, -48, 5,
	-36, 28, 15, 13, 32, -14, 14, -38, -9, -62, -11, 6, 6, -26, -46,
	72, -63, -35, 16, -4, -19, 45, -20, -28, 1, 26, 36, -35, 30,
	-13, 39, -29, 16, -30, 14, 5, 4, -11, -6, 22, -9, 5, -9, 14,
	-27, -30, 23, 23, -2, -7, 30, 0, 6, 32, -43, -17, 11, 10, -29,
	-15, 111, 15, 10, 13, 7, 16, -2, 3, -3, -6, 38, -10, -11, 5,
	-34, -2, 14, -32, -21, 4, -5, 0, -8, 27, -50, -7, 23, 8, -17,
	-63, -87, -1, 34, 5, -1, -11, 3, -6, 33, -9, -45, -34, 2, -23,
	46, 43, -11, 12, -21, -7, 17, -48, -42, -3, 7, 2, 24, 8, 71, 6,
	0, 9, -16, 6, 17, 20, -2, 6, -44, -13, 44, 23, 27, 13, 37, -10,
	58, 8, -12, -4, -15, 14, 27, -47, 18, -68, -6, -9, -16, 2, 7,
	-15, -47, 34, 1, -38, -25, -19, 1, -10, 14, 7, 9, -20, -1, -21,
	4, -13, 18, -26, -10, 31, 51, -59, 15, -3, -19, -70, -17, 46,
	-14, 24, 32, 15, 34, -23, -36, -16, -7, -10, 2, 36, 7, -12, -51,
	-25, -8, 23, -18, -17, 7, -48, 9, -26, 44, -25, 44, 32, 28, -10,
	11, 12, -17, 4, 16, 6, -19, 32, 22, -31, 16, 8, 31, -4, 17, -21,
	1, 56, 36, 21, -31, -4, 0, -46, -26, -44, 61, -61, 2, -21, 45,
	15, -14, -35, -13, 5, -38, -10, -19, -7, -7, -33, 33, -11, -12,
	29, 17, -27, -46, -48, -25, -13, 6, 25, -12, -12, -29, -58, -2,
	-29, 5, -11, -15, -19, 32, -58, 14, -35, -3, -20, -16, -32, -24,
	-45, -18, -3, 0, -1, -43, -9, 12, -29, -2, 1, -9, -26, 5, -2, 9,
	-17, 32, 27, -3, -27, 2, -7, -13, 4, 6, 46, 38, 28, -27, -3,
	-19, -38, 64, 13, 9, -16, 35, 46, 8, -80, 15, -16, -19, -26,
	-10, 48, 8, -11, -8, -2, -16, -22, 50, 9, -14, -52, 39, 11, 49,
	2, 5, -11, 13, -4, 10, 11, -23, -23, -10, 14, 31, 42, 18, 0, 49,
	34, 19, -25, 15, -41, 30, 8, 18, 29, -6, 15, -17, 5, 30, 2, -19,
	12, 43, -32, 31, -39, 8, 21, 16, -12, -8, 24, 37, 8, -13, -54,
	0, -44, -12, -26, 31, 5, -22, 51, 11, -7, -22, 27, 17, 12, 20,
	-8, 9, -11, 48, -21, 9, 24, 2, -4
};

static const uint16_t ntru_h_1024[] = {
	6857, 4524, 6980, 4278, 8521, 9214, 399, 11461, 10346, 9318,
	2768, 1272, 396, 5635, 2424, 3623, 2071, 9145, 8766, 3391, 4900,
	10525, 6985, 3336, 5084, 11240, 5203, 4517, 7825, 974, 6450,
	11728, 3727, 1190, 1946, 2049, 10661, 1728, 1985, 8185, 9223,
	9410, 912, 7934, 2032, 377, 5915, 4515, 2076, 4073, 2109, 6749,
	7387, 4215, 11826, 2227, 4483, 10801, 6125, 5658, 4570, 11193,
	3749, 10418, 5800, 7159, 310, 2683, 453, 5616, 5109, 11698,
	1957, 11587, 11845, 11324, 3939, 3660, 6103, 1382, 6149, 6923,
	1333, 7200, 9403, 5990, 10319, 3473, 4771, 3113, 1322, 6743,
	7880, 11899, 3652, 1437, 6650, 8034, 11683, 11315, 2877, 8676,
	9741, 10509, 10783, 10635, 11008, 213, 3492, 8626, 9271, 4771,
	5099, 10209, 6359, 7738, 10860, 5853, 4632, 9862, 5942, 252,
	10959, 11867, 1685, 4189, 5995, 11443, 5328, 10337, 2968, 5209,
	8779, 4330, 7128, 11161, 9016, 12220, 4751, 4429, 7602, 5861,
	7151, 7129, 772, 4128, 8860, 4537, 4010, 1037, 1692, 11048,
	6880, 3575, 11950, 2203, 2670, 3213, 3925, 9414, 6968, 11107,
	11333, 11878, 11390, 3409, 1632, 5743, 11214, 4130, 5383, 10064,
	8173, 11054, 5112, 7029, 2850, 1905, 7673, 3131, 3383, 10728,
	8997, 4775, 6026, 206, 1602, 6698, 84, 8650, 4051, 2857, 1654,
	10234, 3560, 2220, 10072, 4755, 711, 3377, 3830, 1588, 6249,
	9108, 6301, 718, 4896, 4000, 5810, 14, 7962, 11835, 1619, 10486,
	3549, 3698, 4990, 2693, 2161, 7265, 7865, 10853, 5758, 532,
	9771, 9170, 9181, 10730, 943, 12226, 10180, 12238, 7892, 740,
	1961, 2829, 676, 5308, 8939, 9874, 11816, 8850, 2977, 2717, 535,
	11753, 2410, 4915, 8862, 3229, 87, 8181, 6423, 2900, 7322, 2728,
	11030, 9252, 660, 8255, 5084, 9638, 9905, 300, 10871, 8115,
	3921, 10583, 8542, 11888, 8610, 12287, 8303, 4353, 1249, 8437,
	4800, 11879, 11321, 226, 394, 3180, 8426, 8815, 11081, 10343,
	5780, 3187, 8139, 8663, 3271, 8829, 3961, 8000, 10424, 8944,
	8953, 8797, 11506, 9527, 5086, 3654, 2990, 2609, 9285, 10676,
	2126, 8322, 8388, 2907, 1729, 8000, 11960, 10595, 12191, 6735,
	9877, 2994, 5468, 8463, 9718, 2, 1224, 9842, 2220, 7347, 10016,
	5484, 11643, 3603, 4027, 8718, 1504, 5330, 6070, 6726, 10243,
	5581, 11371, 2288, 998, 11901, 9880, 8241, 3448, 10681, 12014,
	564, 4560, 6851, 9235, 5722, 10116, 12008, 702, 9412, 1818,
	2166, 2521, 3449, 9976, 1317, 8202, 2198, 2879, 9909, 8232,
	4358, 9168, 2723, 6954, 7861, 1599, 21, 768, 2337, 8793, 3970,
	3427, 6800, 3319, 10882, 3474, 11336, 6751, 2944, 2916, 2479,
	6692, 10943, 1129, 10958, 9778, 4105, 1160, 1789, 4091, 11799,
	9847, 4003, 7156, 6, 7913, 5539, 930, 5480, 4256, 4410, 11099,
	7276, 858, 2462, 7336, 7936, 10066, 9162, 1859, 4488, 7896,
	9090, 433, 11723, 12017, 2998, 2568, 7557, 3811, 5754, 6153,
	2684, 6011, 745, 3994, 10864, 26, 6792, 4045, 12039, 8465, 9526,
	3324, 4640, 2950, 11189, 11560, 10968, 3467, 9643, 3390, 3105,
	11058, 10171, 7104, 2221, 2882, 10809, 7349, 5094, 2277, 11876,
	5610, 9833, 11556, 9212, 1093, 4875, 1258, 6525, 1379, 6528,
	8903, 6134, 6783, 3749, 7107, 7032, 6685, 5443, 5050, 10430,
	12242, 11782, 9733, 1619, 3481, 11713, 8961, 1719, 6641, 2111,
	578, 6688, 317, 11397, 6930, 6025, 12121, 9635, 11230, 6031,
	4549, 10556, 5810, 915, 9655, 9997, 9300, 11651, 3638, 6822,
	2744, 6442, 11872, 4596, 9029, 6843, 7691, 146, 8712, 5846,
	9537, 2265, 8123, 10530, 3748, 10109, 4081, 8648, 6032, 243,
	5257, 7387, 3266, 11825, 9483, 5681, 8116, 6123, 5512, 1832,
	12174, 6471, 5779, 9994, 5717, 3438, 10887, 7041, 5482, 5776,
	5052, 1277, 113, 1592, 397, 11378, 8540, 5539, 2871, 4794, 3498,
	6522, 9072, 11037, 7679, 7192, 3190, 4453, 10689, 7319, 4307,
	9129, 611, 8733, 7051, 2177, 4032, 400, 8267, 10724, 6343,
	11699, 2709, 2348, 9276, 199, 8140, 1116, 4362, 10542, 7509,
	4463, 3631, 8311, 10476, 4188, 5615, 541, 11358, 10783, 2653,
	5769, 7483, 233, 7151, 7427, 6954, 8993, 8388, 2634, 2867, 8188,
	10115, 9728, 10919, 2716, 2602, 10405, 8148, 7446, 4372, 4018,
	7482, 9473, 6256, 743, 11460, 2574, 10848, 7890, 6186, 277,
	8438, 6377, 9923, 1538, 8021, 1912, 2915, 8575, 7640, 1224,
	6644, 7740, 8476, 7237, 8105, 8741, 8510, 2956, 7727, 5456,
	4878, 6062, 5590, 4643, 2031, 12027, 7298, 11101, 423, 11766,
	6001, 8391, 11344, 7039, 925, 12087, 4715, 7775, 2577, 12100,
	10177, 7515, 8393, 7854, 7358, 2549, 8037, 7490, 9570, 11450,
	7333, 9792, 6517, 6246, 6324, 5652, 4287, 2916, 10244, 6843,
	1032, 10596, 10106, 412, 1649, 796, 787, 9141, 8210, 11119,
	8722, 5557, 8075, 10581, 5333, 646, 11955, 8382, 10460, 249,
	10396, 1425, 10106, 9653, 2083, 9412, 9482, 10358, 5238, 4889,
	10735, 5696, 10184, 10472, 8912, 4715, 4135, 1850, 6734, 788,
	7911, 12091, 5068, 2196, 8528, 1228, 7261, 6719, 5451, 22, 7250,
	5546, 3002, 1364, 3609, 815, 9625, 6174, 11030, 1121, 5227,
	11682, 127, 9743, 2882, 2013, 6410, 3887, 5624, 6044, 6535,
	10445, 11640, 754, 806, 1728, 10444, 3467, 10796, 1342, 560,
	6412, 9877, 4231, 1004, 7563, 6241, 6650, 7678, 9513, 9268,
	5824, 756, 6364, 382, 6099, 11818, 3452, 10664, 9035, 1892,
	3627, 7790, 2766, 4747, 10766, 2582, 8247, 1343, 5404, 8999,
	1306, 2323, 1697, 3027, 3992, 10237, 12264, 2504, 12196, 285,
	3341, 1023, 11597, 65, 3054, 7012, 3354, 3802, 6381, 11090,
	7956, 8016, 5817, 3082, 7822, 10676, 10795, 9182, 3766, 1386,
	7018, 9919, 4122, 4277, 994, 957, 10047, 4963, 6036, 1829, 3699,
	5927, 2986, 11757, 1091, 8586, 4136, 5998, 8614, 738, 7930,
	9614, 1038, 3465, 9461, 8800, 448, 4790, 6902, 557, 2952, 10752,
	10914, 3678, 10642, 6378, 4775, 8587, 424, 160, 4814, 2921,
	4061, 1553, 10018, 3960, 5267, 1357, 11229, 9706, 5480, 3599,
	695, 9316, 12014, 8205, 274, 3219, 7113, 2914, 4379, 2025, 3948,
	10733, 2075, 9903, 6767, 7202, 5303, 10864, 11908, 2946, 1579,
	5946, 11135, 3629, 12006, 1620, 6884, 6120, 9640, 3085, 8987,
	6885, 126, 8477, 119, 7775, 10599, 11996, 1533, 6606, 9624,
	7770, 3292, 11468, 11115, 9034, 44, 1631, 3867, 10484, 8799,
	6863, 10298, 6792, 10913, 1051, 3927, 3297, 5283, 7269, 10315,
	8364, 7328, 2905, 9803, 8593, 1567, 7314, 934, 10166, 7739,
	2512, 8874, 11011, 10479, 7844, 3646, 6388, 7202, 9880, 4708,
	1057, 9014, 11431, 6222, 4398, 2374, 6684, 4743, 7242, 8114,
	8995, 1222, 2096, 5121, 10994, 8697, 10848, 10235, 2380, 8095,
	7857, 6687, 8380, 7399, 3751, 5398, 98, 7175, 3353, 3777, 8408,
	10568, 12088, 5008, 10713, 10027, 3345, 11243, 2602, 2825, 9460,
	2218, 5381, 9106, 12214, 844, 7720, 8328, 3552, 7008, 11397,
	6321, 1422, 2261, 251, 11402, 176, 10570
};

static const char *ntru_pkey_1024 =
	"0a6b251ac6d110b685263fe063ecc5a1aa4662b404f8063160325e0e27205e3b"
	"988f8d3f4c9291d6d24d084f72be8514d1a57a443ce64cadd03a3c4a61e68801"
	"a6946c01f05ff9901e4c20e41efe1fc01795c6d1a32070fe920f5a5d736d077b"
	"8c88b3460ea315fb561a476abb93a968b25aa1bf704d8a7b07155f04fd6db21e"
	"96d43b916c3c3d8ce4c5f5c5666015b0b14d5c2092ed766a13cd914a8cc2914a"
	"9a577b22e7b391059d67e9f62b68ec332cf61e4983690da87e98bac000d53692"
	"1b290dd2a34fae7e1635de3aa9b16dd48626865cd80fcab3ee5b1a5505d5daec"
	"b353428612e61459892d0ea6f62b998ce2fbc4a3d14d76c96e56fbdbd90c1102"
	"08a711b93ea840d1a72b286b80df7bab889b29b8c8d3d564c66ce2b63b116e66"
	"b1f8d51198166faf39022541e7507fb6b2e4fe1b752c8877177e4c3b34de9e88"
	"c952a75e280ce1909a2a01521ca3f4cb2919da7fa37a08ac9d612930b1cd313b"
	"d863461a639462742ce4c80fa05ac800e7c6ae3b194e8f63774e724df8a8521c"
	"5c617ae6a6559f821498ae3d28f769ea0ebefc29f12fce7b502e41ea4b0d0a91"
	"4bc8bae692b8a22922e84a9d085ede925a93338a78c9d015dff5645cb547268a"
	"a8ac5a4240a5203f4f725a69ac412ca9ddfb33d46957857ae70868afff81bd10"
	"113860f54b02e67b0e40e20628c6c83aa26fad268675a50c737f2e1d7331e27d"
	"3de5f40a2e22f08be625db3ca5374f78e462eb8a3191169b4213a0828310b5b1"
	"b05f40bae2963be7da4f9a54bb2557210f97d8002132267222b1cb39c8156cb5"
	"ece133eee20e17814d25ed9a46a00d5cdb1ac8f00f9ae7d9a6203135e29b9bbb"
	"82344741ac3904d65a9e12ee80afa4c41c688762764d799be052580288962cfe"
	"6b580a11068f40aa36ca9eb518fc0150c009218964f82358da9033dea82364ac"
	"48697cb802d909af6892abf11a6ace98c900912206fd3feee1799dcfa36fd000"
	"67ba55a30e89568428113aad6dc6c0d6899e72a1f009d4a3ca1d0d1887b62382"
	"06c6dcbbbc4bb62821d853b8d67a6024a7c5dec2e93e6aa700069a883f36f078"
	"44653633f12202e1abb5b4a2ad8362e5ab34f8c21acca7bb6f008ad2d0aa3972"
	"d53e62396e6457aa669b4923fc111530b13a997d158d9808b1d7f669fcea56f0"
	"db7868755434eea8bebf4ae0698146533666dc18c046b767c483f0909a2004f6"
	"c856c49789bd665a3af7978f471693c5ac839396de70d9152d8338d9aa62ae19"
	"2ab9811f48d15abb782c09288216d695048d97eee9223a9277d3fc61c85e400f"
	"35225cdb330ae31942d6317ed17eb5620728be399475a4e70a5954d6eaa1db81"
	"55a96904ef04fd01c46380636c7285715a32cdd2ba36a997a8dc2b1d77fdc183"
	"1d9165a705c97434e3a9098e21d6e2c8813f00190812e9e4631edb32a5492c90"
	"f00c77f3045c442a92e755516f38be077a3b105c57bc21db17aa1f297568974e"
	"c0e96fbdd036caa3218310a4a2ccdffc9e0e600aa9ca9c28aa8a57f51d164450"
	"fb274ea50161c02e7b310a0ea981ed260a811583d98e99b0c6027d547782d8e1"
	"7f77604c867d1e3c8471c457ea622584f8b8c78bd5504c397ae57592231fbeef"
	"b720ab5d069edf65dc60c7b141b7f0e76f3749ade5f2846f449f05d5b8325eae"
	"72f89f57d95d42958acba729664065d586662d161442fcb64a011abb10229649"
	"de819c19c431c0c4e3b5804ab6f88495b57e2e9555354286bace0bea3700f9a2"
	"705919dea5b5208e4c4942a87651d9319a7bd6409f228e88b4126b409c73a693"
	"83147b9ef3b4f3089485404cc7175a3f552c01671495aa2ee8554386432f9665"
	"81eac5846151aeda201fe60f2d087dd6428f2f57e179c661e8cdb5e02f20c986"
	"c0a330d8ba8b053e08c190c9a550870fb1d8b61859fa77fa52990d16c00bd18d"
	"c05f97d3b8a8d7ca6a234b1d90e2b79b8ace4a2ea0e285a03714fd51c8c9c51a"
	"244c6a12f4cf989ff6fe82722fa40474d0d0ffed4d0104bee6d90d1a3b698eda"
	"d49f147d416b93029e8ea6d2a2b8f78eb615a9b6a9afd01a42d43e20ef673f4d"
	"8d7941c94e735c9cbaab7b444386290285dba1a60b89efa963840e36264f5898"
	"01c04ad9af608b4b88a802aa2397a99263a92a7862c1a802812ce2da4fdd1846"
	"7223de14931536bdd97a9568383c2b79192eee8034112324dbc92d8911b1fa4f"
	"6ca7b481b9abda6f70894b7a9c2e842e0862b5ceab7f38b6ee61951ae45fa25a"
	"8303631b6b9407e8474077797e967bb705fd673a5987968cdcb332b6b8d2802c"
	"197cf1ba3d225f6b3e83a6a22aa1106cf5733854a3719684b82b1ca02d6664b8"
	"64461f72483a69ed9e3b27422aaac0e8ef7a90e3e63d1c229a612641086336b2"
	"9d84e44b894668712877129fb28c8c4c620c1401abca1f9a9827fb2531f9f7ac"
	"5a1f82f1ce73a9d5160189c073464ec18362948bce1390a76672b3446beb28a8"
	"b0993d08aa5416392bed834c78a20883781b60b2158b116388d503eec8a02c29"
	"4a";

/*
 * Each KAT test consists in three strings:
 *  - nonce (hexa)
 *  - message (ASCII)
 *  - signature (hexa, uncompressed)
 */

static const char *const KAT_SIG_16[] = {
	"895f447be01f4cc0587f79397ecd820d752b1876db1197e653d4b28a88d4c0b7",
	"sample 0",
	"04fff00097ffd2ff100026ff5f00ed009ffeab00cdff4bffe60012ffcdff8b001a",

	"cd6a86be9c547f5e19f075f5e64068962893a94027eed40d2e8f751b266d4422",
	"sample 1",
	"04ffd1ff10000000030043ffad012c00b90023ff030095fe5c00710055ff4f002e",

	"0e8abfcaa4fbe1579231543fc504e8a3148ce60bad5606b731839ed669b15f68",
	"sample 2",
	"04002301530048feefffe50097016dffab000b00920098ffdd0063001b0077ff7f",

	"cf8f0c4c78d4f0df639645092bb454c298a8772644daff56f432f14697c56596",
	"sample 3",
	"040136ffe90035ff9cff33fef80082003cff91007c000bffd3ffe900ecff200057",

	"3f2de8a15575f0b4e8c6067ee6215e23ac49b7d1d9b4f9c7e9001e5f072e85a1",
	"sample 4",
	"04009aff4dff9dff39000a0003ff39ffd000570094ffa10086000e0076000a003d",

	"d0215b52167b13b86162d5908e3619ab72af795a7c66d2c3d3267257cdf29216",
	"sample 5",
	"040009002bffdb00580044ff6b0089006a00acff83004cff5a0083006b003cff51",

	"509a2be909412eef92ec16e6f93dfd7573f9de026fa1add893d8f9ef40511539",
	"sample 6",
	"04fff00067000a00620045ff200000ffc5ffd3007200ec0027003cffaf00e6ffa8",

	"a73711a028e954430b4aef317ea1d9f79c7e054a3e5314131f4df6c0e0bbfed3",
	"sample 7",
	"04ff6affd0ff8b00f600710028006a00560029004f005c0045ffcb0047004900e9",

	"546283756c4ca279efa5bf83c7a3a1cb0d8c68b925278f2ec27c7b7ad5b6ded7",
	"sample 8",
	"04ff7b0059ff260019feedffb9000dffb6ff87ff7f00c7fecaff5a002dffc900a5",

	"3af6b128ffc85e5694bc7a8d4809694d7644b186b31d119e1a2082d5054a4489",
	"sample 9",
	"0400e6ff98fee3ffab00b4ff5b00aa0023ffbaffa30088ffee00c7000701990023",

	NULL
};

static const char *const KAT_SIG_512[] = {
	"cd3f225a65b2c6e155c2af799308af940212633fa519a4b4ddd22048ff8a7d06",
	"sample 0",
	"0900070058ffd7ff7affd9ff1e0015ff7fffce0038ff1affad0006ffceffd0ff"
	"0aff26fefcff9700c9ffec008100470071febd01960023ff58004a0150ffeeff"
	"a70150ffd6ff22ffafffef000dff43ffa3012b00eb015cff1bffeaffaa001f00"
	"120074009cff2efec0ffc10095fe96009bffc90027002c0017ffe1ffc2000900"
	"07ff3f0054fefe000a009f0036002e00310128ffaefebbfff9ffc600b4ff4fff"
	"31ffa9ffdd01da00a20010fffd010aff8b013cff7dfef3feccffd3001aff92fe"
	"3f0042ff35006b0025ff9300b401db0049ff79fe24ffdc001e0061ffe10044fe"
	"98ffa2ffff0016ff3200cffeaeff6bff4dfece002effe0fe66ff3aff89ff25ff"
	"6afffc007effd4006bff02005b006900c8ff8bfe55003700290071ff5700da00"
	"5affc7013a006cfff4007d006d00b3004f0004ff18ffecff2eff940070ffccff"
	"4c0086fff7ff51ffc0ff7cff1cff86005b0088ff770099ff8d006ffffa00d500"
	"abffdfff2700570076ff6c0091ffd500fe006b00ec01c2007effc90083ffeb00"
	"43ffbbfee0ff740004fe86ff8cffe700faff49002d00a4ffb3ff7600dffef100"
	"7cff6cff93ffb2005e0073ffd3009100cdff6b0022fffaffd5fffcfff9ff92ff"
	"b7001301080011ff9200ca0018012b000500f400f7ff74011500b7004dfffcff"
	"48ffd20078ff37001e008e01430086004cffc4ffdbff3fff51ff81009b007400"
	"8fffd700870031005dff19ff8d000dff87fffdff8aff63fe97015afffafe9800"
	"5300e5ffb4ff4e006affe000e300f80094ff45fec600c600b400d2ffab010e00"
	"00ff32feb1002b003f005c003fff3f00be0014ff29ffd4016aff06006e000aff"
	"fa0026007d00ae0047ff50ff460078ff36ffd3ff88ffd6ff0500120075009dff"
	"c50062009effddfee4ffc80150ff64018f012a007cff78ff83fffb0027007101"
	"4e000cff1bff6100ff00220039ffd1ff48ffec004f00390079ff5a0067004c00"
	"20ffc7fed300c4004bffacfee4ff2000b60030ffe0fe5d00320015ffc8ff30ff"
	"20ff46001b00e50115ff3a0034002cffc2ffe200110007ffe9ff56ffdffff4ff"
	"250004ffc30028ff3400b3004000c4009f013bffe7009900350038004dff1301"
	"b5ffae008fffdb0084ff44ffad008d0134ff500003013effe1ffc2ffb6fee800"
	"34feb40179fff5fed4010bff74ff2aff38ff5500a8ffe10038ff140010fe5400"
	"ddff1afff300300014ff2b00240016ffb8ffc000b2ff6a0022007a0067ff7100"
	"caff7f0087005eff86ff200098feab0003001300d7ff860106ff96004bffb0ff"
	"c500e700f5ffaeff00004cffd8003aff8cff80ffbeff6e0066002f0032ff7afe"
	"c9ff80ffc6fe770128ff4eff8800e5ff74ffeb01650048ff3d009bff95ff35ff"
	"ad00dcff5302200113feedff94fec9ffc2ffcc0002fe84ffce01c6ff7dffd6ff"
	"c9",

	"a1526fcfb875c35db412013937e99fb7796360f3cccfb1a2cbf175c0cb1d6d35",
	"sample 1",
	"0900bcffd1fe860096fea6ff0ffe5bfe10ff17ffb1fff7ff3400daffe5ffa600"
	"71ffaefff4017efeea0050fefdfff5ff84fe96ffb3ff05ff91ffa90072ffff00"
	"eaff7cff56ffcefff2ffb5fe8cfff1ffd60011ff4aff9500740024ff27010c00"
	"4d004801720098ffe80088ffe3ffb7ff84ff24003500c4ff1000590078008f00"
	"68ff75ff5300f90006008c0074fea400a700860119001c00300079ff6dffdb00"
	"7700f700c40007013dff8bfeec0024ffaa00420199005cffc7ff25ffcd000f00"
	"ecfff9ff39fff90088ffab00b9ff66fe0fff960097fed8ff77ff8c0008001000"
	"73ffb0ff4ffe29ffe7ff56ffb20007005c0012ff4bfffa0097ff7bffbcffc400"
	"0100d100290058fee000f2ff02fffc00abff2affe6ff7dff7ffede00330049ff"
	"fe00a8ffd4ffc400af0035ffe6ff42fe75ff31013a001400f6012f0030002a00"
	"19fe770152000700b60030ffce0079ff69004dff930116fe57ff89ff5500dffe"
	"dc0058ffbd0065ff6b00e5ff620076ff50003aff5bff4f000e00c0ff8eff3000"
	"ebffdfff3dff74ff59002bffe2ff7afffd00890099ffb4fffd00100000006dff"
	"be0058fe85ffd4006cfef1ff4900a4ffed00a900e0ff8900740085fff5000f01"
	"2b00b00014ff18ffbe00830045ffb8003f0050ff1affb50090ff27ff95001500"
	"01ffb800940007ffddff2700a7ff9500fb00b3ff6dff9300d7ff74fff7fec3fe"
	"50000e002d00adff3e00b8010c001c00440016010a00b1011eff65003500f6ff"
	"c4ff4d00e2ffabffb00056ff480047ffa3ff8bffc20066ff4affdfffe7ff3c00"
	"7ffff2fe870068fffeffa40058feca0012ffed0022ffb4ff76008a005000a601"
	"f7ffdb00e400660098fe61ffd6002f00d7fe34005f000f0013ff23004e005fff"
	"2c0034ffa3ffb5ff070029ff64002a00f0ff24ffb2ff7c00920072fff9fff8ff"
	"79ff23fe5dff1c00c100b4ff44008f005c0086ff3e0050002fff3500daff93ff"
	"7effed012c008effba0195ff60ffbbffbf002fff210129ff6d001500daff66ff"
	"7b005a0095fffb009bff2eff5f0032ffa0ff1c00ddfef800d0ffaffedd0164fe"
	"8affc7ff98ff0aff20ffdaff8300b2011affa90092ff5dff7eff760050ff76ff"
	"0cff15009effeeff94fff0ffd2fff6ffac010fff6afefaff1dff16ffc60037ff"
	"b1ff9effaeff2b008700a6006dffa8fff4ffddff89ffc8ffb30041fe97ff27ff"
	"16ffb400b3ff83ff2effcaffb900b900caff5a00b7ffc000330006ff350054ff"
	"a2ff90ffcd0014000e0089ff65ffc80025ffdcff00ffe7fed0006200e00082ff"
	"34ff700093ff61ffe6fef9ffe60119ffecffb20021ffe40012013000a4ffc1ff"
	"2cffdbffc9ff7b006b0147ff91ffd5feea0040fec30015001f00bfffe6febe00"
	"d400cdffbafed6fff9fee0ff630044006100b30065007901380084ff8000da00"
	"09",

	"0c48305764bd939fcac5f86b9e40a18bdbc7c26fd28d875a24328cd2dac3a224",
	"sample 2",
	"0900060003ff940042ff8900cd0100ffd1ffe5ff64ffcf017c003500c9fea600"
	"04ffa0004aff42fe95ffb7ff3e007d0035ffb4ffa700aa004100baffd3ff2801"
	"61ffd9ff940010003b00680020007000c7ff50013cffe9ff63005f004affd8ff"
	"f1ffaf000bffa800280120ff8b00d2011fffe00071ffb00137ff5300b70012fe"
	"a8fed20068001eff2b0014ffa4ff64008fff32ffeaff310063ff190021002900"
	"2e003c0070ffbcffadfea4007c0106006d0071ffbe007a0018fed4ff48001eff"
	"8affd1006900a8ffd2009a00edff11ff43ff01005fff42ff65ffe8ff8fffd5ff"
	"18ffc500c901180179004dffc10056002c0020ff7fff6c0032fff200f300c300"
	"9bfeff0137ffb900f1ff1effec0019fffb00bd0022007c009300ec00d6ff9cff"
	"5e0010004d00da023cffffff41004b0036ff6c00b4ffef00b1fed401440044ff"
	"1b00f60078004300cf00d00067003fff51004e008f00d5fec000e7000e0062ff"
	"bfff8cff20ff9aff9c008e007c0038ff44ffd00156018c0060ffd6ff74005d00"
	"0600a4ffaf02a50096ffacffbf005b00bb00c10000fffcff54001aff54ffc200"
	"1900edffdb004a002701480135009100d8fefd007cffdfff95018200cc0039ff"
	"2a010cff81010bfefc00a0fff80096010fffdc008b0036ff7eff4cffcfffbeff"
	"810058007100d7fff2ffec0021008aff7d019dff7c00cb0013fec3ff7e0098fe"
	"e1000801c3ff9800c300a500a2005a012fff7500a4001e004e00a00045fef8fe"
	"b801afff0800e300f6013d0098ffff007800a8ff00fefe0105ff0fff77ff2d00"
	"1bff7a00a900150095ff100011ff99fef700c1ff51ffa50141ff5affdd00b2fe"
	"34fff9ffec0013fef2ff2eff91ffdf0021004f005f005eff8b0015ff64ff4401"
	"5eff4affea00ff002dfe56005dff02ffe70088ff4a00a5fef9ff5fffc50032ff"
	"c400eeff8cfee80111feb5ffb5ff9fffacffcfffbdff0700370042ffddfee700"
	"79007e009bff26fe2cff3e00e3ff73002401370056ff9700f6001b0016fefc00"
	"aaffc2ffe30005012b0059ff81ffe10005ff7200ea0026017aff92ff7a001d00"
	"55ff88ff97fffa00a1003c01a300790157003aff62000e009401460077ffbeff"
	"f8003d001701bc000dfff90027ffb100a0ffa000f2ff21ffabffd80114001600"
	"b7fecfff20feb4ff33005900a0fef3fedeff9e00de007eff0aff84fff7fedc01"
	"13ffaeff9200d1ffd4ff650086ff49ff87ff57004a0065feffff82ff5bffa501"
	"43009b0097ff81fee0015000000127ffed005f004fffebffb1ffdc009bff1900"
	"88ff790138fff700b30157ffe0ffbefee40083ff830015005e01560146ff4f00"
	"26001700fcffef00950069ff4dff43ff30fe51ffea001a0093ffc7ffc6ff81ff"
	"faff79ffd40077ff64001eff40ffb1ffb90042ff41ffce01490066ff9f00a000"
	"20",

	"782658797c488ce4f873262ce6a9e78561410c258c60c268c3f4be762578a8fc",
	"sample 3",
	"090065000f00c100fbffa7ffd7ff3e000e008dfff0ffc3ff4dfef3ffb400b401"
	"bbfeb4ff12ff5800fb00d3ff5eff0dfeb80095fe9600cdffccffe8fecdffa2ff"
	"a4ffe50045ffc70078ff40ffb800340063fecf003900eaffa0feed0077002800"
	"aaffcdff470010ffe000edff0800e9ffb00093004efead00e2001bffe70012ff"
	"aa006e007a011e004100adffff00aa0144ffb7018c0032005eff620069ff92ff"
	"a5ff5b0093001b00ec0113008bff1d00f80057ff6e00d30022ff32ff2d002d00"
	"13feb70136005d009200530018009dff5900d70064fed1ff96ffb900a6008bff"
	"cdffe20062ffe700effedaffe9ffa1feedffb6ffe40040ff3300530146004eff"
	"ec00a8ffdb003d007801000012feab005fff72ff6b00da003effde00c6ff5100"
	"51ff5b0059ff1bfff3001dff7900fd011dff4ffeba009ffed7ff6d0080006dff"
	"9b00370082003f006fff37007400210029ffe5fedcffa0ff2ffff70091013000"
	"3bff3100e300640062fedefff9ffef00640009ffdd00ae00a1ffe0ff61ff9100"
	"0d008c009b002500b8fecdffe7ff1fffed005bff7eff73ffa5fffcffdaff9000"
	"ccff8e004a003f0052002100b3002a010e0006ff15ffc70121fee5ff7eff91ff"
	"bcffb2ff5c004c00aa00b2ff3c007fff8dffdcff830024003ffe45ffb7ff9301"
	"03ff2d00aa0088004afea8fffcff30ff35019a013c004dff41ffbc002100dd01"
	"31ffd6009aff40fea500880133009bff3100830023fef100a4ff86019aff4fff"
	"77fff7ff2cff3100160059ff82ffdf001dff6affb200d5fff60094ff54ffd900"
	"29ff6500beff98ff6c005bff29fefdffb5ff58004500a2fea9fedd002400abff"
	"fd016e0007ffedffcefffcffa00086fe2efeea0108ffb30051000100680016ff"
	"01fff200aa000eff35fffe00d00199ff5e000cfef0ff17ff040061ff8800fa00"
	"2b0016ff150018003a0034ffecff9eff83012d01290035ffeefff7ff76ff6e00"
	"ff0072ff53ffaafff6ff81ffa600d10030ff82ffc0ff91002affdb0025007700"
	"69fed1003d00c80033ff6a00a7ff440060ffcd015bffdb015000d300b3ff94ff"
	"59008affeaff4e005b0191fff6001f00c900cdffbbff1cffa5ff670090ff2300"
	"37004e006300310116ffddffbdffc800ecff59ff90ffb10024ffe2002f00b300"
	"65ffaaff3d015c009ffedd0014000bff4b006700a20063ff51ffc0014bffc000"
	"81ffaaffb6ff90005c007c0037000e0122ff0cff3bffc7fff10058013dff91ff"
	"62fffa020bff1600880074ffec005c0028ffe80044ff97ff64012a001efff400"
	"f7ff3e000e0005fe600007fee2ff4aff13009700ef010400f00064fec8004e00"
	"2600920043ff1a007c003200eb0048003dfedaff4400510013ff4700580016ff"
	"a3feb201b0fef0fede0048008e0042feb2ff7ffff9000d00b7ff9f00d6ffd600"
	"f3",

	"ede0d5c1beeab1de0cf3eb392c3fa53a184ceb8e3745bb9dbf8a13ed01aeef7d",
	"sample 4",
	"0901390087ffc4001effd6006a004a0089ffb3fedeff8200360071ff7bffe4fe"
	"fbff8e00d2ffc3ffc8feb7ff34ff24ff15ff44ff880042004f006afefcffd501"
	"09ffc9ffbfff76ffd1ffc4ffe8011fff400128003fff760025ff55009300a100"
	"a20018ffc60077004c016eff2bffe4018e002d00b9009b0027ffd5ff1f00de00"
	"19ffb0007cff94ffde00b1ff6fff26017cff10ff75ffc6fe62ffce010efed7ff"
	"f40069ffe1001e00a6ffd40011ffbc000e013fff91ffdcff51008500a500c7ff"
	"ffff4bff9f0021fff3002dffe7ffc8ffa3008500550092ff1cfff7ff60011600"
	"a8ffdfffebfff4019f00dfffb4007b016affb000900129015100b5ff7d000f00"
	"b800ebff7fff6a00c70043003a00c3ffb000e1ff78006a00fdff84ff65ff68ff"
	"d8ff22ff81ff28ffc60075ffec0040ff59ff44ffbb00a4ffe100000026fedffe"
	"fdfef2ff67ffc80016ffd5004efe2e01ebffeb0012002cfe3dff46ffd4ffecff"
	"aaffdfff46005f007e001e01d5005fffd3ff4c0062fff0004501a8013c0080ff"
	"82001bff94fee4fe27ffb6ff9c00320099ffe4ffb9fe8fffee011bff01ff6c01"
	"ec006900f500830032ffcc0108fffd0101ffb60019ffe2fffbff2100cbff0800"
	"bfff01ffd9ff0dffd0ff3a00be01940084ff5d003d003900310070007c003cff"
	"e6003500f800d8ff73ff8cff85ffa900a4ff1efff800edffbb00d7011d000dff"
	"b900150041fed4008f0004ffef0035ffe6ffbb00feffc000270015002100a5fe"
	"890063ffe5ffafff6000340182ffd8ffbd00fbffa90008ff39ffda0149009600"
	"fb005e001c0008ffa60037005d00ed000effb1002e0085ff78004900b300bdff"
	"b200effffa0143ff2e000cfff2ffcbffbe003700c001deff7b006efe6f007e00"
	"b1ff69ffd8005cffb3ff94000a00c300d300bfff1e0120ff8c00e4ff2f001600"
	"2300cbffcc009900e6ffd7003c003200a10057ffdc003ffe7a000600ecfffeff"
	"da000e004800a6ff72ff590078004dffd600f4ff580089ffd70049ff15ff74ff"
	"9a002600d0007bfecdff9f0013002bffbeff5fffde00f5ffc4001a0052ffaa00"
	"3eff9fffb302030091ff9201480034ffb7003a01730059007800eb00fa014f00"
	"b1002bfff9ff5cff7cff48005bfff3ff3100bb009d00340047001f0047ff59ff"
	"b3ffbbfef3ffda001b002cff1bfe71ffd20091fee100e70048002600f30124ff"
	"1000c7fec0ff15ff7600e90046ffa5ff990095febc007cfffc0042004eff7900"
	"bafff4fe83ff6effe200f4ff7300c2002bfeccff1a017e0041003301e8ffea00"
	"9dffd5ff710082000dffda008100ca004f0151004c00230044001f009e004201"
	"0c00a80045ff78006400fe0042005bff4b00d7ff7c00b000ccfecf0024ff4600"
	"0f0137ffc4ff6000260002ffb40004ff37005000830032ff6e0105fee1ffeaff"
	"4f",

	"fa4ba817c5ccf62fe37a5a3db2804b1d79b3475dd5df51d23a1e0505bc43ce36",
	"sample 5",
	"090110006ffef1001a004afff9002c01300092ff2bffe20174001a002effbeff"
	"4affd50114000b00cbffb5ffccff7e00eb01300018ffdcffaaff72009200eb00"
	"3f01c1ff11019affe0ffbe00c3fff5ffe30063012cff2000070001002cfeaf00"
	"acffd60094ff4cff16007cff21ff74fef90007004afe610038ff46001eff9100"
	"caff6b0080ff88ff67fee0ff61ffc700320032fff70078fef30022018bfe4dff"
	"c5003effeb008bffebfef80005fffcff7cff62ffbd014400d8ffee00d1ff41ff"
	"4e011900df003800a9006200670000ff9dfefeff74ffaaff73ff4e0057ffd400"
	"e300b9015efe6b0021ffa2ffcd00c0ff0f008400d00007ff680014ff56fed0ff"
	"330083000eff8d00830062ffe10061ff2c000c006cff70005a0041fffa002e00"
	"9e00bbfff500840024ff6cffa30057feb80130ff230070fe890107009dff32ff"
	"fb002eff47006200d60062ffdb0092ff4bffc4ffb0009dff61ffb5fee2ff65ff"
	"34ffa90012ffabffc1006dfe17ff3b003cff30ff08003afff0ff280156fed7ff"
	"c0fecf000c00c6ff5fff37ff75ffc8013f0082fedcffb9fffe0009ffbe0045ff"
	"87ff6b0006008bffb7ff34009a000dff5100b80063ffadff8c0113fea3008afe"
	"22ff8bffcdfec0ffdeffc6ff37ff35ff230038006800d0ffdc00ba004d000100"
	"ebfe8f00230012006effbaffe5ff1000a50044ffd7ff63ff660094ff88ffdaff"
	"3d00cf00d900b4ffdb008200540012001400a800b5ff15ffd60016ffb200d4ff"
	"e200fdffdeff4b0088ff870125ffa700b50092005c002eff48ffb6006b001a00"
	"e700c4002300baff3800bffff6008effb600570047ffd4ff7c00f30037ffb800"
	"54ff9b007affd400d3006eff8e0004ffb4ff7c0031fedd005f0019ffe8012300"
	"62ffeffe2000680043ff6f0045ff840069ffa3ffa50033018900580117ffd201"
	"2aff47ffe9ffc9ffd800d50010ff18fffd011eff70fffaffbcfe9dfef1ff7700"
	"bbff9cff76ff17feb80079ff870059ffe6001affb8006fffd400efff64012afe"
	"7b002f008bff32ff03ff56000effc900e90156fef30079ff3ffff500be007400"
	"8100d7ff6cff18006cffa5008600f5ffdefffc003bff1100180111ffc2ff79ff"
	"a5ff25ffca007500f00063ffae011900770044fe780076fff4ff57ff0a000d00"
	"6dffee0051002bfffe00caff5efef1ffa6ffea0063009aff7bff3b00acff8600"
	"4900b6fe90ffe3ff18ff700079ffabff60ffe70096fef2ff85ff4c001100d500"
	"b60052ff98ff09ff62ff8f00cdffb90120ff4a009eff4afff3ffddffcb005eff"
	"2500280045ffee00a0ff4e001cffbf002800cf004bffdcfff500abff7eff9800"
	"54ff7c00470076ffb6ffce00c60056ffe9006e00140018000200d2ffd2ffa6fe"
	"b2ffc3ffb6fffd003dff68ff66ff9c0062ffbf00aefee000bb0048ffdf007eff"
	"2a",

	"69e5bf07ea263f1903a46ef2f9aa7551b5be6a784a575441c6a5b59750e41717",
	"sample 6",
	"09ff8d002b00efff94ff84ffd600a3fea9ffb0ff27005bffd3ffcd019b000cff"
	"1b004f00d9014800bbffa6ff60ffa7ffde01e50065006e00e4ff76ffce00b0ff"
	"a2ff4e005f00e0002c00450073ff6a000601c3ff7cff96ff94ffa9ff460189ff"
	"9b00b400e40005007eff74ff85ff9bff110081ffd5ffadffb50026ff93000dff"
	"76ff8dfec5fdb9fec8ffc201d400c9fe32003bff0fff4c0013ffa5fe9d00fbff"
	"10009bffe9ff7b004b000dff45ffc5ff7affee0023ff540011ff6e001d001eff"
	"ef0123fffbffc10119ffc70042fea1006d0135fecafff1ff46ff1effda01ce00"
	"2100daff900027fed7fe48ff61001cff88003400cd005d001e0112ffe2ffbe01"
	"67fff90148007e0002ff7e008100100055ff58fee400a6004400c9ff52fe7fff"
	"a1ff39ff3bffabffb8ff70ff8b00490003ff96004d006b0058ff6201170025ff"
	"a900d60008ffb700d200dc0116ffaeff5dfee7ffd6ffb10041ff59018affac00"
	"adff9dff4a0131007d011c0016ff8f0072ffc8ff6bff010103fff8002fffaaff"
	"d8ffda00c30054ffa30018ff0c00290088fdeefff6ff54ffd9ff78ff92ff52ff"
	"6c0028ffe00014ff7cff28ff8ffedcfeddfe91ff18ff8dff19ff1affa6004801"
	"5effba008b0145ffeaffacffbb0043ffd100cdff9eff9600b700b8ffbcff9300"
	"15004700920165ffb60077ffacff88005f004a005cff520037ffacff7600cefe"
	"e5ffb900af00acffa70065ffa60010006dfff7ff950034fffc00f7ffcb00a100"
	"45000e00edff4affbeffea00adff6101a0fe3900c1ffee004cffa6ffb40098ff"
	"93ff9aff92004c002bff10ff95ffc8008c0027004dff2600a9ff74fff3ff1b00"
	"ca00b0ff23011cffe0ffc7ff530063006bffa6ffee006a0012000cfea3005a00"
	"e40085ffb5fedaffe0ff810011ff3bfea2006300d1003300eeff880070feb000"
	"3b008e0056004bffe7005c0072011e00d2ffa1ffe80102ffdfff00006fff7b00"
	"36000d00340040ff8effc20015ffd5ff9c00cf012afee3ffc30081feb9ff0d00"
	"1f00500007013b000b0075006200340016fefc00e700f400b7000cffafff65ff"
	"280024ff11002400780081ffd0007fff98003effb600f3005a0054ffde005dff"
	"3bfebb014e001c01c50000ff55ff48ff8cfeac0087ff840011ff20015200a4fe"
	"df0057ffbaff82ff6a0050ff12ffc0ff99ffbaffce0129ff18ff7bffb2ff9efe"
	"fa00caffc3fedcff87ffde004c0002ff4dffad001dffdb007b00e5ff9aff9e00"
	"4bff83006fff6f00360009005a001d0006004f01200103ff0f019800a8007f00"
	"06ff5fffe1ffa1fff5ff8100470077004500c20005ffc6ff60ff6d012800d701"
	"370011ffa900ac0170ffadffbc006efff2007d004600920040ff58ff5effb3ff"
	"64004dfe2affcbffcc0050ffef0025fff0ff54fe6cff1c00deffa70034011aff"
	"85",

	"4bf3e3db906ad25bbe78cd425485eaa6c54983dc626fd919e11198dc01eb6f13",
	"sample 7",
	"09ff6900a500150109fffe0078fecbff390148ffe2ff03010bff660052009700"
	"7afec40050fef0012d0118ff89ff84fff200fbfee700a000b100e7ff52ffd4ff"
	"fdffbfff93ff2e005f00390013017000ceff90ff80ff4dff40ffe900270010ff"
	"9effbdff930087ff73ffa300beff2cff97ff9afebdff06005a00a4ffb3ffb400"
	"0efff8fe8eff39012c00010009ffbfff7cfffaff4200e3003b0026ff7fffb500"
	"eeff76ff95ff5e001600a4019cff000029ff63ffd9000dffa6ff4cff51000200"
	"2affabff2c001900a200af01080141001fff71ffca004c009700cd008900db00"
	"340050fffd0045ff96010c009200e90089ff60ff1b00bb0161fe47ffb700cbff"
	"8dff87ff7bff4dff57ffa000dfffac00b2ff55ffe9fff3ff67ff82fe51009401"
	"19fecb004e01730001ffe7ffa1ff600002ffe60183fff5ffa4001900c2ffedff"
	"4f00c4fef9001cffeeff65ff2f00bcfee2ff24009e0078ffde0034fe590088ff"
	"bdff9c0018ffca014600a7008cff7bff4effecff5300770004ffe4fef2ff8a00"
	"510047005500f0ff4f0125fe5700040038000a0043ff06006d00bb00b5ff91ff"
	"70fe7e0004ffacff7e00070024fe6dffcbffbe002200b3ff91fe6bfebd0070ff"
	"b4fff3ff570127ffdd00d10087004400310005ff4100060098ff960053fff800"
	"56ffb4ff40fff5fffe0051ffa2012a00a6004301a5ff2cffa5ff5800f6ff33ff"
	"b200b9005fffc000e7006c016a002500b300d4fff1fffdfefcffc200e1ff0fff"
	"dc003e002cff38ffdaffc700150092ffc8ff90012a0023fff0011eff74ff3700"
	"0aff82ff86ffa4ffcbffc5ff9affa60134ff5afff6ff6eff7d000f00b0ff1eff"
	"dc00a500e0006fff2e00b7fff900870162005f0148ff8a00ddff9b0034ff6100"
	"3d0103014bff48ff0fff250193000cff4a0063ff7f001e00a4ff95fe99001f00"
	"22ff7bffcb014afffa00210088001200c4ff1bffbf00e100bd00ad00af002400"
	"f4ff670038ff30006a002f006eff6fff60ff8cfeebff6f0133000e00d5ff93ff"
	"2b00b20020ffd90121fff3fed60036001eff92ff6700b0fff7ff5fffe3ffac00"
	"95000f0102ff0e00ff0039ff5e0111ff1eff80fff2002affa9ff910002005500"
	"0100bb012f001bffaf000b0129005bffa9ff1700ccff54ff91fe5a0063007500"
	"0f00f60097006100aefee10042004afdf6fed80083ff6200520002013200a601"
	"22ff6c001b003200ab00540031ffa40021ffb800280124ffe6ff8a01310020ff"
	"e800df00d1002cffddfe75ffebffe6ff5500af0092ff29ffd8006f011fffdbff"
	"7b0041ff49004effb5ff110062002affc2004f017cfe9f0023ff7fff4fff93ff"
	"2dfeafff64006b006c00ba00e8ff99ff8e0050ffa2000fff6900be000bfee500"
	"04007a00720160007dfffd00f9ffa4ff0000b0fe70ff66ff4f0029000f002dff"
	"d2",

	"857241e477e7b1d335e634874a6b61ed590180b7d9d7bccb7609c0e95b47143e",
	"sample 8",
	"09ffb90006000f011e0034ffbcfe9e0107ffc3fede0107fe55ff4dffea006dff"
	"56ffd20064ff71006b0069ffe1002b0035ffd00080009dff37ff6d010500a6ff"
	"d000c900f3ffc9fe8fffa400c7ff98ffbfffccffdd00d0006100be0086ffec00"
	"82ff8afff8ff6c0111001b003d00220053ff4a00d4014700e7005d005effcb01"
	"53ffb3ffe80000ff97007effeeffb1fff600d6ff18fff6ff74ffcbff01000c01"
	"560002fef0ff8eff1f000efedd014b0025ff8bff4400d1ff2f012800af0043ff"
	"1700b5ff9cff9bff09ff5e00ddff92004cffc9fe3600ad00c3009d004fff1efe"
	"ea00aafeccffebffd4ffaeff890047ffb10115009aff04ff6600d300e3008501"
	"5b000e00b60058ffcd00d3ff11ff0e00530023005b000000de00ce00b6ffe600"
	"3ffe98ff4f0020fff8000f0105ff7bfec0ffc8fffc004bfff4001cff5100bbff"
	"ca014100b0ffc8ffb000d1fff4ffbe0109ff63ff7b0021ffa9ff68000c002bfe"
	"dfffa8008300a7ff7bfebbffca0031005d008000550039ff2fffa1ff4a01b8ff"
	"2b0027ff37ffbf00dfff0a00e3ffc000a80064000efe39ffba00a7005d006f00"
	"9e00ddffb7ffe8ffc2004a008cfffdffe6fee300ca0105016e00ffffd6007bff"
	"ea001f004dffcc0175004e0123013100a8ffa6ff9b003dffc80046fe77ffb1ff"
	"6301aaffb1ffb9ffbeffee00fbfeef0027fecaffe4feaa00b4ff51004b0052ff"
	"410072012a0105ff88ffe6ff71ffa0fefe00280033ffe50043ffc40015ffc0ff"
	"7e005500caffd6ff330065018affa5000bfff600230164ffa9ffaa0058ff3d00"
	"100013ffbd004c00fe008c0029ff11fffd00890020fe84ff39ffe7ff6fff9700"
	"b2fff1fecc0027ffabfffdffeb0078ffe5ffd0005afff9ffbc008000b500a400"
	"8b0017ff7900710058005bff9b002e00b600090056ff83ffd3ff7dff060041fe"
	"ddff9cffc9ffa100aaff98fefcffdc013300bcfed800a1ff9200420057ff1c00"
	"07007dff8b009e003a012100b1006d00aa00ae0067fff800f5ff1ffebafebd00"
	"ba00a9ff24ffb1feec003701d0ff7eff65ffa6ff2b008efeddffa70058ffb001"
	"04ff3b00a7007100040138ffb600bcffdcffcdfe62ffd3005fff52ff6e0029fe"
	"cdfdf0ff64ffe1011bff7a0042ffcfff8f015dff200069002fffeafef4002a00"
	"8dffb5003c0100fec10019002f0092fe7dff9e00e7ff37ffc7ff26ffbdff5600"
	"3c003bffbefff9003c00ffff3a0002001d00fafe69ff34ffe50020ff8dff7bfe"
	"d80066007cffb00092ffdbffdd006dffea0047ffb2ff9100d200d80095fff6ff"
	"08ff83feb50027fff8ff6300df006e0099007aff71ff5cff9bfff800cdfe4300"
	"6aff4e0040007dfff8ffbc013400ae004b0060ff92ff62ffc90071ff5cff9001"
	"42fef20085ff8afff7019c0071ffc9012eff73ffb5fecc0014ff97ff58004c00"
	"6c",

	"032294bf7a7bbecbb2f4f0f474f7025c9cb6b6abbedba2ae4709fa7f430454ba",
	"sample 9",
	"0900fdff3800cbffe70017fe9800b0fefe0066fedc006b00e300a1ffee008300"
	"5201720063ffdd0008002b0031010eff550029002e013cfffd0075fff6002fff"
	"b1ffe100b8ffeb0006002dffe4ff9400b7ffdafe6fff5f005300a0fe94ffe801"
	"2901e4ffe1ffbcfef0ff7dffe7ff9300530041005cff900164fe2bff9301a7fe"
	"9bff78ff0fffbb0053ffb70017ffc9fecb006fffd801430020ff66005dffb800"
	"d20029fee4fef3ffee00050052ff78ff9fffdf0076fff8ff40012d00d400c400"
	"480098fff2001afe03ffc3ffe3ffbdff23000600edffefff68ffc70103ff2bfe"
	"1100c40067005000e6ffccff8efea0ffc600ca003cffa3ff1e008a003d005d00"
	"410041ffa100fb008b00c6ff2c007900300179ffce00dfff400008ffe0ff9800"
	"e4ffd5ffa5ff42000fffe6008200a3fffb0030ff79ff6fff4effbcffbe000b00"
	"5500aa00de0000ffbe00aa0000004afffa003000ecffe0ffac00b5ffe0fff8ff"
	"2c007c000001be009f00cd0044006c003600b200aeff91ffe60149fef000aa00"
	"48ffe000c7009fff4f0082001aff76003b0026013800a1fef801c9ff87ffd700"
	"3cfe98ffc4003101bbfff2008fff61006a0005005e0022ff66ff2400bbffa401"
	"96fef5ff6c004000420075ff38003b0040006cfefe00a7ff4fffcc0060007000"
	"4c0064ffe9ff7fffcc002700e20082ff770047ffd2006eff970070ff880064ff"
	"e801bb00740001ffd401e00017ffffff67006c0167ff83005200aeff85ffecfe"
	"8c0078ff4b002700b00037ff8c00d50086ffa2fe550068013c017e004aff7cff"
	"eeff08ffb0008d0018003b004500e0ff70ffb4017fff1b003affa4016fffa000"
	"4e006100a2ff09012f00adffb50096fe9efee900cfffdcffcdffbf009dff87ff"
	"7bfffa00d00088007cff22ff8700bbfeda01e1ffd20107ff84ffc3002a003600"
	"97ff8c0053ffb0ff85ffb2ff25002c000a00160056ffaf00870044006600cd00"
	"09002dff2dff64001effe0ffa1ff25ff5800620049010b004e006a00bdfedcff"
	"5cffa6008400ffff5fff77ff83ffb600abff9f011dff67ff6200950074018d00"
	"94feea01a6feb2003cffb9ffb3fe67014400c4ff6eff44fef60041ffd5ffc2ff"
	"ed011cfe07ff9600370114ff5eff80015bff8100c8fed3ff2efeb700a8002b00"
	"ba01070082ffc3fe90ffdfff5100580109ff6300080090ff6aff2a0071ffe200"
	"e5ffe0ffcaffe6ffb7feeefff1ff03ffb7000a003cffa6fefcff20001e003200"
	"4c00c700d8ffdbff2dffc4fea7001200440045fee8ff4d01270034ff75ffe5ff"
	"8bff3b0094010b00affebcfff9ff0400f500960055ff02002a006afeedff9900"
	"21ff64ff6cffd2009affda0069ffb30012ffe5fef5ffcd0198013dff2501a2ff"
	"a3fe15ffccfff9001d009800d2ffdcfe87ffc2ff5c01bcfe8101f5ffcaff8dff"
	"a4",

	NULL
};

static const char *const KAT_SIG_1024[] = {
	"af0228b7e30f8c0a6620c8419cd181acfe6c76d134020a9fedb3839ca732f775",
	"sample 0",
	"0affe7ff90ff90ffc0ff42000f0151ff18ffaeffa0ff9effaaff72006a005aff"
	"affe4fffdeff80ffe00078007800b5fff8ffe4000400b600550106007d0133ff"
	"31007effb500730035ff93ffc0ffbc00ca0024ffd7ff46fffe0083009effee00"
	"29004800260034ff36ff1bffccffbf0000ffd0005500bcffbe0036ff6900bf00"
	"24ff0c007cff59ff15ff470060ffcc00380069ff33ff8000cfff62005cfffb00"
	"3c004700d4fff7ffd80123005b00bdff020045ff66ff1d010400adffb100baff"
	"f80101ffeaff5bfedbfff9ff85002efe2dff45ff85ffb700f000ceffe3fef200"
	"2d000000b300e0ffcfff030178fee2ff0dffb4feb8ff930040ff93ff8aff4a00"
	"560226fec9ff53ff50fedcffc5fe6aff8fffacff3dffd9004ffeca0089ffc700"
	"3dff92ffffff89ff64fff1ffdb0030003bff75ff1500bfff64ffaaff65ff6900"
	"29fec1ffff00ea009cff0fffa1018101ad00e90070ff470081ff9c00950087ff"
	"230032002bffd0ff3f00c2fe9700aaffb300caffceff69ffadff96fefbff0cff"
	"a2003a0084ff61ff42ff97fefdff58ff81001001bc006dfff700020195ff33ff"
	"a0ff63ff6a0097012effd7ffadff32003b00320006ff960026ffeeffa8ffdfff"
	"4bffd20014001300220068fee900510059ffa6008600c2007fffc9ffe5ffd7ff"
	"ecffb400160109ffd8002e0006ff3dfee6ff83ffdfff62ff3e00200011fef900"
	"cf003fffcfff70ff090026ff87ff25ff63007a001700e5ffda004b00b8ff4dff"
	"990095ff37ff5b0135ffc0ff9b0159ffab0091010701d3005cfffaffb0ffec00"
	"61fed400e000b4ff940079008ffeba00cbffc0ff070091ff90ffd3ff36002400"
	"61ff33ffe2ff7900e3ff3900400038ffa500d000fd0080ff69ffe2004a00c2ff"
	"f2ff7300dfff07ffcafe4600110113ffd20085003e00afff9d00230049ff03ff"
	"1a002a00150041ff75fffcff6200550067003700bb002b0092ffd9fff3000201"
	"68ff90000800070011ffb800910095ff10003aff8eff38ff93008f00c5011700"
	"2cff2f01400152ffd2ffadff9b005900a80036ffe5fef2fff4febdfff6fff6ff"
	"96002e00d3ffc6ffaf00bcff0cffa9ffc9ff3400e20015ff8ffea900ceff4700"
	"60ffa3ff62ff73001dff8ffff3004eff54fe6f000dff3300af0028ff62007e00"
	"63ff19011fffe3ffb3ff1dff95ffc8ffa40042ff97ffc2ff39ff7dff9bffda00"
	"8b000bff6bfebe00540021ffea00320118ffbefee4004eff3c00d3fff700a900"
	"1e001d0091015e009200bd00e7ffaffff0ff45012aff49ff010135ffffffc601"
	"64ff6cffcfff25ff63fff10026002000e3fffd00650133ffc600b4ffdaff40ff"
	"0700e20043003d00210001012500b6ffb4008bffd9ffa2ffd2fefcffaaff7f00"
	"ceff0b0063fffc0019000bfee5ff76ffe50026ff92fffeff6f00d0ffcdff26ff"
	"9cffe000210090ff720003ffa7ffe2000000e8ff8500afff3100b800a700d300"
	"08008201880089007a0055ff500022ffe0ffe8fedaff0eff2d0012fe4cff0400"
	"140068fdec004cfff6ffdaff31ff63ffb0ffa3012500ba005300cc0005fff0ff"
	"f5013d00bdff50fe3400a40024ff95ff2800c6fed100f1010d001f00ee00d3ff"
	"96ff83ffc40010009f0144002a0051ff36ff8b015b001800800067ffabfecd00"
	"50000cffc500aaffa600580071fff4007e005fff37ffbffff6ff1ffeb2005600"
	"8a004801570051ffafff27ffb400f0ff3eff7200ef00f2ff50ff99ffacff49ff"
	"7affd70068fff1ff1c00b6feffffceffd9ffe7ffff00edff95007cff7a00f9ff"
	"af0080ffc6fff1ff71ff1401a4ff190054fec6ffe5fea6ff6100eeff89fedf00"
	"9600550024ffe4ffba00520080ffffff75ffb1004aff33002f005700e30097fe"
	"2a00d50074fea6ff89001d00120007ff0fff38fef70052ff9d00180079007200"
	"8a01920116ffee00a0ffca008d006b002affb6ff61ffc90002001800ab009300"
	"940054000bff120058ffccff26ff96ffd0ff18ffcbff4fffa9ffc0011301aeff"
	"8eff6bffdd00830181004800b30088fff900fd0041ffffff83fee2001dffa8ff"
	"c00124ff89010a0050011500a7ff3200d0ff63005aff9900470005ff32ffe2ff"
	"7300ec009e00e700f6ff20ff6f013200a9ffb7009cff4cfff4febaffd00009ff"
	"08ffb0ff570093fef9ff75ff610016011ffec5ffd2ff84ffc600d6fff1ffcbff"
	"0400e8fe88ff730086003bff82ff23ff7efea8000bfeb8ffce0027ff17ffe800"
	"1cff840092ff24ffac00440035012dffb2ff950054006effc4ff67005d003bff"
	"2fff520007fff4ff7dff68ffe8ff5d00b6ffce0046ff02fe73000b0132ff2b00"
	"35fffd0085015d00a900570031008bffe5ff2b0130006effca0043ffdf006800"
	"4c00ac00f6ffe8007affa30060002e0077ff47011400d8ff4effd30058003a01"
	"76ffd80033ffa9fe8dfe57ffb9ff31ff2600a2ff78012800590072ff7effd400"
	"4dff48fe8affe6ffc6ff4b00b70079002001450052002c009c01ed00ccff7b00"
	"e3ff34fffe0085ff7f011900b5016d001dff7e007affa600baffe0ff6effe1ff"
	"810008feacffb3ff8aff84003efeecffccffde013fffe900230059006c0006ff"
	"94ff8b00a60089fff7ff70ff0dff1efef200a9006600810071003bfee9ff3500"
	"59ff04ffe5008a002c0035ff8c002a005a006b004bffdd003101f00029001000"
	"06ffecff8f00f9ff16012effc4ffd7ffba0020001effd50082ff4fffef0083ff"
	"74ffabff8dff6f00680097010c004cff2d00a0ff83ff7b012f0000ffc90121ff"
	"73009effcfff5bffd5ffa6ff82ff9dffc80071008bffd1008dffaaff14fe7a00"
	"d30089fec3fee6ff6f0041ff7600170104ffceff620026003700430056ff9200"
	"2c",

	"0deb2593f9773204e70b1cac2898e54d8c75b8c86918a711120622feaf80994c",
	"sample 1",
	"0afedbffe8fed8ffc7ff83ff5effd4fffbff71ffca01e9fe37ff2f00be00bc00"
	"3a00cfff9300b1ffaeff13010d004bffcc00c50038ff1700abffda0048fef900"
	"80ffc7ffbd00150097ffc3ffa8ff500116fee2003bfe5bffa800afff52003300"
	"76fe46ffb2ff98007c0043ffdc00a60046009bff8aff99ffbd0008009bffc7ff"
	"e5ff2b003cff65ff52ffd80031ffa2ffbc010bff81005c008800fb00dd003800"
	"85001900b2fee1006fff79006dffa0febcffc4ff5600ef00d0ff8aff64ff87ff"
	"b60027ff540056ff9effbe005b0114ff6aff37004fffb9fe5400e101cfff6500"
	"7600d100fe0068000eff25ff5900b9ffeaffbeff11fff600d3fffc0008ff5400"
	"e80035ff5bffb1ff6eff9300f0009000c3ff9c003c00d4001fff2afeb6001a00"
	"bdfe6500caff880050ff8effb1ff5100a2ffbe0007ff49fe51ff4900f4ff89ff"
	"f4001c006e00060017ff35009300c7ffd90031ffc200ba011f016d0008ffe5ff"
	"df00e4feb0ff5f00a8ffbcff27ff86ff16015cff6d008e00c900c30055fefb00"
	"3f00c300c8005bff540022fece0009ff42ff2e00dfff8dffdefe75008bffc4ff"
	"edff6100c601110010ffbc003a00310057ff4dffd8ff7efff5ff35fe6cfffc00"
	"a1ff9801510038ff89ff8b008cff78002f004b003e003d006c0152ff57ff9dff"
	"27002800d1fffe0134001800660037ff39ff95ff5bff5a0144ffa700d90140ff"
	"94fe56ff14ffcf0074ffd600360189003affe2ffe4017f001b0074ff5300f800"
	"edfea1fee70033fe1a00f4ff6700250010ffddfed5ffae0094ffd4013dffbaff"
	"aa011f00ab0055000c001cffbf004b0031ffa4fff800420102ffa5001b007400"
	"a7fffffedcffadff63ff89fff7ffe00039ff9fff1fff7e005dfffdffbbff51ff"
	"bb0112003200b80093ffd6ffdeffcd003e000cfffc011aff42ff18ff46ff9fff"
	"a90149ff80012dffa000bcff65ffd400560111ff6cffb4ffa3004eff4affa2ff"
	"59ff52ffd5001a0089ffb900b6ffaa0150ff93fff300ee0066ffb8ff8a000bfe"
	"a90033fff4ff4cff8fffc50081fefd00540108008fffceff330114fffeff99fe"
	"9cfffcff5400d1fefdff9eff5bfff600afff7a0090016800aefff8ff4500ad00"
	"4fff5afe83012affb5ff18ff40010700a50150ffcafec0014d0016ff58fecf00"
	"04fea0ffa7feb6ff88fea6ff45ffdd00ea0012ff86002300c00166fffcffd801"
	"bcff6a01a6ffba004fff7c00fe00eb0012ff75ff50003b00d5ffccfee3009aff"
	"ff0051018200c2ff3fff48ff7efffdffee002500dfff7e005b0107ffc20054ff"
	"f9000800acffbdffb9feb8ff45ffd7ff91ff94fe91016a0097006a00350017ff"
	"69ff5c00740033ff32003a008aff4f006f0061003b00b9ff6eff05ffe8ff3fff"
	"a9fff800bbff5c0065ffd7feb90019fffdff8fff65feb9ffaefe8b00a8ffe400"
	"17ff6c00ee0090ffa700c2006dfec30058003eff17ff6d00f6005600abff18ff"
	"c9ffb0ff48fff7ffcaff25018a00140038ff5b005bff8f0037ffcc00a4ffdaff"
	"cdff880083ff2bffb1ffc3ffa700bd00a5004f004d014a002100970017fe7f00"
	"640104009dffddfecbffed0087ffc1003dfff20061ffa6ff380020001cff21ff"
	"a20102005effccfefafe7c00acfff2ffcd0033005f00b9ff6f01600015ffd4ff"
	"87ffdbffdbff34ffcaff620012ff4fffbaffe20064fefd0021007100b600a7ff"
	"5bfff0fff7ff51ff6100cb004dff6f0077fff90089ff7c00c3ff08ff79016b01"
	"1f017200ad0023013e00ae014b00a2ff8efffaff4bff50fe6c006cff85ff9bff"
	"4afffd000a006effe201070030fead00dd0033ffe9000efee200cc00bb0077ff"
	"ee0028001eff39ff4200b900b70019001e003dffcaffdcffd3ff5cffa300d7ff"
	"e8007400320036ffb00028fed0ffdf003afffd007efff10061fff50119ffd8ff"
	"8dfefb00b900f7ff94fef300cf00610059007700ad0085ffcfffcb009fff4e00"
	"e3005a01600034005cff93ff8eff0c0080ffe2014501200090fe76feb80105ff"
	"5d018a015fffc6ffbcff63ffce00aeffadff240018feeeffae01250055ffbf01"
	"00008b002a006fffb800d5ff1efe8dfff2ff870100012800d8ffd000d3ff7200"
	"0aff7aff3bff0900b000ff00ebffb8ff7c0016007200cafee80089ff7a00f8ff"
	"94ffe0ff2dfff3017bff85ff6c004f003affc100dbff22fef5001c0075ff7c00"
	"24ffacffee013c00deff3200280064007200e3ffa3ff77ffde006aff2a000401"
	"3000e80050ff690043ffa40164002f013000bd00abfeb6ffae012cff00ffd4ff"
	"ec003efff00143ffcbff89000a00bdff8200bafff7005e0097ff5b0146ffe1ff"
	"dc00a7ffc5ff38004affb5ff6dff7ffed4ffbc0031001c0026003d00a2000400"
	"9cff73ffdbfeeaffcdffb9008a002000410079009affe300a9ffb1fffaff7b00"
	"b7ff70ff6dff08ff03febcff9f002eff9601660045ffd2011a00540075006e00"
	"0bffd0ff870008ffbeffe8ff0700bd0084009d001bffd90068004e00ffff37ff"
	"d300e9fef5ff290003ffe000b0001affde003200ed0016ff6a0106ffb4ff7afe"
	"baff84ffebffea00a901630075ff11ff84001a0134ff96fffb0057007efeab00"
	"f9ffeb002c0063ffb4ffd50069ffaa005f00170020005600090048ffdc00e3ff"
	"000020005f0035008f0008ff59feef00a8ff630068ffb6007d00370026ff7d00"
	"240095ffbcffa4ffaaffe000940086ffb6ff9a003cffcf003200c5ff08ffe500"
	"2700eefe490018002d002300b200c8008aff5bff3bff07ff7000160043ff1500"
	"82ff2a00f1006a00f1001800280151ff1bfff7ffe30211ffc6ffbf0005ffd400"
	"a700ac005a0079001500f70020ffb8ffdeffa9ffb2ffc8005f00f3ff76fff5ff"
	"e2",

	"d6f42222c7d600a0168c614d04927d74c7dc3b3eeab9c97d18637f7d658c8e0e",
	"sample 2",
	"0a012d005500d3002700b0001cffc1ffe20005012800a9ffd8feda004a0047ff"
	"140040ffe1002700d7006d0088ffdefeb80043ffbe00acff56010d002d001600"
	"4a0048fffa004700b0ff99ff83009a00910058000bff81ff230033ff4500cc00"
	"7effa9ffb100b1ff7aff50ff62ffd4000dfebeff9fff5eff84015e00d1fee800"
	"160114ffe10269002efffffefeff45ffd30021ffeefe84ff6f00470029ffa0ff"
	"43ffed00590170ff530069ff9b010b00b3ff65ffe0fedb00c9ff89fffd0066ff"
	"faff4c00710001fed9ff870014ff89009effdb0059ffe9ff3000b9ff03002b00"
	"2c0016ffc7fece0110ffe0ffd3013c0040fe6d0029fedc0010fecb0000ffb8ff"
	"6cff760079015a0162fffbff6aff490116ffe70037ff79ffd60022ff0a010c00"
	"a8013500280014ff1fff96009fffdcff860026ffb600a300acff8b0032005eff"
	"a8ffea00ed0140ffc7009c006e01180040004eff43015700dcffa4ff3b0050ff"
	"c6004cffbc0075ff1200f2ffed007e00e100c10012007200b9ffd70013ff52ff"
	"ecfe80ff2dffed0061013afff2ff93ff72012c0051fec6fe78ffddffb4005aff"
	"6cffc2ff9d0026001d0024006a0023ffc2003cfff50018ffe4ff5dffafff6dff"
	"1effbbffc7010cff6aff3e00b9fee6ff4b002bffecffbd00d800fcfe2eff53ff"
	"db009ffefc00a1ff48ff56ff83ffb9004c000c0024003f01660056012a0013ff"
	"8e000400460025ff75000c001100e200fd0040fff5004f003a00d2002affbdfe"
	"b8ff32ffc9ff8d0178ff840091ffba0106006600a200080085ff3fff5900d600"
	"b701330032ff66ff980044005f0014ff5f009b00b40032ff570098fee3ffefff"
	"96ffebfefffef100acffa70109ff3effc50055ff41ff740090016500acffabff"
	"baff0b0077ffc700ef0076fe6eff94ff93002f006d0038febd00da01340184ff"
	"9b015fff66ff79003d0117ff6b00760013ff2700360064ff8700a10047002fff"
	"bbff6d00d0ff60006000e0fff9013b002300ea01c8010aff07002400d7ffe6ff"
	"df01030098ffa0ffdeff380001ff44003d002d007e003cffb1004800da006700"
	"9a008f008b003100170031000e0016ff8f00ff00a60063fff4ff9fffc9004d00"
	"640128013e002fffd800f00046000effb5008c005b002a00360063ffb7009c00"
	"5efffeff750021ffdaff78000cff16ffce00e4ffe7ffecff250078fffbfff500"
	"440015fed90009009f001e0067ff42ff7700cf00cb007f0024ffd9ffcfffe500"
	"99fe85fe6a0164007500320007011d0009ffd8ffdc004dffed00c30005005afe"
	"880038ffb500b6ff0bfffeff27ffc2ff90ff6800180043ffaa000cff2c0022ff"
	"9bffd8ff10ff9a0083ff50fffc007bffc900f90054fe860005ff8cffab0080ff"
	"7100adff5e00ed0069ff390140ff5800290065ffc7ffc00105fff200940040ff"
	"80ffb200c7007fff280020001b01bbff47ff9dffa800b30014ffb6fe3e0028ff"
	"d20077ff560069ffac00e9ffba0017fec0001300b2007800570161ffff0025ff"
	"6a01930037004d0040ffa0ff6f0040fff100670077ffdfff12ff430099ffaf00"
	"f7004e00c500010032fe8c015b0096ff08fed4ffe7ff9e009c0049fef5ffa8ff"
	"c0004900edffee0035001500a9015dff9d00dd0061ff82001100740098013500"
	"03ff85ffa3ffbb001d0165014b00c400f2ffb8ff5e0054fe63fff1ff90ffcb01"
	"0a00aaff36005b01feffdc002effa5007700a7ffc10059ffd7ff53ffbfff72ff"
	"caffb6ffac00bdffee0108ff9dffc900c0001c0123ff6900180073ffebff9300"
	"140021010f0002fe7fff7b00af004a001bffa7ff24ff3aff0cffd3fe7f003700"
	"0affd400b800d8003d00daffa700a5ffbcffb000a7ff7900980063ff7d004a00"
	"a3ffcc0007005c00acfedfffd60035fffc001f00feff5effc5011dff42008c01"
	"2cfea5ff97ff2d00b700c0fe2dff6e00cffe9d002e01760040ff98ffd400d200"
	"f9ffec0064ff3cffe2ff6900c200e5ffaeff80ffe9ffbfffa4ffd2ffa0ffc5ff"
	"c4ff84010000c900b9016a00ddffae00b30080fec9fefdffd60014012bffa8ff"
	"80ffb20051febb01130082000800b1ffd1fef700d5ff2efedc00b8004cffe3ff"
	"e0ff79004a00aa005aff8dff9d002ffed2ffbf0048003100af003200150029fe"
	"9e00e500150059ffc4ff750040ffb0ff63ffeeffffff6c00fd008400dcffe900"
	"92ff7fffec016d00ccff8aff8a00d7ff47ff210024012dfff90015006e0092ff"
	"a30097ff34006c002f0073ff3d0015008bfee1ff0bfe7eff040090ff8affd5ff"
	"b200a8ff70ffd3fed0015eff69ffa5ffc7fff3002effdc0096ffdf00a0ffd901"
	"00fff8ffb8ffca0036001cfed5012aff84ff80ffaf0078ffcaffd0ffd7ff7bff"
	"68ffa10022006bfffb011aff69000d005b006f00a20128ff9dff83ffbdffa100"
	"53ff47011f0060fefa001fff6dff6e0046ff94ff4d0180ff90004600ab0015ff"
	"faffe60065004c003bffb4ffb6ff98ffaeffed01b200aa00fdfee2ff73ffaaff"
	"be0081ffa6ff810012ffe1febbff89001a000eff60002700b20060fe5affcd00"
	"ff00acff1dffe100440081ff0500c700bf0090007400b20016ff8dffa10036ff"
	"6500fc0043ffb1ffaaff72011efe4200a500090136ff4bff6cffe9ff9cff6eff"
	"75fff000c3000a00d1ff85ff8d01d00130ff6fff0d0078009100f8fe690034ff"
	"dbff220086ff1dff59004b00da00c0ff37ffd8006400620100ffedfffd004eff"
	"a300ed0085002cfedfffcdff78001500c700a0ff6dff71ff6b00b4009f009401"
	"33011d009a007dff76005ffee701030017ffb10097006cff4e002c010fff9d01"
	"4e0054ffb6fe33008affb6feffff3000a900adff8cff1d00de005dffb0002501"
	"31",

	"67b099b366cf45c33e4b0b642d85f59f005333191606e3eee1a1b5a1d1f4d969",
	"sample 3",
	"0affcbfeee00dc00220058ffc0011effac00a000ff01290005008fff2fff51ff"
	"f801260067fefe006eff7efea9004aff87010fffe1009e0047fee60072ff93ff"
	"dbffb60022ffdaff75002600f100a900bcffb7ff43008eff5d0017fff4ff5100"
	"06feb6ffa2ff9a0136feb1ffd80165fff10050ff98009a004300dfffa1ffe9ff"
	"effffbffcdffd0001efff4ffb5001c00a9ff33ffeaffec00720117fea8ffb800"
	"6e00190031ffa8fe9d0101ffea002c0010ff16018d002dffa9ffa7fe38006401"
	"440058008e004b0083004effcf00a4ffd900940051007600abff9dffa6014200"
	"470006ffd1000d001b0031000fffbaffa1fe88007bffa3007cffdbff5900a6ff"
	"d601130082ff36ffb2ffe8ff23003dffbaff6fffba0094ffcb003600b3ff71ff"
	"8eff360001008800c6ffc20032011dffb60050ffe1ffedffb7ff4fffa7ff7000"
	"96fe43ff490019ffcdffa4002400360102ffc7ff0fff780024ff22002eff5701"
	"17004affa50145ffa6005effb3ffe00213ffdc000cffe8ff7b000c00cb000b00"
	"93009300d5ff0bffadfe8d002cffd5ff36ffb9ffde00c900ce00f50028ff87ff"
	"3effcdff9efee70016ff23ffceff2e01a9ff49006d0094ffb90051000cff9cff"
	"0d0067ffe4fede0128ff12ff90fffa00c0fff0ff22ff33004efec800deff6500"
	"eaff8b001ffff5010b002dff900104010a002b007effed000b00130022ffcc01"
	"31ffc1ffcfffc4ffc7007700e6ffe0ffd800350042fffb0051ff93ff8afff8ff"
	"4c0179ff08ffb9fff600acffd7001cffe4fff8feb70037ff79ffebfef5ffd6ff"
	"f0ff9e01c90052004bffc501630085ffddffd800a7fec1ffb0ffac0058ff25ff"
	"f8ff50ffb10085ff4efff60091ffbaff77009bff9f00af002900daffe6009dff"
	"ceff7bffdfff330055ff7c0046ff750124005b00db00db001e0053ffd9fff800"
	"230012ff70ff68001e00e0ffb4ff360088ffb20036fff5ff05ff50ff94ffdffe"
	"93fec0000dff5affc7004d00c30038fef700dafff6ffca002600a60022ffe600"
	"e70168ffa8fffaff0cffe5ffedff24007400140075ff380049ff14008dff1a02"
	"010083008cffd80061ffb0fea7fe7800f6ffb1fee5018e0031ffd8ffde005200"
	"77ffe400600021ffeaffec0131ff540076004eff94002c003eff310050ff60ff"
	"4c009cfffb0052014aff0c00e000bbff8c00710052005fffe8ff48ffc8009dff"
	"aeff3a00850030ff1eff6500c00067ffe0ffbb01d9ffe6006cff4f0089ff22ff"
	"f4ffd7ff54ffb7ff80ff53005d0083006efff3002eff1a00680011ff73ff99ff"
	"66001600dc004b005c00b600640040ff9dfebaff300111ff60ffc600dd0040ff"
	"2d00a0ff9b00540026ff350011fe8200e20105fff0007d011a000a01ac00a5ff"
	"3400340098fef80080feec00560080008600b7ff9fff7b00f7000b00b2ffacff"
	"c8005b013aff5f009a00c3002dffd5fecc0177ff7c00ac004bfe500012000201"
	"0a009afec90052009affa900980089ff74ff39ff1cffb50000004effc4ff2eff"
	"50ffd500f101beff4500950066ff8d00e8ff7f00320229ffdfffbeffdd001200"
	"ebfef200760117ffed00f40032001effbbffe1ffeb00130079ffdeff73ff5aff"
	"ba00790032ffd7007900c0fedd01bb00c8002cffb5000b0080ffc2ff4500baff"
	"3ffed10017ffbb010600edff6dff34ffcc005a008dffc8014cffbc005f0128ff"
	"b2ff6d0096ff9600a200730036ff62007dffbcffc500d5ffafffca00a9009900"
	"55ffffffd100410024017d0085001000ffff6f002aff86ff870031fec9000001"
	"420024ffa200a3febdff14ff76fffdffe1ff73fea4ffbe001b0086ff41000d00"
	"34001d0050ff95001bff7ffedfff9aff40ffe300360059fffd002affa7ffe900"
	"44fef2ffda0079ff2f004200700060ffbefebafeb8fe6500e5fff9001b006400"
	"dbff8efee600ba0100ff230010fe7900a700410036ff0700ea0098006300ebff"
	"b800ff0007002c006c0108fe5500f1ff470059ff84003e008e00e4ffc2ff6eff"
	"9fffadffd9ffa70034ffe60034ffcc00fb002bff55000dffc9000effee004e01"
	"21ffb201d8ffd9ffb9002fff15fed3ffbc0040009dff7e0050ffd0ff06003e00"
	"1400150010ff13006cffa4001cfefe00d5ffda00af0041ff9501440154ffbeff"
	"a7feb701ab00edffe5ff9d00b5ff640021ff6e00b8ffb700a9000cff040067ff"
	"69ffd20109016f0085ffbf0133ffbb000700a1ffc9ff82ffa8001a000a0115fe"
	"f4005dffd8007d0047ff370051ffcd003800a3ff540160ff4aff8300cc00a9ff"
	"ff002dff7aff870008fff5ff93ff67fff40022ff350110ffd40083ffd9ff2501"
	"28ffe700a0ff6affbdffca008dff38ff49ffaa008dff2affff0048ff25000a00"
	"9cff40fff1ff9d0072fd76ffdeff37000fff660008ffe7ff7d00250014ffb3ff"
	"84ff63ffd8ffe8016dff380094007dffae00450082ffeeffd2ff91ffd0012700"
	"06ff4300e1000cff22ff9b0037005e00dfffbd004000e2ffab0090fff600f500"
	"dcffd1ffd0ffddff3bffd30094ff5a0063ff9fff4c00970020ffe3ff2dfff500"
	"fbff8cff74ff35ff9ffffaff8a00a7fffaffc1ff540003ffcbff690056ffdf00"
	"780050ff50008400abff4600d1005eff81fffd007a0007ff9600af0029fff5ff"
	"18ff8affb90052ff1900010015fe61ffd6ff19fffdffdb0070ff7cff46fff1ff"
	"deffdbffee0041010cff36ff91004f0079ff6cffe10091ffedff9d002a00b200"
	"afffbf000cff9a0151ff72ff7a00f4ff4effdd007eff9100a80011ff9b00c1ff"
	"21ffa7ffc90096ff6dffb4ffd000a2ffa2ffd10068ffd200600120ff1aff0eff"
	"71012d003a007e005f00bf0008008d00420051ff500057ffde0099fffb013300"
	"85",

	"036f0921b89631213dc33f05707a0a3fece5aa9e507f6646b6f8443c27ccc843",
	"sample 4",
	"0a0051ff8c003fff05008bffa30078000eff18ffc000560016001500daffeb00"
	"60ff5effa6014900bc007affb600aaffe00013feff01130055ffa2004700cb00"
	"5f0003004000cd001a002b0092008d014bfed800c9ff2cffa3fef901c1014d00"
	"6efeb4ffa9fff701310072fffbffc0ff62ffea002e003d01400029fff3ffab00"
	"ee00730069ffedfeed0061ff69ff4d00f7ff30ffda0017ff600014009f00d5ff"
	"d0fff000b6ffe8ffefffee00290005ffc4fffcff9b00bf00bcff41ff8eff7aff"
	"b5ff97ff59ff36ffbd007effeefeb8005e0017ffcb003dffc801dc0096fed2ff"
	"3eff4effad0021ffbd00baffeb0070ffee007dff79fff6009b007dffc6ff77ff"
	"f3ff7afe2500a1012effabffc8ff95ffe3ff79004d0060000900c3ff4bff4f00"
	"0aff20ffc8ff4f004cfff900c0ff9a00280037ff3bff18ff7b0050ff2b0189ff"
	"8cff2c003d0026ff53006aff180042008dffbd007bff56008c00f9ff15fed6ff"
	"3f011afffc005effcbffc2ff30ffaeff65ff3dfff1ffabfffdff1dff870041fe"
	"a00095ff5bffee009200c400c6ffbaffd400b9ff4d00a9007500c70010fffb00"
	"4b0121ffdb009d006000c8ff5100a4ff02ffbd00bf006e0120015f00910051fe"
	"8d012a00f0ff0fffe1ff3d00a300deffbbff780044009e00670189002b0001ff"
	"65ff520093ff9f00bbffe6ff71002cff15fec000cf0086005cfef20084ff9cfe"
	"adffd4003400ff01080016ff98007700a8ff96001f00740126ff4700e2003600"
	"28000c01170007007b0020ff88000100e9ff820005ffdcff4fff650062010100"
	"5200a2fffeffb0ff3affbf0051ffd2ffba00b5ffe6fff20078fffcffb20088fe"
	"b100550068002f00ebff32ff25005b00300025fe4500ac00120004ff950095ff"
	"8c0021ff8aff2b0067009c0003010c00f4000afff100610088ffec00e900fd01"
	"9c00c1feec013b0059003cff22feccff16005600ce0069005400f600bb000301"
	"11ffb9fe5bff6901850089008fffdb0138000d004dff5bffdd00a4ff59ff9efe"
	"6300720197004e003600780130ffb000170172ffb40078ff8cffd8ffeaff9c00"
	"0c0049ff62ff0400590048fefc0081ff87ff6600ec002500a6005e0197ff3e00"
	"7fff87ffe9ff45008dffe600a600a5ffd800fb009aff7d00180115fea5007300"
	"9f0019ff22ffceff200030ff3200a6ffaaff5bff7dff54ff03ff6200db0093ff"
	"2fff94ffceff87ffda00ad002a009200ca0182ffb0fff6ff8d015000c100fdff"
	"20ff34ff45ff0dfef7018600900019007bffb5ffe8ff8a002bffb700e5ffebfe"
	"c8ff8a00e4ff7c00150013000d0092ffc6000b009dff9aff47ff1c00a3005d00"
	"0dffcc0090ffcafe9f0058ff6d0027002dff9000d20027ffd9ff5b0119fedafe"
	"be006500e80129fea2ffb300b60169fffeffc100510058ff190055001bff9bff"
	"cdff81ff820101ff00ffd80136ff7effa8ffeafe8bff340096ff7bffba00f1ff"
	"75008a00bc007fff5cffcf0060ff3e00280110008200e9ff7b005200c1ffbfff"
	"f800d90049fef0ff9e0155ff79ffb9ff72ff27ff4f00160003ffd600caffbaff"
	"9effd3005b000e00380009ff1b0198fffa00feff3c007fff42fff9ffd7ff80fe"
	"a3003bff2bff2400cdfefa003bff8f00220026005e00b1ffc7ffeafeceffe401"
	"16002b0027ffa1ff8bffa2ffc2fec4001dfefcff8600c100b50049001fff6800"
	"0600dffeec0116ff4dffc6ff95ff20ffedff5effd0004d00360035000cffc7ff"
	"42006700f9ff69ffec015e0088ffadff41ffda001bfffeff86ffa20031ffa900"
	"23ff9efe5f010d00a5011300b1000d0056ffffff59ff11001d0003006e00d0fe"
	"edff4cff76ffefff26ff83013800b8ffdbffc7ff71feed00ff006200d8002400"
	"690017001100b5fff600fcff230073ff4800a300e60035ffd3ffae0030011301"
	"16ff59ffa2ff45001d00590014ff2b00ebff66003fff4a007900e6ff81018700"
	"1dfff4fedc00dafefdffe1fef500f9ff8ffff700c90088ffb4009d008effc5ff"
	"07ff71ff7affb30001fff500c5ff4e00050025003cffad00c3ff28fef10035ff"
	"f4ff78fffcff5c0002001aff0b00c100a400d1012dffbf001afefd0008ffacff"
	"3ffeb1ff1affad00dafff6ff94003c00bbff4401360037ff88ffb4007b004300"
	"05ff1c0095ff2f0040007b00f2005500b6ffd6fe7e0068fe73ffb5ffd000b700"
	"3fff5efff0fe98002700a2ffe6fffb00bb0167ff0200b5002800fb027a0048ff"
	"55ff950008007cff91ffabff1a000aff9bfe5100d8001f004400abffda002cff"
	"c600d5ff35001bff9d005bffb3ffcdff9ffffc001f00bc0136ffffff2cff2201"
	"6cff77ffc1ff99007800830027002cff0d00b1006fff43ff76003e012b00c700"
	"0eff32ffd300c6ff7effaaffbcff23ff6fff0f0007008800bc0044fea8ff1400"
	"c10058ff6dfff500b8016200ebff930063ff2d0078ff9dff5bff9d011cff9a00"
	"e60073ffd7ff59ffd40038007efee4ff22ffb80059ff80ffe8003f0093002600"
	"6600c2ffa3fea3002cff2dff650026ff8f0137004300fdff60015f0056ff8900"
	"c90037007700ca005ffee00008ff8e0097ffd0ff6bff6500d9ffccff69ff69ff"
	"bd00040048ff3400b5018a0099ff9cffe0ff4dffc2ffe3ff89ff65ff7d007e00"
	"7200b90094ff560061ffe4ffdd005e004000a6ffc600e6018900180009fe8800"
	"f9008d0092001f00d8007ffff001120001009fff99ff18003fff49ffd1ff68ff"
	"ae0059ffffffbfff5dffb0ff62ffc5fe83003e0083ffe9ffe200c5007300bbff"
	"ac004400a5ffd2fe680064008dffc1002a001500b6001affbeff82ffa401d500"
	"06fff40077ffe3000d006eff6cfff3ffe100cdfef0003f004e012ffefb0058ff"
	"fa",

	"7cf467172d3c90505ee0ca12051777b73954d6ed8c82515ba2e4e6098f4d9cb3",
	"sample 5",
	"0affb4ff43fffeff7afff7ffc800b5ff74023000490021fed0ff1f0099ffcfff"
	"05ff28ff90fffc013dff9fffd4ffaa00fcfecf0008fffbff9bfe33000300b200"
	"bbff2b00f50082000afe9f011500a3ff6fff640091ffaa008a0009fef1ffbb00"
	"25ffca001b0024ff99003b0036ffc4009ffe76ff85fed80066ff7e00e5005000"
	"4800defecfffc40069ffb8fea9001bff24ffa9ff3a0045ff0d0013ffccff83ff"
	"1d002dff9e01db002100d30061ff2c003dff780150ff19ff8a00b100750013fe"
	"3b0105ffda008cffb3ff93ff1c0058ff93ff1cffc10043ff910043ffa7ffecff"
	"5dff5f001cffb3ff540056ff5afee7ff01005500940030ff70ffd300a4fff500"
	"16ff39ff9dff6e00a8000300d1007900a1002cffe3008e01000063000effa700"
	"40003a00b50063feb4002a0055ff5fffc4018c01250082fec50075ffccff1bff"
	"f7fffe009fffcd001cffb8003e007900df00dd00f50015ff0c00130052002000"
	"7dff750016ff5cffb400a4fe13ff640004fff700fa0017ffde000dff68ffbb00"
	"c90107002d00ea01cc009c00a5ff9cffd4003bffa8005effdefffcff9eff6aff"
	"7200440116ff0b00e10114ff65006bff86003cff57fff5ff9a00a3006dffb7ff"
	"effeed002700200158fff9ff7afee20032002ffef8ff2c0003ff2d003dffc100"
	"a4ffc9009f007bfff5ffd400ecffa6ff79ffedffa000eeff52ffb0ffe5ffbb01"
	"60002c01a5fff3017cfee5ffa6ff96004aff6a0041000cffe9ff6b002e00d400"
	"35fff30084ff6eff7effb2fffd009a0071ff270046009b00baff8cff6701e5ff"
	"eeffee0109ffbefe8affa6ff2b004d00930032001a00fb0080ff39000f008500"
	"a8ffd6001c00670096ffa7fe90ffb90098ff02005100c900350051ffc4ffb800"
	"9affd7005400520015ffd000cc00bb0044008effbaff510001ffcdffc100ce01"
	"58ff210079fef7fee1fee100a9000100960150ffc100d3006a00390090ffbdff"
	"22007000a5ff8a009eff58ffca006500b7ffe90058ffedff450076ff0700d300"
	"f7fffc003bffe0ff0cfee1fff5fe66feb0ff96ff02ffd000b7ff4f0071ffcc00"
	"090054ffa5ff97000c01c9007c00f400abffee0038ffd4fffbff2bffd80034ff"
	"ab01bd00a300b500e1ff9d0025feffff58ff89ffe0fe7bffb3ff42feaefef800"
	"6dffa3ff93ffd4feeffff500650095ffc3ffb7ffa00049007dff9c002aff7fff"
	"fbff540020ffb30064fffaffed00edffc1006fffe1ffd10012ff1fff9b0028ff"
	"f00057ff5cffbf00cdff8d0043ffd900c0ff7fff87feb80074ff46006f006a00"
	"73004fffd3ffbcffb7ff2401ba001f01d2fff00011003aff68ff74013cff51ff"
	"e800f800310034ff9fff1f0031ff2c012700d700a20093ffc4000000300055ff"
	"ac00e60079ffd5ff13ff4efe6e00c50128fff0ffbdff82002100560021ffa6ff"
	"9b00020008fff1008d00bc005cfe4c0055fecdff05007bffaf003affcffeaf00"
	"10ffa0ffafffa7002d004e008600ffffe9ffd30036006a0034004cff34ff90ff"
	"2e003fff78fff0008ffffbfed90075ffbe00a500990047ffcf000dff8bff77ff"
	"9dffd7007200800080ff6800f1ffc3002efffa0023ffb2ff650113ff9a003601"
	"0aff7effb5ffe7ffccff8b00db002bff56ffd400b3ffda008900ba0052fffbff"
	"710012ff7d0034ff9200f5ff5100b7ff0fffeefed3ffce00ff00fd002b0083ff"
	"98ffed00790082fedc0093003fffedffa2ff8b002dfffbff4800260089ffe5ff"
	"71fec6ffd6ffa90082002800dbff6ffef3ffac0025ffa30088ff180054ffc900"
	"62002d0054fff700e2fea30026ff29010f00cbff920032ff8f00b0fef4fff1ff"
	"c0ffaefe9a0079ff64ff81000a00a9000cff60fff3002dfffa007d00340032fe"
	"930008fff6ff1cff530150ff9c005cff66007101e5004afeccff6dfd9f00b500"
	"84ff89003aff33ff8b008dfecf019f008aff1fffacff75fec201e30050ff6fff"
	"f5fec300c700e2fed9ffe8ff84001800c6023000a30030ffe40010ff6300c900"
	"4f001dff5300b1006300a6ffd80099ffd50127ffae0050ff650086006b0046ff"
	"32002a001400e1ff990048ff41001bff5600590011017eff99ffe5ffd3fe6f00"
	"73fdf3002d005cff2b006a010d002cff7cfe7cffc4ff56ff940042ffa1ffd9ff"
	"6f001efef1feed003900610029ff520050ffd4001cffd700c9004eff70ff5400"
	"20008e007aff51ffbf009dff35feb9ffb7011f009f00d300e200a3ffe6ff5600"
	"e8fe82fed7ffa6ffea01ee008dfefe001b005500beffac005efff9ffdbffe2ff"
	"72ff1e0009ff690034fedbff9700920090013c00a400650055fed8ff92ff38ff"
	"edffaafdf8ffae013d0019001ffff40076ffc0000800fbffd6ff1500f400bfff"
	"71ffb5001f0076ffd9ffd1ff8fff660121ff92007bff37006ffffbffab00ce00"
	"70ff2b00bdff16ff3c0086ff45ff69fdc1ff9800830089ffa4ff4700c8ff8b00"
	"6f00d7ff49ff32ff33fea9ff74006e0089ffaeff7300c0ff36ffabffb7ffc2ff"
	"9bffd3ffd1fed101370161feebfff9001bfff9ffd3ff9f00590007fff0002eff"
	"4e0124ffec0016ffc8003bffbb006200dd00c6ffd6009fffd3fddeff2dff4eff"
	"d2ff8affc40128002a00c3ffac0084ff40016b00800087001e0042ffb000c7ff"
	"0b017cff1cfffbff9c0045ff31005ffff8fff10136012affec0068001aff88ff"
	"d5fffeffd3ffe2001bffaeff78ff750135ff7e00bcff39ffbbffdefeecfff9fe"
	"95ff57ff73fe480013ff610063ff220054ff0cffa7ff7200a2ffebffebffc700"
	"2c000d006affbfff3f00d500660023fed1ffe2ff94ff09ff1900860010ffd001"
	"5effe800760038ff7a0097000800c6ffeb001dffdffffbffdeff4b004c004cff"
	"de",

	"acc78539c8b82aa74f435eab9a974b55b80b4258bf480c103a7e6575e31ec822",
	"sample 6",
	"0affaffee8ff30ff720158008400ccffbdff960148ffee00abff4bff8f00e100"
	"5afea10046001900390053009c015200d0013200d6fffa0031febe000b00d601"
	"13ff2200b600d4ff5bfebb00c3ff56ff55ffecfffdffef005bff650089000eff"
	"cafff6002000daff31ff68ff6b0026000fffda0066ff05ff820083ffb50026ff"
	"40ff2600cbfff200c6ff02fff1ffb2000500d6ff670092ff54000b01180105ff"
	"9cff65ff9b00d700b00068ff43ffdbffe6003efefc0070ffc9ff7affda004600"
	"42007eff9600fbfeabfe66feddffb6004c0017ffe7001ffffe009301040021ff"
	"3d0084000c0161006ffe9c00db0026ffd8003d00e9fee70103006d00bc0027ff"
	"5500faff8efe9e00670052ff2fff36003bffce004affe2000d00db0004003700"
	"9aff9affd100b1fe73ffd1ffa6fffd00aeff43ffdaff44005a00b9ff9f00f000"
	"7ffea500bfff9e00bfff9f0033fee9fec8006d005000a4004200d5ffa6ffc400"
	"64005e0010002f000e0035ffc8010fff9a00c700670005004eff84ff82ff5b00"
	"c500a6003cff880032ff4f0036ffccfffb00680047ff2b002c007500cbffa400"
	"b10048feb7ff710002fed4ff91fead0019ffe5ffa5fe9b00f0ffdeff6f00bd00"
	"74ff07ff91ffb3004200b0ff8dff6d001ffefa008e0013ffaf003500a600cf00"
	"73ffbefff800b9ff54ffb50016ffa7ffad00410045fec8006e01e00189001600"
	"850034ffd0fffcffd2002e0074ff6dff9c00ed00c200e1002f0061ffefffe200"
	"58ff92ffa9012cffc70036ffadfeed0023fed0ffb5002f005100c5ff16015700"
	"d4ffbdff6d00850012ffe7ff0800a6ffc9ff33ffcdff24ffc0ff7e002cfe7c01"
	"240090fffdff4f00a1ff000065004000160090ff75ffbfffc3ff00014800faff"
	"690047006affeeff8affe8ff65ffc900140061ff0c0030ffc7ffc7ffb4ff7c00"
	"7b00ee00d4ff54ff800044ff8400ac007d0014006400130018ff0e00a000f800"
	"89008000610016fe41fff70081ff9fff92014fff82001601200035ff3200b100"
	"860108012f00d601d3ff490069ffc7ffaafed7008dffe200270048ff48fffaff"
	"5d003e00a4000affd0ffe0006eff7c00e60088ffab002bff3c0080005dffaaff"
	"e3ff47ff780134015000fafebb00310014ff1c0006ff900070010dffc6ff6300"
	"830167ffc1ffa2ffd8ff81ffd7ff8f00d100d5fe2fff47ffc2fecc0077ff83ff"
	"7bff6000230107ff8fffecffbc002b00aeffe6ffb400fd00beff05ff090045ff"
	"c7ff920005ffbeff6200fcff94ff1400a2004affc9ffe4ff14fe91ff0fff6b00"
	"01ff3dff64ffd70009ff7d02380004008f002000e0001f007bff5eff02ff2e00"
	"5bff8affca00cd0047002a0109ffcdfffaffc300a5008c0032ff9e0074000dfe"
	"f4ffaeffb3005bff61fec40074ff27feda0117ff4900a6fe3d005000080018ff"
	"d6feb200970082002800bb0015ffb900fdff7bff94ff68ffecffbeff3901d9ff"
	"d2ff85ff8bff540003ffceffa3ffa1fee00031ffd100a3007bffc10013ffee00"
	"39fe5500c30034008affb4fe45fffeff5b000fff86ffd600ad013e00a4ff7eff"
	"e200330049ffb4ff9fff3bfff2ff22006eff930019ff2c0045ffa7009eff4800"
	"7b00cc014400c6ffdc007e000b008d00b700bc0035ffc0ff57ffc8ff58ffee00"
	"d7fff0ffb200d9ff28ffc20011ffae0003fffc00edffd1fed2005ffffb00e900"
	"3f0086ff3900110101005f00350014000a00ab0098fff3fe20008b00b8ffe000"
	"bcfeef005200adffd0ffc7ffb7fff301a900d2003dfff5ffd80095ff2b0037ff"
	"a90045ffa3fe6800b80003ffa6ff31fff9ffa6ff1300b8ff80014cffedff9500"
	"0bff2cfeecffaaff60ffd2fea0fff3ffff001aff5f00610068ffbcfef90061ff"
	"70ffb500a1ff1c0110ff6b005f00b10195ff94ffa4ff8effe5007b00a4ff68ff"
	"9800b0009800a500d0ff74006bff5cff47ff82ff16ffcfff3a01b5fee6fff0fd"
	"e7fffe003400070006ffcb00b6009d001f0086fdebfff3ffc3ff6b0129ff3b00"
	"7f00f6ff9cfe3bff8a0003ff7a0062007effddffb90091ffe0ff9afe30007e00"
	"18ff550064ff22000100cffff9fff1ff440047ffe0ff91004f0027ff4b003d00"
	"ee00040118000aff2ffebb007500dbff140027ffdc0018ff86fe5a0061002400"
	"8dffaa008500ce001fffe2ff5dff9ffe7aff6f0012fffd00360041ffb0ff6100"
	"66ffd00041002c017eff79ff44ff1b007f0034fff40036ff9700860083ff1601"
	"1d00a10024011dff6b00c5ffa8ff36008eff92009c00c8ffb400550048001fff"
	"d0ffabfff0ffc9ff0e0053ffd1ffd0ffd2ff6dffac00500059ffa600b8ff42ff"
	"d200daff9d003b00b3ffe3ff89005eff0cff3fff31fefaffcbfffdff90011aff"
	"d000ea0088ffd0ff02004a0031ffa00077005cff00000d0082ffbd006affb5ff"
	"b6ff9a000dff58004efe570034ff90004b0103ff6f013d005cff79ffdcff1100"
	"22ffe90088ff5a00770108ff76006e01a20018fdd600870021005effa5002600"
	"bb0096fff1ff91002f0103002f00140038001cffaf0120ffee0024ff8f013cff"
	"bdffc9006bff67ff76ff5cffb80076fff4ff8cffbafee3006aff21004a0058fe"
	"ae0051ffeeff5fffdc00e5fe03fef40004ffdc00940018005d0045ffb6000400"
	"b3ffaaffc7007300e4ffa6ff14ffb20052ff6aff6d0045ff91001afefbffc4ff"
	"ca0030ff92ffc70043ff8700b7003dfed20067ff18ffcbffa300a100910045ff"
	"2cff4c004dfff5ff9900ac008c001800ee003f000c0101008d008b00240095ff"
	"c2ff380098007bff550127fe710086ffdcfffa005001150010005afe90011bff"
	"5eff69ffd9012effc5ff07fffbffc60091ff5fff75ffd200d1007afffeff8f00"
	"53",

	"519bf3fa8785ccb4b95f2ef0d3f0168245218323450be56a4a5660b9fe097d27",
	"sample 7",
	"0affc1ff420024fec7000bfea1004e00560023fff40121005eff45ffdbffeaff"
	"32ff100024ffaffe8affff012fff4dffe600a0ff6d0016ff6aff24ff1cffc200"
	"2ffebdffe2ffbc012eff45ff95fee7009dfec7ff0b00b9ff24ff03014f0070ff"
	"f3ffc10053ff8cff8800fa007a0004ff5300bf002aff41ffbc00590009004dff"
	"45ffea004efec6007eff8a011201740091ff850121002b018a00050016ff00fe"
	"650055002cffa9febe002bff84ff570105ff9f002f00d6007e00780057fedfff"
	"020033ff14ffdafff0fee0ff83ff5b0009002c00cdff99ffa9ffceff8f000600"
	"bb000a006bffa500ed00a0ffd600bbff3e005501bb0054ffaf00ecff92ff23ff"
	"ecff9600bdff26fe72fed3ffd00051ffb300030070ff60fff5ffef0052004100"
	"900151002bff97007dfff5ff5c0024ff7eff90ff58ff900138001c000cffec00"
	"7b016700dc00ca0034ffce0163ffe6ffc3ff400019008f0063ffaa00f700a400"
	"b7ffc70035ff6a006bfedfff0dff69fff5007e006000c10007ff60ff9100c7ff"
	"a2fff200ccffa80073ffcfffdd00e40000003a006300c4002d009ffee8ff2bff"
	"b3fff8fefb012100e2ffc800ef007dff05000affbaff3000b5ff52ff17feceff"
	"beff85ffadff65008bff4affdaff8bfee0ff270014ffb90141ffb5ff21004900"
	"8f004d002cfedfff86fed80011ffecff42ffc300bcff44ffd800a0fee5ffd6ff"
	"fcffb3fffa0005ff650091009bfef1ff61ff170023ff83ff4800d5ffc1ffe800"
	"45ff20ff9800b9ff7e012fff7100e1ff4bfff7fefcffb1ffd0ffbe0035ffd8ff"
	"9700a6ffbeff62fff900a2ff2f008eff3a00090084ffb30021ffefff6bff7200"
	"49ff3f0009001cffe1ffc0ff3ffea5ffa2ff30ff15ff6b0047ff6c00deffefff"
	"2bffaa0022fff100f2004d00cdffcdff91ff6c00a200a30030ffca002dff8100"
	"49ffe2ff550149ff3e0050ff20ff17002400700103000fff57ffd7ffe300af00"
	"810154ffd9ff2000a8ffbc00310041009dfee1ff0b011dfed70012ffbb0041ff"
	"b7ff2e001e006fffd700cffea7fffe00ccffda00440063ff3cff03ffcb003900"
	"c300f400b5fec1ff78ffdb007500b3ff9f0012ff8bffc80089ff51ff76004aff"
	"0eff7eff1e001e009d004a006affa8fff10093ff97febb0075ffdaffbc0095ff"
	"f0ff7cffa80027ffa1005e00150052fee4001a00380018ff6800fd0095007f00"
	"89ff94ff98009cffb1ffc6ffe60059ff2affb1ff45ffb20178fecfff39ffb0ff"
	"49ffd4ff30001001bc00caffff002efe70ffdefea80048ff6d004effc8ff4300"
	"9c0157ffa700c9ff660087003000c1ffa30099ff63ffb9008ffec3fefdfecaff"
	"3c0078fff3000bffac000d00610002ffec006400150066ffd700f6ff74ffbeff"
	"c30015ff8a009dffc9ffb800ed00cbffcfff3d003500d4ff920058007e005900"
	"a9ffd4ffb800a1001600b5001b000dff740137000fffa10002ff540023008fff"
	"6b0082000affc50039fefd00bffeddfff7004800a1001e00e70019ff5b0068ff"
	"d0ffe9ffe7000c003dff86ffa8fedb0050004a0011002afe7affcefe7d002bff"
	"b9ff6800b1ff47ffd10167ffe0ff0eff620095ffe3ff5afe10ffdd0074015600"
	"5900890111ffe8ff23ff80ffeeffd7ffc9ffdb000a00ae000c003b00e7ffc1ff"
	"b300afff9aff4affbbff70006501580044ff9a006a005affbdff8dff4cffadff"
	"aeffbcff91ff4b010500ddfff7015f0004ffbbff7f000fffbd018dfeedff1b00"
	"a7fef9ff93ffeefe40003bffc90013ff99ffc400ddff41feac0085ff9c009bff"
	"2fffc90007ff5301b90021000c000fff6cfe2effd30020002b004dfedafff100"
	"4700c100aeffad00c6ff50ff9300370095015eff25005dffebff1cfff900b600"
	"11ff08004800c1004a00a1002e0015fef9ffffff7bffdf005100090056ff5dff"
	"11ff76fe6aff60fff5ff76007600d600080030ff7b00d8ffef008fff00ffebff"
	"37ff5f0046002fff85003f00b0fdd5ffb9010b0057ff6cff41fea800bb005bff"
	"11ffa10033002500190014007b00810075ffca00970048009d0115fff9ffceff"
	"040040008dff6f003e000a00c700e5ffb2fe8100080037ffd8ffddffc3ffcb00"
	"10ff530010007400d70058003cff980032ffc9ffd8ff540081ffb20047ffeefe"
	"f2ff310064005a0072ff86ff9d006eff4eff59fead00e400b2feca01a0ff83ff"
	"20002b004ffff10078004600c6ffa90078fff20008fee1ff8c0072002ffeb5ff"
	"e5ffe3ff7c0079ffdc012d0019fffbff5bffacff60ffa000690082fff9fe6afe"
	"d7ff95008e002dffac009bffe90092ffb8ff4e0042fefeff9c006201b60112fe"
	"da01950035feaf00a9006e00b8fe14ffa40095004aff4100d7001700ed012000"
	"710026fefdff750049010bff5cff32009500040027009dff3a0051ff3cff94ff"
	"fffee3ffceff60000fff7effa20018008bff7a007a0033ffbb011dfee2fff1fe"
	"ad002e00840105ff3bff66ff7e008dfed5fffd00affe79010701740015ff8e00"
	"f2002200640024feccfff500da0049fffdffa200c00058003dffccffc0ff3300"
	"90ff5000cdff72ff9cff3fffb90020ffcaffe300f70075ff6bff98ff4700a700"
	"20007f00b7ff8bff3b01020099ffe0ff5800bc006affda000fff4a0077ff9aff"
	"b7ffe800d6fffb0064009a0021fffbff83ffc30023ff2c017900380051ff9bfe"
	"af006a007c007200c100ca006cffa8ff9e00890006ffe2fed6009d011d010300"
	"47002dffbbff10ffcefeb7009400a4002cff9a004b00d0000b00fdff7affc401"
	"3e0024008fffc3003200090093ffcbff8a0049fffa0053ff9effd10093010eff"
	"57ff88005e00f3009a0158ff3dff9000050064ffb6005d0027ffc700a6ffe900"
	"2e",

	"b4c3bb96b3614ca047ee15ce94f3ecce0f0451dfb00877611170e56017e76269",
	"sample 8",
	"0a0077ffcb00020072ffc2007400c4fea600ec002c00280076002e0075000c00"
	"45fffe00c5ffc2ffdeff9b001fff6600dfff0900e6ffae011d005dff840022ff"
	"36ffb1ff97ffd5ff0dff9f00a0ff6200b00070ffbcffab0055002dfeac002100"
	"9a001f0095ffdf00c2ff2bff5d00f7ffde0003fff00100ffbc008900a2008700"
	"290165fef6ffa400a5ff18ffcb006c00af001b0089ff99ffccff9f012700c1ff"
	"aa0074ff9affcdfeecffd9fe64003a000aff840085005c00cc0039ff4fffd9ff"
	"c900a50144fee700db00a900d1015b003bffbfff80fff0ff2eff0f0033000901"
	"60006bffbbffd5001400ffffec0000fef5000100050033007aff90feaeff0f00"
	"47ff320028ffbb00d2ff9c003300bc00e3ffd200060061fe5d00f2ffa6ff8a00"
	"3eff9affa6fff9ff6aff270037000cff94ff87000e0040ff8eff16000c006900"
	"7fffb2ff2b00b8fef8000f007dff3c003f00780028000cffe00079fe66ffd500"
	"1eff40fe1fffc50107ffc7008cfe54ffe4ffcd006c0084ff49006fffe5ff6700"
	"24fef000a4ffe0ff90fed00051fec8ffc2fff30017ff1affd10097ffe6ffbb00"
	"afff8b00870046ff050011008efe9e003ffffdff75ff5bffbefff9ffb100c3ff"
	"db004dfeb800270001ff5d006700fb010cffe700aeff990060002eff0900a1fe"
	"63fff600c3ff130043009b0177ff4d0024ff50ff45ffafff72fef2fe8fffe7ff"
	"c600d7ffb000c20031ffcaffbe002e010bfffbff1e0082fef2fff6ff460031ff"
	"650087ff520093011400b600de0007000eff4aff30ffea00540083008fffb000"
	"9300b80057018dff1bffdeffda00c6ff87005eff3dfed7ffc90093ff67ff09ff"
	"69001c00e0004cff93007affe0ffaeffe4ff140042ffb6ff0f006f00690057ff"
	"d0fecafff4ff38fe2f003fffa800930033fed3ffa0ffcaffcd00060032008fff"
	"67ffebffa6ffdcffc2ff87000bff1dff9800f900a6ff2400d6fffa0050fecbff"
	"74ff86003a010400ddfe5cffbc006a00cf003c0029fffa00dc0075003f000e00"
	"54ffa0ffbf010effbeff1dff480002ff87ffaeff3a00c8ffb6ff92008eff8500"
	"96ffaaffe8ff95ff47001200fe01020084fea4ffd0fe8a00c0009f0079ffefff"
	"4a00efffc7ff5efeecfe9cffba015a0030ff2bffbd0005fffbffefffd30072fe"
	"b2ffc100bfffd6ff76008f0065ff55012a003b00aaffc7fee1ffb2feaaff2eff"
	"7f00c5fff00044ff7cff9e00a90034006bff48ffff00e700610036fea200cffe"
	"b600bcffdbff8b001bff870012008d0019002fff2bff2dffd3ffbcff59002e01"
	"01fe8efdad00b3ff98ff3effe201140130ff53ff9a0116007aff29ffc8000a00"
	"3b00ba005bffcb010bff7a0052004700e5ff7dff830099003c0036ff70ff7000"
	"00005a010cffbfff8e0037ffc8ff2600c0ff54001d00abffa00024fffffff600"
	"c1feffff87fedbff88ffde000200be0005003cff5a004700f100deffe9ffe300"
	"a4fe97ffaf00560097fed30062fed500ddffdb006300dc00670148ff13fee7ff"
	"eefe96ff59ff5bff47ff79ffc100e1ff61ff33007e00afff51fff7ff93ff9000"
	"17ffec008701bdffaf003f00db01660078fff70000ff8aff260090005fffc4ff"
	"670039ffa0ff62009300f3ffa701b0ff5fff26ff81fff900a8004aff13ffb800"
	"86ffd1006f00170074ff440152003a0008ff36ffe600d1ffc9ff20ffe6fefe00"
	"0601ce0000006dff7affb9006fff37ff20ffe2004fff9d0182fefdff240019ff"
	"44ffb300b6ff19ffd8ffd000180051007f0016ff46ff2100760135ff94011000"
	"21ff00ffda000200e5ffc2fef3ff8000e3ffab014800d700a6fff9feb200a2ff"
	"9e005c004f011fff9cffe3ff91009dfff6002ffed6fed2005100c3fff2ffcdff"
	"6f00a400a4ff8f002a0137fe4c0030fead0050ffce005400010009ff4900be01"
	"00ffad00550047ff1500c600ac000b0061016b00ccfff701b6fed80025ffd200"
	"93ff19ff34011300aeff6dffe7ffc60002feebff7bfe6aff6fff8aff4c005dff"
	"de000500430039fe6a012eff83fea1ff9cff40ff7cfef0001e004aff89010400"
	"afffb2007f000c014e00b200e0fe3bfe3eff6fffb100fc0052ffee0028ff6c00"
	"8effe5ffa8ffc7ff4bff20009aff1aff870121feddffc100d200c6ffd4ff30ff"
	"f4fed1ff28ffd000fd00f0ff67002e002700de0057ff9efff200acfff5ffc5ff"
	"c500920116ffccffbcffdbff6cfeccfe970088000100b4ff97003ffff10075ff"
	"bc00010012ffc60097ff1f00dfffd4ff94ff9efe6400350035ffc6ffccffb000"
	"bb00280008003f00f6008ffee6ff3cffa7ff97fff20004004bff170032fec300"
	"54ffeffee0003cff4800d7feba0000ffe7005201820022ff9600540089001100"
	"1aff380057fed9ff11011c0022009b002c000efe8eff31ff3f006b00e70037ff"
	"230075ffb3ffc600a1fee70051ff2dfffa003f00f9005d0045009bffd0ffc7ff"
	"92000c00b300e1ff6f006a0040ffc6ff5aff8f002d009dfefafe15ffe6fe9200"
	"9a0077ff82ff73ff0cfee8014cff9000e4ff75ff520058006200dcffabff47ff"
	"fc004c005affb00004ffe6ff2f00250046ff20fefaff6c006c00370049ffb3ff"
	"e2ff89ffa6ff7fff37fec7003a0059ffe800b70072ffe9fffcffe800ee007700"
	"edffbdff9500abfff2fef200670004fecaffd0fef50107ff3aff79ff97ff0e00"
	"3fff8300680036006f019f0021ff6dffc1ff0fff45ffa4fee2003f005c008500"
	"b40151006bff5dffbbff8b008ffec60003ffac003c00f600430002016b00ec00"
	"39011a0159ff1100b7fff80094009700480096ff27ffea00460163ffef00a400"
	"fdff9cfe71ffcfffffff4cffc6ffe9ffb7ff99005a007f005bfebb0089ff50ff"
	"f9",

	"2b982d5b2aef3932ad1c2aa72cdc2bd8d5badd60d19508d5b7832f12867a41ce",
	"sample 9",
	"0aff9a001f0058006f008dff280022ff090011010b006e006bffee0009000f00"
	"67ffa2ff44ff8000f4005600ff0014ffc80008ff920049001400f4003e006100"
	"54ffdfff47ff4dff91ffa800e40065fdee0075002e0044ff40006f0001ff5e00"
	"4900b6009bff5c00fcffa4ffd100a6fec80015ff68003300f1ffc3ffc3ffe5ff"
	"56002dfec30030ff22ff0bff77ff5700f0ff130066ff4bffa8003fffd8008ffe"
	"5c001700a70172008f007bffcb00b50007ffe30050002f0075ff6eff69009300"
	"eb0039ffbcfff9ffe0010200250051004a0011ffc5003afefc0026ff7bff88ff"
	"8e00d3003cffb9ffbaff87ff9e00fd001bffe5ff31ffef0012ff21002b0099ff"
	"cfffa700550003ff6bffe30037ff20ff800073ffca0065ffc0ffa10073ff0f00"
	"600048018700b10109ff8cffbbff9e010afffc0022ffc1ff0affaaff80ff4fff"
	"e400fa001b0075ff87ffc7ff8fff61001d0019ffea0194002200bd0135ffc8ff"
	"6bff73ffcaffb9ffb400e700b20065ffedffbbffe200b20057ff32ff8dff7b00"
	"260029ff510076ffb2002100f1ff4ffe3b0027002eff6800d5ff0300910016ff"
	"0400ec005cff45ff7f001e0021ff8900420086011f003dfff5002a0082009800"
	"00ffcf0035ffaf0065ffb5004fffe5ff5eff990063ffc1000dffa9fff9000bff"
	"5900f30131ffd6fff20058ff9d0056ffdcffc501f200cf0106002cff50ff1000"
	"f0ff170025febeff9500750022feb70082ff48ff2200bbff18006f006fff75ff"
	"ab009600790060005b0012004300cdffcc00b8007f0125fffeff8d000cfff4ff"
	"97ff880070ff83ff26012fffd5ffb2ffeb002d00c900d1ff8900a1ffa60133fe"
	"ffff64ff79001c0053ffb80161ffd6ffb7fff900cbff84ffbb008affa201ad00"
	"d00073ff01ff6a0017ff5b0016ff8d0019feec003dfffb01cb0094ff3f000cff"
	"92ffd8ff650044004b0003ffc600080080ff8c00f1ff2600a1ffd0ff58ffecff"
	"48001a00dbff4dffd6001cff5a0157ff690177009eff2cffadff62fee60027ff"
	"b00034010100780127ffbc0052003e000c00e1ff62008bff250016fee3ffe200"
	"a8001effad00efff19ff66005d00b2fed600700112ff5eff690073003901a5ff"
	"e9ffb60013ff4bfeb2ffe8ff2cffefff14ffa4004affdf006c016efed900b5fe"
	"f9ff5effbd006c0068ffedff6100bf0138002bff7f0016ffb90066012100ef01"
	"01fee601490024ffb4005e0038ff1700c3ff5f00d0002e001800ec00850049ff"
	"d8ffe8ff90ffb6fff5febc0078fed2ff5dff95000500920084ffe60194004dfe"
	"c7ffb300e2ff97ff06ffff00caffa3fed00012ffddffe0002700b3ff4400cbfe"
	"af001dff170064ffd60166010b0019001500050085ff0cffc50022ffa4008f00"
	"71ff5c0037ff23ffc10060fe8c01070075ffe0ffc90066ff04ff47ff9d006300"
	"68001700d3ff7bffce0028fedbff26ffffffdaffe2005f0033fef0fffcfec9ff"
	"b3ffe6025100660056ff83ff3e00300097fedc008fff940098feafff81ffb1ff"
	"a5005cff98013a00260024007f0031003900cd00ad0075ff69ff860016ff2300"
	"a6ffabff9fff8100480056ff97003b003cffc20084001c01090057feffff6100"
	"51fea6ff8effe3ff840072fffd00a5005eff770160ff320118fedefffffede00"
	"7b0006ff80000f00c50119ffc2fef9008bff5e022aff6200caff03fff3fed2ff"
	"550007ffd5ffb2ff11001600f6ffd2ffc1ffad006a003aff280035ff49fff3ff"
	"a0ff0e00baffea0095fed700a9001aff1200b3010fff3a006801170042ff4800"
	"69ff610109005f002d00220055001fff400068008cffb60070fffdfff60010ff"
	"8f0009ffdcff3e0051fff2ff4bff4000c5ff9d00b7009b00f200aa004fff4900"
	"fe012c00be000e0060003b000c005c00e0ff2eff6bfefe01b6ff9d00c100a000"
	"6aff51ffb3ffde002f00a200c7002bfebe0016ffe0ffbb0093ff2200abff8cff"
	"17ff8d002fff0afff8feda006eff040082ffb50058ff73005e00cb0091ff7500"
	"e2004a007b002cffacfffcffa001b5009300d300700002ff740009ff9dffe500"
	"e400770033006bff7cfea0ff48007dffec002cff8300f6ff34006a011afffc00"
	"eeff1000570061006a0028ff92003cffbd001a001100a7ff5b002effcf00bcff"
	"7dfff8ffce0030ffc6ff3700bf00070006ff7b00acff53004bff54007c006801"
	"34fff80138fe7cff9e002fff700091fff701ad003a007efde8fff30031fffaff"
	"6dfffafee10086ffdcffc1ffc3ff37ffe500b00090ff82ff4d00920053ff8801"
	"80fefefffdff4100c8004401440066ff49ff73000bff8eff50ffa8008b00dcff"
	"5effb0002dffd00024ff3bfefcffcb00e3003800f5ffadff57ffa3ffd40120ff"
	"63ffbfffebffd0ffc7ffe0006f0050009d00ce001e00a6ff13ff53001f006efe"
	"d50085ffabfedfffa9ff46ffd500280092000c005cff6a0078ff50ff630037ff"
	"e9ff34fff9008effb500e1005e00af014800a8ff83005cff98ff6300a9ff2f00"
	"74ff770105ffd1fe6bffc3ffb6ff3100b4003b01030077009b011bffb9003800"
	"40ff7600b60059ffc70092feee010dffd3ff70ffec0002004eff93ff86ff6f00"
	"d60016ffd90149ff7900440004ff3affb1ff76004dff67ffa4008b002b003d01"
	"90ff5301990022ff2800f00001fe6dfe90005f007bff280030ff65000b016001"
	"7f004fff6fff47ff97fe9d009100fc0009003bff86008500faff7dff4b009700"
	"320044ffd4ff13005200b2ff41011a002e002bffcffe95ffe2000effeefffa00"
	"35ff3c00b6009bffd0009a00d6feaeffb4ff17003cfec7ff2b0026ffdd0038fe"
	"fa011fff400191ff0d00e6ffedff71001bff9e00a10000ff56fed1ffe10157ff"
	"fa",

	NULL
};

static void
test_codec_inner(unsigned logn, uint8_t *tmp, size_t tlen)
{
	size_t n;
	inner_shake256_context sc;
	int i;

	n = (size_t)1 << logn;
	inner_shake256_init(&sc);
	inner_shake256_inject(&sc, (const uint8_t *)"codec", 5);
	tmp[0] = logn;
	inner_shake256_inject(&sc, tmp, 1);
	inner_shake256_flip(&sc);

	for (i = 0; i < 10; i ++) {
		size_t u, maxlen, len1, len2;
		uint16_t *m1, *m2;
		int16_t *s1, *s2;
		int8_t *b1, *b2;
		uint8_t *ee;
		unsigned bits;

		m1 = (uint16_t *)tmp;
		m2 = m1 + n;
		ee = (uint8_t *)(m2 + n);
		maxlen = tlen - 4 * n;
		for (u = 0; u < n; u ++) {
			uint8_t tt[4];
			uint32_t w;

			inner_shake256_extract(&sc, tt, sizeof tt);
			w = (uint32_t)tt[0]
				| ((uint32_t)tt[1] << 8)
				| ((uint32_t)tt[2] << 16)
				| ((uint32_t)tt[3] << 24);
			m1[u] = w % 12289u;
		}
		len1 = Zf(modq_encode)(NULL, 0, m1, logn);
		if (len1 != (((n * 14) + 7) >> 3)) {
			fprintf(stderr, "ERR modq encode(0): %zu\n", len1);
			exit(EXIT_FAILURE);
		}
		len1 = Zf(modq_encode)(ee, maxlen, m1, logn);
		if (len1 != (((n * 14) + 7) >> 3)) {
			fprintf(stderr, "ERR modq encode: %zu\n", len1);
			exit(EXIT_FAILURE);
		}
		len2 = Zf(modq_decode)(m2, logn, ee, len1);
		if (len2 != len1) {
			fprintf(stderr, "ERR modq decode: %zu\n", len2);
			exit(EXIT_FAILURE);
		}
		check_eq(m1, m2, n * sizeof *m2, "modq encode/decode");

		s1 = (int16_t *)tmp;
		s2 = s1 + n;
		ee = (uint8_t *)(s2 + n);
		maxlen = tlen - 4 * n;
		for (bits = 4; bits <= 12; bits ++) {
			unsigned mask1, mask2;

			mask1 = 1u << (bits - 1);
			mask2 = mask1 - 1u;

			for (u = 0; u < n; u ++) {
				uint8_t tt[2];
				unsigned w, a;

				inner_shake256_extract(&sc, tt, sizeof tt);
				w = (unsigned)tt[0] | ((unsigned)tt[1] << 8);
				a = w & mask2;
				s1[u] = ((w & mask1) != 0) ? -(int)a : (int)a;
			}

			len1 = Zf(trim_i16_encode)(NULL, 0, s1, logn, bits);
			if (len1 != (((n * bits) + 7) >> 3)) {
				fprintf(stderr,
					"ERR trim_i16 encode(0): %zu\n", len1);
				exit(EXIT_FAILURE);
			}
			len1 = Zf(trim_i16_encode)(ee, maxlen, s1, logn, bits);
			if (len1 != (((n * bits) + 7) >> 3)) {
				fprintf(stderr,
					"ERR trim_i16 encode: %zu\n", len1);
				exit(EXIT_FAILURE);
			}
			len2 = Zf(trim_i16_decode)(s2, logn, bits, ee, len1);
			if (len2 != len1) {
				fprintf(stderr,
					"ERR trim_i16 decode: %zu\n", len2);
				exit(EXIT_FAILURE);
			}
			check_eq(s1, s2, n * sizeof *s2,
				"trim_i16 encode/decode");

			memset(s2, 0, n * sizeof *s2);
			len1 = Zf(comp_encode)(ee, maxlen, s1, logn);
			if (len1 == 0) {
				fprintf(stderr,
					"ERR comp encode: %zu\n", len1);
				exit(EXIT_FAILURE);
			}
			len2 = Zf(comp_decode)(s2, logn, ee, len1);
			if (len2 != len1) {
				fprintf(stderr,
					"ERR comp decode: %zu\n", len2);
				exit(EXIT_FAILURE);
			}
			check_eq(s1, s2, n * sizeof *s2,
				"comp encode/decode");
		}

		b1 = (int8_t *)tmp;
		b2 = b1 + n;
		ee = (uint8_t *)(b2 + n);
		maxlen = tlen - 2 * n;
		for (bits = 4; bits <= 8; bits ++) {
			unsigned mask1, mask2;

			mask1 = 1u << (bits - 1);
			mask2 = mask1 - 1u;

			for (u = 0; u < n; u ++) {
				uint8_t tt;
				unsigned a;

				inner_shake256_extract(&sc, &tt, 1);
				a = tt & mask2;
				b1[u] = ((tt & mask1) != 0) ? -(int)a : (int)a;
			}

			len1 = Zf(trim_i8_encode)(NULL, 0, b1, logn, bits);
			if (len1 != (((n * bits) + 7) >> 3)) {
				fprintf(stderr,
					"ERR trim_i8 encode(0): %zu\n", len1);
				exit(EXIT_FAILURE);
			}
			len1 = Zf(trim_i8_encode)(ee, maxlen, b1, logn, bits);
			if (len1 != (((n * bits) + 7) >> 3)) {
				fprintf(stderr,
					"ERR trim_i8 encode: %zu\n", len1);
				exit(EXIT_FAILURE);
			}
			len2 = Zf(trim_i8_decode)(b2, logn, bits, ee, len1);
			if (len2 != len1) {
				fprintf(stderr,
					"ERR trim_i8 decode: %zu\n", len2);
				exit(EXIT_FAILURE);
			}
			check_eq(b1, b2, n * sizeof *b2,
				"trim_i8 encode/decode");
		}
	}
}

static void
test_codec(void)
{
	unsigned logn;
	uint8_t *tmp;
	size_t tlen;

	printf("Test encode/decode: ");
	fflush(stdout);
	tlen = 8192;
	tmp = xmalloc(tlen);

	for (logn = 1; logn <= 10; logn ++) {
		test_codec_inner(logn, tmp, tlen);
		printf(".");
		fflush(stdout);
	}

	xfree(tmp);
	printf(" done.\n");
	fflush(stdout);
}

static void
test_vrfy_inner(unsigned logn, const int8_t *f, const int8_t *g,
	const int8_t *F, const int8_t *G, const uint16_t *h,
	const char *hexpkey, const char *const *kat, uint8_t *tmp, size_t tlen)
{
	size_t u, n, len1, len2;
	int8_t *G2;
	uint16_t *h2;

	n = (size_t)1 << logn;

	/*
	 * Test computation of public key from private key.
	 */
	h2 = (uint16_t *)tmp;
	if (tlen < 4 * n) {
		fprintf(stderr, "Insufficient buffer size\n");
		exit(EXIT_FAILURE);
	}
	if (!Zf(compute_public)(h2, f, g, logn, (uint8_t *)(h2 + n))) {
		fprintf(stderr, "compute_public failed\n");
		exit(EXIT_FAILURE);
	}
	check_eq(h, h2, n, "compute_public");

	/*
	 * Test reconstruction of G from f, g and F.
	 */
	G2 = (int8_t *)tmp;
	if (tlen < 5 * n) {
		fprintf(stderr, "Insufficient buffer size\n");
		exit(EXIT_FAILURE);
	}
	if (!Zf(complete_private)(G2, f, g, F, logn, (uint8_t *)(G2 + n))) {
		fprintf(stderr, "complete_private failed\n");
		exit(EXIT_FAILURE);
	}
	check_eq(G, G2, n, "complete_private");

	/*
	 * Test encoding of public key.
	 */
	len1 = hextobin(tmp, tlen, hexpkey);
	if (len1 != 1 + (((n * 14) + 7) >> 3)) {
		fprintf(stderr, "unexpected public key length: %zu\n", len1);
		exit(EXIT_FAILURE);
	}
	if (tmp[0] != logn) {
		fprintf(stderr, "unexpected first pkey byte: %u\n", tmp[0]);
		exit(EXIT_FAILURE);
	}
	len1 --;
	if (tlen < 2 * len1) {
		fprintf(stderr, "Insufficient buffer size\n");
		exit(EXIT_FAILURE);
	}
	memmove(tmp, tmp + 1, len1);
	len2 = Zf(modq_encode)(tmp + len1, tlen - len1, h, logn);
	if (len2 != len1) {
		fprintf(stderr, "wrong encoded public key length: %zu\n", len2);
		exit(EXIT_FAILURE);
	}
	check_eq(tmp, tmp + len1, len1, "pubkey encode\n");

	/*
	 * Verify sample signatures.
	 */
	if (tlen < 8 * n) {
		fprintf(stderr, "Insufficient buffer size\n");
		exit(EXIT_FAILURE);
	}
	for (u = 0; kat[u] != NULL; u += 3) {
		uint8_t *nonce, *sig;
		size_t nonce_len;
		inner_shake256_context sc;
		int16_t *s2;
		uint16_t *c0;

		/*
		 * Hash nonce + message.
		 */
		nonce = tmp;
		nonce_len = hextobin(nonce, tlen, kat[u + 0]);
		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, nonce, nonce_len);
		inner_shake256_inject(&sc,
			(const uint8_t *)kat[u + 1], strlen(kat[u + 1]));
		inner_shake256_flip(&sc);

		/*
		 * Decode signature.
		 */
		sig = tmp;
		len1 = hextobin(sig, tlen, kat[u + 2]);
		if (len1 == 0 || sig[0] != logn) {
			fprintf(stderr, "Invalid sig KAT\n");
			exit(EXIT_FAILURE);
		}
		len1 --;
		memmove(sig, sig + 1, len1);
		s2 = (int16_t *)(sig + len1);
		if ((tlen - len1) < 2 * n) {
			fprintf(stderr, "Insufficient buffer size\n");
			exit(EXIT_FAILURE);
		}
		len2 = Zf(trim_i16_decode)(s2, logn, 16, sig, len1);
		if (len2 != len1) {
			fprintf(stderr, "Invalid sig KAT\n");
			exit(EXIT_FAILURE);
		}
		memmove(tmp, s2, n * sizeof *s2);
		s2 = (int16_t *)tmp;

		/*
		 * Convert public key to NTT + Montgomery representation.
		 */
		h2 = (uint16_t *)(s2 + n);
		memcpy(h2, h, n * sizeof *h);
		Zf(to_ntt_monty)(h2, logn);

		/*
		 * Hash nonce + message into a point.
		 */
		c0 = h2 + n;
		Zf(hash_to_point_vartime)(&sc, c0, logn);

		/*
		 * Verify the signature.
		 */
		if (!Zf(verify_raw)(c0, s2, h2, logn, (uint8_t *)(c0 + n))) {
			fprintf(stderr, "KAT signature failed\n");
			exit(EXIT_FAILURE);
		}

		printf(".");
		fflush(stdout);
	}

	printf(" ");
	fflush(stdout);
}

static void
test_vrfy(void)
{
	uint8_t *tmp;
	size_t tlen;

	printf("Test verify: ");
	fflush(stdout);
	tlen = 8192;
	tmp = xmalloc(tlen);

	test_vrfy_inner(4, ntru_f_16, ntru_g_16, ntru_F_16, ntru_G_16,
		ntru_h_16, ntru_pkey_16, KAT_SIG_16, tmp, tlen);
	test_vrfy_inner(9, ntru_f_512, ntru_g_512, ntru_F_512, ntru_G_512,
		ntru_h_512, ntru_pkey_512, KAT_SIG_512, tmp, tlen);
	test_vrfy_inner(10, ntru_f_1024, ntru_g_1024, ntru_F_1024, ntru_G_1024,
		ntru_h_1024, ntru_pkey_1024, KAT_SIG_1024, tmp, tlen);

	xfree(tmp);
	printf("done.\n");
	fflush(stdout);
}

static const uint64_t KAT_RNG_1[] = {
	0xDB1F30843AAD694Cu, 0xFAD9C14E86D5B53Cu, 0x7F84F914F46C439Fu,
	0xC46A6E399A376C6Du, 0x47A5CD6F8C6B1789u, 0x1E85D879707DA987u,
	0xC7B0CE6C2C1DB3E7u, 0xA65795537B3D977Cu, 0x748457A98AC7F19Cu,
	0xD8C8F161EEB7231Fu, 0xE81CAE53A7E8967Fu, 0x27EAD55A75ED57F8u,
	0x9680953F3A192413u, 0x784145D6687EA318u, 0x9B454489BE56BAEBu,
	0xF546834B0F799C67u, 0xAC8E4F657C93FB88u, 0xD0E6C7610CC4028Bu,
	0x417296FB7E1124BDu, 0xE7968F18E3221DDCu, 0x1DDEC33FC7F2D5FBu,
	0x76556A8C07FB48EEu, 0x7910EAA4C163BC2Fu, 0xAAC5C6291F779D17u,
	0x575B2692885C4CFAu, 0x0664AA8C3E99DA19u, 0xFA55C1AE9A615133u,
	0x7F1DB1A620F63220u, 0xE740AE9AF9CC9755u, 0x8393056E1D0D81E1u,
	0x556EEF4483B434AAu, 0xC6D17BEF7C2FB0C3u, 0x27D142BD5BBF6014u,
	0x6FD90B14DB4AA0BBu, 0x7ACDD6F240530D0Du, 0xE980F9F9DBE6109Au,
	0xA30C677211C7BF37u, 0x1E41FD290B90CE8Bu, 0x478FCD48D5E4A9EDu,
	0x10586F987EA5FA7Au, 0x691891C568F5DAC7u, 0x3277735ED18D9107u,
	0x78FCC576E47E8D71u, 0x940A2C6777E3BEBBu, 0x814612E210DD9715u,
	0xABBCAFCC6B54279Bu, 0x2550E2538A063BFCu, 0x7965EFC9D3F8A5BEu,
	0xAE35E74B5A0B8717u, 0xD855D6ABB96EA3AFu, 0xAB4689B903C01C4Eu,
	0x8D8018988CA554ACu, 0x0BB6689524F3A2B1u, 0xAC0676FCBB193A87u,
	0xD0A83D30F34F65ECu, 0x26D3A8C167CA09F4u, 0x7D17403D2B1DD9A0u,
	0x47B1C836A0224550u, 0xF6ABECF6422C5A56u, 0x6FB1B2FF5CDDEC25u,
	0x118276B244B55F88u, 0x1FB953EF9E6C2C41u, 0xF351C2717ACE9BF3u,
	0xDF787B64D51A5440u, 0xE4B8B81149B8A70Bu, 0x337E5363F506228Bu,
	0x48948ADE314B5980u, 0x7FBF7A7139004610u, 0xA6CB33F6802C96C7u,
	0x745888A51A99BBEDu, 0x49D411403BA9CFDAu, 0xA547A6EA4BDD5538u,
	0x2D65DCF44F045E9Fu, 0x734FBE9360EFCC44u, 0x1131E0AD573D37A0u,
	0xADF3E9199FD90113u, 0x8EDF3EAF50E6E00Bu, 0xFE0240D04C171901u,
	0x45A97204596F7C46u, 0x54D1D1F962484BC5u, 0xEBAC109CDB975ED4u,
	0x51182BF46BD2D61Cu, 0xF12D0EC8A80092D3u, 0x69CA22BA55B34270u,
	0x5FF97BBE7A525BF7u, 0xF4E19780A4149ACAu, 0x2CD5AE45826309FCu,
	0xF0EF1F0A309C1BCFu, 0xC16AF49962FE8A87u, 0x2CD2575C27761E54u,
	0xD9199411E9CC816Du, 0xA0C397A63D036B05u, 0xF439D283DFE4C172u,
	0x5DAAD309E61F2A60u, 0x2E7DDC8F9CD47E91u, 0x2E1BFCDDC439FD58u,
	0x8E62B7C84C3C27F8u, 0xECD06ED0C1938A5Eu, 0x0335351E644A9155u,
	0x71A735982C6DBBF7u, 0xD8FE9FAF2DDF9AFFu, 0x06BC9F654B9814E7u,
	0x2DF46A488EC46052u, 0x80CB8E04CDEF7F98u, 0x9B65042EE20B4DAFu,
	0x203BF49ACB5B34D2u, 0x54E8F69957D8903Bu, 0x84D63D4BA389AF36u,
	0x7A2D4A2230D0DC82u, 0x3052659534D82FB8u, 0xC5058A8EC3716238u,
	0xB8063774064F4A27u, 0x2F0BE0CE382BFD5Bu, 0xEE4CEAD41973DA0Fu,
	0xFB56581EB2424A5Au, 0x09F21B654D835F66u, 0x1968C7264664F9CCu,
	0x2CBD6BB3DD21732Cu, 0xA9FB1E69F446231Cu, 0xDBEAD8399CB25257u,
	0x28FF84E3ECC86113u, 0x19A3B2D11BA6E80Fu, 0xC3ADAE73363651E7u,
	0xF33FFB4923D82396u, 0x36FE16582AD8C34Cu, 0x728910D4AA3BB137u,
	0x2F351F2EF8B05525u, 0x8727C7A39A617AE4u
};

static const uint8_t KAT_RNG_2[] = {
	0xC9, 0x45, 0xBC, 0xC4, 0x5B, 0x67, 0xA3, 0x25, 0x97, 0x19,
	0x64, 0x67, 0x4A, 0x98, 0xD4, 0xB7, 0xA7, 0x83, 0x18, 0xC8,
	0x40, 0xE2, 0x7F, 0xB8, 0x25, 0x8B, 0x7E, 0x92, 0x4A, 0x8C,
	0x68, 0x1B, 0x77, 0x61, 0x1E, 0x70, 0xED, 0xC2, 0xC4, 0xA5,
	0xDF, 0x9E, 0x76, 0xED, 0x49, 0x84, 0x3D, 0x08, 0xFE, 0xFE,
	0x99, 0xE2, 0xC6, 0xEF, 0xFE, 0x2C, 0xD4, 0xC0, 0x04, 0xD8,
	0x9A, 0x51, 0x21, 0xCD, 0x5B, 0xDB, 0x9F, 0x0B, 0x9C, 0x47,
	0xCF, 0xE8, 0x38, 0x6B, 0xB4, 0x94, 0xDC, 0xCD, 0x9A, 0x9B,
	0xB7, 0xED, 0xEE, 0x82, 0x64, 0x53, 0x20, 0xA0, 0x8F, 0x59,
	0xB2, 0x4F, 0xE2, 0x5A, 0x35, 0x88, 0x39, 0x5B, 0x6C, 0x59,
	0x59, 0x8C, 0x10, 0xC5, 0x2B, 0xF3, 0x7C, 0x49, 0xFD, 0x99,
	0x0C, 0x86, 0x07, 0x9E, 0x35, 0x71, 0x8E, 0x23, 0x7B, 0x9D,
	0x23, 0x34, 0x7A, 0xC8, 0x8A, 0x17, 0xDA, 0x7B, 0xA2, 0x97,
	0x0A, 0x78, 0x2B, 0x19, 0xAD, 0xB1, 0x35, 0xBD, 0xB1, 0xE7,
	0x74, 0x4B, 0x82, 0xFB, 0x72, 0x9C, 0x8C, 0x51, 0x3B, 0xE3,
	0xF0, 0x31, 0x11, 0xAA, 0x59, 0xA4, 0x66, 0xAC, 0xAA, 0x9E,
	0x85, 0xD9, 0x2D, 0xAD, 0xCA, 0x2B, 0x69, 0x5E, 0x19, 0x9F,
	0x77, 0x15, 0x43, 0xF0, 0xC9, 0x9F, 0xBC, 0x5B, 0x66, 0x26,
	0x7F, 0x7D, 0x7C, 0x95, 0x5D, 0x60, 0xE0, 0x49, 0x15, 0xC4,
	0x56, 0x47, 0x7E, 0x8D, 0x68, 0x3C, 0x54, 0x6F, 0x20, 0xF9,
	0x00, 0x43, 0xB4, 0x52, 0xD8, 0x46, 0x51, 0xFC, 0x0B, 0x92,
	0x15, 0xEF, 0x56, 0x45, 0x49, 0x94, 0xC2, 0xD0, 0x5E, 0x95,
	0xC4, 0x6D, 0x00, 0xDD, 0x13, 0x93, 0x78, 0xC2, 0x85, 0x21,
	0x5D, 0x18, 0x92, 0xB9, 0x48, 0xD2, 0x96, 0x45, 0x89, 0x0D,
	0x69, 0x2B, 0x85, 0x5D, 0x23, 0x5D, 0x10, 0x92, 0xD7, 0xDC,
	0xDC, 0xF8, 0x60, 0x5E, 0xED, 0x1F, 0x21, 0xB2, 0x19, 0x27,
	0xB7, 0xB7, 0xCD, 0x49, 0x98, 0x29, 0x90, 0xC9, 0x81, 0xCD,
	0x4E, 0x44, 0xB5, 0x39, 0x56, 0xED, 0x2B, 0xAA, 0x53, 0x34,
	0x3B, 0xB0, 0xBA, 0x1F, 0xBC, 0xF8, 0x58, 0x5F, 0x3E, 0xD0,
	0x4D, 0xB3, 0xA8, 0x5E, 0xC9, 0xB8, 0xD2, 0x70, 0xD3, 0x30,
	0xC0, 0x3C, 0x45, 0x89, 0x9B, 0x4C, 0x5F, 0xE8, 0x05, 0x7F,
	0x78, 0x99, 0x48, 0x3A, 0xD7, 0xCB, 0x96, 0x9A, 0x33, 0x97,
	0x62, 0xE9, 0xBD, 0xCE, 0x04, 0x72, 0x4D, 0x85, 0x67, 0x51,
	0x69, 0xFB, 0xD3, 0x12, 0xBC, 0xFC, 0xB5, 0x77, 0x56, 0x3B,
	0xB9, 0xB5, 0x3D, 0x5D, 0x7D, 0x2B, 0x34, 0xB0, 0x36, 0x2D,
	0x56, 0xE9, 0x24, 0xC2, 0x5A, 0xE9, 0x2A, 0xF8, 0xEE, 0x83,
	0x74, 0xC1, 0x0C, 0x80, 0xAD, 0x43, 0x5C, 0x04, 0x49, 0xB0,
	0x41, 0xD2, 0x29, 0x32, 0x9C, 0x7D, 0x70, 0xD5, 0x3D, 0xFE,
	0x82, 0x27, 0x8A, 0x38, 0x19, 0x12, 0x14, 0x78, 0xAA, 0x2A,
	0x29, 0xE2, 0x2B, 0xBB, 0x87, 0x4F, 0x7A, 0xDC, 0xC0, 0x72,
	0x30, 0xB6, 0xDE, 0x73, 0x7C, 0x04, 0x2D, 0xB6, 0xDF, 0x5E,
	0x4C, 0x3B, 0x82, 0xF6, 0x10, 0xE4, 0x94, 0xCE, 0x90, 0xD4,
	0x23, 0x0C, 0xBD, 0xCA, 0x56, 0xB7, 0x09, 0x6C, 0xAC, 0x35,
	0xA8, 0x47, 0xF0, 0x94, 0x21, 0xBD, 0xD5, 0x09, 0x18, 0x78,
	0x7C, 0x8D, 0x1E, 0x03, 0x15, 0xB1, 0x1A, 0xE8, 0x72, 0xB7,
	0x98, 0x5F, 0x23, 0x3A, 0x91, 0xB2, 0xDF, 0xFD, 0x70, 0x69,
	0xC4, 0x3B, 0xFA, 0x73, 0x17, 0xCC, 0xFB, 0xCF, 0xA6, 0xCF,
	0xC1, 0x32, 0x3E, 0x74, 0x0C, 0xCC, 0x73, 0xB2, 0xBE, 0x73,
	0xAC, 0x8E, 0x44, 0x51, 0x45, 0xED, 0xF6, 0x60, 0x21, 0x3D,
	0x0C, 0xE3, 0x3E, 0x1B, 0x11, 0x55, 0x68, 0x1A, 0x15, 0x97,
	0x80, 0x67, 0x23, 0x4F, 0x37, 0xF5, 0x30, 0x3D, 0x05, 0x4E,
	0xCF, 0x0E, 0x03, 0xB9, 0x2F, 0xD1, 0xD5, 0xD6, 0x5F, 0x79,
	0xF6, 0x61, 0x15, 0xBC, 0x79, 0x80, 0xA4, 0xD7, 0x98, 0x5B,
	0x38, 0x7A, 0x07, 0x9B, 0x02, 0xB2, 0x47, 0x89, 0xB2, 0x25,
	0xEF, 0x7B, 0xB1, 0xB0, 0xA5, 0x35, 0x39, 0xEB, 0xA0, 0x1C,
	0x24, 0xF4, 0xDB, 0x0C, 0x6C, 0x2B, 0xA3, 0x75, 0x47, 0x00,
	0xA3, 0xC8, 0xBC, 0x1E, 0x15, 0x3A, 0xC6, 0x1D, 0x91, 0x19,
	0xBA, 0xB4, 0xCA, 0x28, 0xD2, 0x57, 0x7C, 0x0D, 0x71, 0x4A,
	0x03, 0xD5, 0xAE, 0x96, 0x6D, 0x92, 0x70, 0x27, 0x82, 0x88,
	0xB6, 0x12, 0x1A, 0x84, 0x38, 0x1B, 0x74, 0x2F, 0x74, 0x33,
	0xE0, 0xA1, 0x82, 0x93, 0x62, 0xB6, 0x5B, 0x9E, 0x4E, 0xC2,
	0xE6, 0x5B, 0x49, 0x7E, 0x4A, 0x68, 0x8D, 0x08, 0xA9, 0xD8,
	0xEA, 0x47, 0xFC, 0xD2, 0x31, 0x21, 0x38, 0xEE, 0xE4, 0xE4,
	0x97, 0xFA, 0x91, 0x90, 0xC4, 0x26, 0x4B, 0xA5, 0xB3, 0x7D,
	0x33, 0x7F, 0x5A, 0x2D, 0x54, 0xB3, 0x01, 0xCF, 0x9C, 0x0D,
	0x9E, 0x97, 0x01, 0xE8, 0x54, 0x3C, 0xC2, 0x13, 0x69, 0x0C,
	0x35, 0xCD, 0x63, 0x02, 0x70, 0xC8, 0xA1, 0x1F, 0xC2, 0xBE,
	0x8F, 0xFC, 0xCE, 0x05, 0xA7, 0x3F, 0xCC, 0x04, 0x3D, 0x18,
	0xC4, 0x13, 0x38, 0x0D, 0x4C, 0xEE, 0x81, 0xFA, 0x02, 0xF8,
	0xFC, 0x4F, 0x21, 0xD0, 0xE6, 0xF2, 0x7B, 0x92, 0x76, 0xC5,
	0x8E, 0x96, 0x6C, 0x53, 0x84, 0x3E, 0x74, 0x1D, 0xD5, 0x0F,
	0x98, 0x03, 0x0E, 0x6A, 0x9D, 0x49, 0x03, 0xAE, 0xBE, 0x70,
	0x61, 0x5B, 0x45, 0xC0, 0x1E, 0x2F, 0x94, 0x42, 0xFA, 0x16,
	0x9F, 0xFA, 0xD5, 0x9B, 0x60, 0x88, 0x92, 0x19, 0x08, 0x02,
	0x31, 0x99, 0x6D, 0xA1, 0x72, 0xCB, 0x45, 0xC6, 0x93, 0xBA,
	0xA8, 0x71, 0x42, 0xC6, 0x85, 0x28, 0x6C, 0x1B, 0x60, 0x7C,
	0x14, 0x2F, 0x9A, 0x17, 0x10, 0x34, 0x27, 0x48, 0x36, 0xB2,
	0xE8, 0xD3, 0xEA, 0xE4, 0x9D, 0x67, 0xE4, 0x46, 0x2E, 0xC6,
	0x41, 0xE1, 0x83, 0x42, 0xB8, 0x82, 0x5F, 0x79, 0x61, 0xA3,
	0x0C, 0x63, 0x00, 0xCB, 0x7C, 0xB9, 0x30, 0x53, 0xF4, 0xFC,
	0xAF, 0xAC, 0x22, 0x71, 0x87, 0x4D, 0x4B, 0x4B, 0x9E, 0xAE,
	0x69, 0xB5, 0x58, 0x04, 0x9C, 0x03, 0x57, 0x58, 0x8D, 0x2F,
	0x82, 0x95, 0x57, 0x2F, 0xC3, 0xA1, 0xC5, 0xB1, 0xF1, 0xF1,
	0x98, 0x9A, 0xF8, 0x99, 0x74, 0x5C, 0xC5, 0xAC, 0x4A, 0x32,
	0xE9, 0x24, 0xCF, 0x1D, 0x1E, 0x29, 0x18, 0x7C, 0xBF, 0x43,
	0x74, 0x23, 0x28, 0xB0, 0x3D, 0xD1, 0xB3, 0x8C, 0xE1, 0x28,
	0x02, 0x3E, 0x8F, 0x7F, 0xDD, 0xF0, 0x5B, 0x4D, 0x37, 0x96,
	0xF7, 0x73, 0x73, 0x7F, 0xBC, 0xAD, 0x6C, 0x84, 0xFC, 0x47,
	0xD2, 0x1E, 0xAB, 0xEB, 0xB6, 0xCA, 0x4E, 0x3A, 0x2C, 0x47,
	0x59, 0x61, 0x0D, 0xA0, 0x17, 0xCF, 0xDD, 0x62, 0x6F, 0xA3,
	0xF4, 0x72, 0x2D, 0xB0, 0xB2, 0x34, 0x2A, 0xE1, 0x63, 0xC3,
	0x5B, 0xAC, 0xE8, 0x6F, 0x92, 0x77, 0x78, 0xE2, 0x34, 0xAD,
	0x4F, 0x6C, 0xFF, 0x71, 0xE1, 0x92, 0xFD, 0xED, 0xA1, 0x20,
	0xCA, 0xCB, 0x80, 0x32, 0xD1, 0x78, 0x72, 0x68, 0xFE, 0xAE,
	0x73, 0x22, 0xD7, 0x60, 0x23, 0x1D, 0x3D, 0x06, 0xD6, 0x2A,
	0x81, 0xC4, 0x43, 0x98, 0xFD, 0x4E, 0xBD, 0x85, 0x09, 0x29,
	0x11, 0xE8, 0x36, 0xE1, 0xCE, 0xCF, 0x07, 0xA7, 0x45, 0x8C,
	0xCB, 0xB2, 0xDC, 0xD0, 0x98, 0xB9, 0x93, 0x33, 0x8A, 0x2A,
	0x13, 0x82, 0x36, 0x3D, 0x22, 0xB0, 0x9C, 0x74, 0x3F, 0xCE,
	0x6F, 0xCC, 0x69, 0xFF, 0x81, 0xE8, 0xAE, 0xC8, 0x57, 0x0D,
	0x98, 0xEB, 0xC5, 0x2A, 0x45, 0x55, 0xDC, 0xBB, 0x0A, 0x5B,
	0x3D, 0xB4, 0x61, 0xC4, 0xAE, 0x11, 0x68, 0x7D, 0xD4, 0x45,
	0x83, 0xAE, 0x66, 0xC8
};

static void
test_RNG(void)
{
	inner_shake256_context sc;
	prng p;
	size_t u;

	printf("Test RNG: ");
	fflush(stdout);

	inner_shake256_init(&sc);
	inner_shake256_inject(&sc, (const uint8_t *)"rng", 3);
	inner_shake256_flip(&sc);
	Zf(prng_init)(&p, &sc);
	for (u = 0; u < (sizeof KAT_RNG_1) / sizeof(KAT_RNG_1[0]); u ++) {
		if (KAT_RNG_1[u] != prng_get_u64(&p)) {
			fprintf(stderr, "ERR KAT_RNG_1(%zu)\n", u);
			exit(EXIT_FAILURE);
		}
	}
	for (u = 0; u < (sizeof KAT_RNG_2) / sizeof(KAT_RNG_2[0]); u ++) {
		if (KAT_RNG_2[u] != prng_get_u8(&p)) {
			fprintf(stderr, "ERR KAT_RNG_2(%zu)\n", u);
			exit(EXIT_FAILURE);
		}
	}

	printf("done.\n");
	fflush(stdout);
}

static void
testfp_hash_u(inner_shake256_context *sc, uint64_t x)
{
#if FALCON_LE
	inner_shake256_inject(sc, (const uint8_t *)&x, 8);
#else
	uint8_t buf[8];

	buf[0] = (uint8_t)x;
	buf[1] = (uint8_t)(x >> 8);
	buf[2] = (uint8_t)(x >> 16);
	buf[3] = (uint8_t)(x >> 24);
	buf[4] = (uint8_t)(x >> 32);
	buf[5] = (uint8_t)(x >> 40);
	buf[6] = (uint8_t)(x >> 48);
	buf[7] = (uint8_t)(x >> 56);
	inner_shake256_inject(sc, buf, 8);
#endif
}

static void
testfp_hash_d(inner_shake256_context *sc, fpr x)
{
	union {
		fpr f;
		uint64_t u;
	} t;

	t.f = x;
	testfp_hash_u(sc, t.u);
}

static fpr
rand_fp(prng *p)
{
	uint64_t m;
	int e;
	union {
		fpr x;
		uint64_t u;
	} t;

	m = prng_get_u64(p);
	e = (m >> 52) & 0x7FF;
	e = (e & 0x7F) + 1023;
	t.u = (m & ~((uint64_t)0x7FF << 52)) | ((uint64_t)e << 52);
	return t.x;
}

/*
 * The FPEMU code defines fpr_scaled(), but the FPNATIVE code does not.
 * Also, neither defines fpr_ldexp(), though they previously did, and some
 * tests still rely on it.
 */

#ifndef fpr_scaled
static inline fpr
fpr_scaled(int64_t i, int sc)
{
	return FPR(ldexp((double)i, sc));
}
#endif

static inline fpr
fpr_ldexp(fpr x, int e)
{
#if FALCON_FPEMU
	uint32_t ex;

	/*
	 * Extract the exponent.
	 */
	ex = (x >> 52) & 0x7FF;

	/*
	 * Add 'e' to the exponent. However, if the result is negative,
	 * or the original exponent was 0, then the result should be 0.
	 */
	ex = (ex + (uint32_t)e) & -((ex + 0x7FF) >> 11);
	ex &= (ex >> 31) - 1;
	x = (x & (((uint64_t)1 << 63) + ((uint64_t)1 << 52) - (uint64_t)1))
		| ((uint64_t)ex << 52);
	return x;
#else
	return FPR(ldexp(x.v, e));
#endif
}

TARGET_AVX2
static void
test_FP_block(void)
{
	long ctr;
	inner_shake256_context sc, rng;
	prng p;
	int e;
	fpr nzero;
	unsigned char tmp[16], tmp2[16];
	size_t u;

	printf("Test floating-point (block): ");
	fflush(stdout);

	inner_shake256_init(&sc);

	testfp_hash_d(&sc, fpr_of(0));
	testfp_hash_d(&sc, fpr_neg(fpr_zero));
	testfp_hash_d(&sc, fpr_half(fpr_zero));
	testfp_hash_d(&sc, fpr_double(fpr_zero));

	nzero = fpr_neg(fpr_zero);
	testfp_hash_d(&sc, fpr_add(fpr_zero, fpr_zero));
	testfp_hash_d(&sc, fpr_add(fpr_zero, nzero));
	testfp_hash_d(&sc, fpr_add(nzero, fpr_zero));
	testfp_hash_d(&sc, fpr_add(nzero, fpr_zero));
	testfp_hash_d(&sc, fpr_add(fpr_zero, fpr_zero));
	testfp_hash_d(&sc, fpr_add(fpr_zero, nzero));
	testfp_hash_d(&sc, fpr_add(nzero, fpr_zero));
	testfp_hash_d(&sc, fpr_add(nzero, fpr_zero));

	for (e = -60; e <= +60; e ++) {
		fpr a, b;
		int i, j;

		for (i = -5; i <= +5; i ++) {
			a = fpr_of(((int64_t)1 << 53) + i);
			testfp_hash_d(&sc, a);
			for (j = -5; j <= +5; j ++) {
				b = fpr_scaled(((int64_t)1 << 53) + j, e);
				testfp_hash_d(&sc, b);
				testfp_hash_d(&sc, fpr_add(a, b));
				a = fpr_neg(a);
				testfp_hash_d(&sc, fpr_add(a, b));
				b = fpr_neg(b);
				testfp_hash_d(&sc, fpr_add(a, b));
				a = fpr_neg(a);
				testfp_hash_d(&sc, fpr_add(a, b));
			}
		}
		printf(".");
		fflush(stdout);
	}
	printf(" ");
	fflush(stdout);

	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, (const uint8_t *)"fpemu", 5);
	inner_shake256_flip(&rng);
	Zf(prng_init)(&p, &rng);
	for (ctr = 1; ctr <= 65536L; ctr ++) {
		fpr a, b;
		int64_t j;

		*(uint64_t *)&j = prng_get_u64(&p);
		j >>= (int)(ctr & 63);
		a = fpr_of(j);
		testfp_hash_d(&sc, a);

		e = prng_get_u8(&p);
		e -= 128;
		a = fpr_scaled(j, e);
		testfp_hash_d(&sc, a);

		*(uint64_t *)&j = prng_get_u64(&p);
		a = fpr_scaled(j, -8);
		testfp_hash_d(&sc, a);
		testfp_hash_u(&sc, (uint64_t)fpr_rint(a));
		a = fpr_scaled(j, -52);
		testfp_hash_d(&sc, a);
		testfp_hash_u(&sc, (uint64_t)fpr_floor(a));

		a = rand_fp(&p);
		b = rand_fp(&p);

		for (e = -60; e <= 60; e ++) {
			testfp_hash_d(&sc, fpr_ldexp(a, e));
		}

		testfp_hash_u(&sc, fpr_lt(a, b));
		testfp_hash_u(&sc, fpr_lt(a, a));

		testfp_hash_d(&sc, fpr_add(a, b));
		testfp_hash_d(&sc, fpr_add(b, a));
		testfp_hash_d(&sc, fpr_add(a, fpr_zero));
		testfp_hash_d(&sc, fpr_add(fpr_zero, a));
		testfp_hash_d(&sc, fpr_add(a, fpr_neg(a)));
		testfp_hash_d(&sc, fpr_add(fpr_neg(a), a));

		testfp_hash_d(&sc, fpr_sub(a, b));
		testfp_hash_d(&sc, fpr_sub(b, a));
		testfp_hash_d(&sc, fpr_sub(a, fpr_zero));
		testfp_hash_d(&sc, fpr_sub(fpr_zero, a));
		testfp_hash_d(&sc, fpr_sub(a, a));

		testfp_hash_d(&sc, fpr_neg(a));
		testfp_hash_d(&sc, fpr_half(a));
		testfp_hash_d(&sc, fpr_double(a));

		testfp_hash_d(&sc, fpr_mul(a, b));
		testfp_hash_d(&sc, fpr_mul(b, a));
		testfp_hash_d(&sc, fpr_mul(a, fpr_zero));
		testfp_hash_d(&sc, fpr_mul(fpr_zero, a));

		if (fpr_lt(b, fpr_zero) || fpr_lt(fpr_zero, b)) {
			testfp_hash_d(&sc, fpr_div(a, b));
		}
		if (fpr_lt(a, fpr_zero)) {
			a = fpr_neg(a);
		}
		testfp_hash_d(&sc, fpr_sqrt(a));

		if ((ctr & 0x3FF) == 0) {
			printf(".");
			fflush(stdout);
		}
	}

	/*
	 * Should be: 77cea0ea343b8c1c578af7c9fa3267b6
	 */

	inner_shake256_flip(&sc);
	inner_shake256_extract(&sc, tmp, sizeof tmp);
	printf(" ");
	for (u = 0; u < sizeof tmp; u ++) {
		printf("%02x", tmp[u]);
	}
	hextobin(tmp2, sizeof tmp2, "77cea0ea343b8c1c578af7c9fa3267b6");
	if (memcmp(tmp, tmp2, sizeof tmp) != 0) {
		fprintf(stderr, "Wrong hash"
			" (expected: 77cea0ea343b8c1c578af7c9fa3267b6)\n");
		exit(EXIT_FAILURE);
	}

	printf(" done.\n");
	fflush(stdout);
}

#if 0
/*
 * Similar to test_FP_block(), but using the native 'double' as expected
 * values; this can be used to pinpoint discrepancies. IMPORTANT: this
 * assumes that the native 'double' faithfully follows IEEE 754. In
 * particular, software emulation shipped with GCC 7.3.0 for ARM Cortex
 * M4 sometimes gets rounding wrong in the last bit; in that case, the
 * code below would report an error while the Falcon FP emulation is
 * actually the correct one.
 */

static uint64_t
double_to_u64(double x)
{
	union {
		double d;
		uint64_t u;
	} t;

	t.d = x;
	return t.u;
}

static double
u64_to_double(uint64_t x)
{
	union {
		double d;
		uint64_t u;
	} t;

	t.u = x;
	return t.d;
}

static void
check_fpeq(const char *name, fpr a, double ax)
{
	uint64_t au;

	au = double_to_u64(ax);
	if (a != au) {
		fprintf(stderr, "ERR (%s):\n", name);
		fprintf(stderr, "  %20llu   %.20f\n",
			(unsigned long long)a, u64_to_double(a));
		fprintf(stderr, "  %20llu   %.20f\n",
			(unsigned long long)au, ax);
		exit(EXIT_FAILURE);
	}
}

static void
check_fpeq1(const char *name, fpr a, fpr c, double cx)
{
	uint64_t cu;

	cu = double_to_u64(cx);
	if (c != cu) {
		fprintf(stderr, "ERR (%s):\n", name);
		fprintf(stderr, "  a =  %20llu   %.20f\n",
			(unsigned long long)a, u64_to_double(a));
		fprintf(stderr, "  c =  %20llu   %.20f\n",
			(unsigned long long)c, u64_to_double(c));
		fprintf(stderr, "  x =  %20llu   %.20f\n",
			(unsigned long long)cu, cx);
		exit(EXIT_FAILURE);
	}
}

static void
check_fpeq2(const char *name, fpr a, fpr b, fpr c, double cx)
{
	uint64_t cu;

	cu = double_to_u64(cx);
	if (c != cu) {
		fprintf(stderr, "ERR (%s):\n", name);
		fprintf(stderr, "  a =  %20llu   %.20f\n",
			(unsigned long long)a, u64_to_double(a));
		fprintf(stderr, "  b =  %20llu   %.20f\n",
			(unsigned long long)b, u64_to_double(b));
		fprintf(stderr, "  c =  %20llu   %.20f\n",
			(unsigned long long)c, u64_to_double(c));
		fprintf(stderr, "  x =  %20llu   %.20f\n",
			(unsigned long long)cu, cx);
		exit(EXIT_FAILURE);
	}
}

static void
test_FP_detailed(void)
{
	long ctr;
	inner_shake256_context rng;
	prng p;
	int e;
	fpr nzero;

	printf("Test floating-point (detailed): ");
	fflush(stdout);

	check_fpeq("fpr_of(0)", fpr_of(0), 0.0);
	check_fpeq1("fpr_neg(0)", fpr_zero, fpr_neg(fpr_zero), -0.0);
	check_fpeq1("fpr_half(0)", fpr_zero, fpr_half(fpr_zero), 0.0);
	check_fpeq1("fpr_double(0)", fpr_zero, fpr_double(fpr_zero), 0.0);

	nzero = fpr_neg(fpr_zero);
	check_fpeq("fpr_add(+0,+0)", fpr_add(fpr_zero, fpr_zero), 0.0 + 0.0);
	check_fpeq("fpr_add(+0,-0)", fpr_add(fpr_zero, nzero), 0.0 + (-0.0));
	check_fpeq("fpr_add(-0,+0)", fpr_add(nzero, fpr_zero), (-0.0) + 0.0);
	check_fpeq("fpr_add(-0,-0)", fpr_add(nzero, nzero), (-0.0) + (-0.0));
	check_fpeq("fpr_sub(+0,+0)", fpr_add(fpr_zero, fpr_zero), 0.0 + 0.0);
	check_fpeq("fpr_sub(+0,-0)", fpr_add(fpr_zero, nzero), 0.0 + (-0.0));
	check_fpeq("fpr_sub(-0,+0)", fpr_add(nzero, fpr_zero), (-0.0) + 0.0);
	check_fpeq("fpr_sub(-0,-0)", fpr_add(nzero, nzero), (-0.0) + (-0.0));

	for (e = -60; e <= +60; e ++) {
		fpr a, b;
		double ax, bx;
		int i, j;

		for (i = -5; i <= +5; i ++) {
			a = fpr_of(((int64_t)1 << 53) + i);
			ax = ldexp(1.0, 53) + (double)i;
			check_fpeq("fpr_of+", a, ax);
			for (j = -5; j <= +5; j ++) {
				b = fpr_scaled(((int64_t)1 << 53) + j, e);
				bx = ldexp(ldexp(1.0, 53) + (double)j, e);
				check_fpeq("fpr_scaled+", b, bx);

				check_fpeq2("fpr_add1+",
					a, b, fpr_add(a, b), ax + bx);
				a = fpr_neg(a);
				check_fpeq2("fpr_add2+",
					a, b, fpr_add(a, b), bx - ax);
				b = fpr_neg(b);
				check_fpeq2("fpr_add3+",
					a, b, fpr_add(a, b), -bx - ax);
				a = fpr_neg(a);
				check_fpeq2("fpr_add4+",
					a, b, fpr_add(a, b), ax - bx);
			}
		}
		printf(".");
		fflush(stdout);
	}
	printf(" ");
	fflush(stdout);

	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, (const uint8_t *)"fpemu", 5);
	inner_shake256_flip(&rng);
	Zf(prng_init)(&p, &rng);
	for (ctr = 1; ctr <= 65536L; ctr ++) {
		fpr a, b;
		double ax, bx;
		int64_t j;
		int sc;

		*(uint64_t *)&j = prng_get_u64(&p);
		j >>= (int)(ctr & 63);
		a = fpr_of(j);
		ax = (double)j;
		check_fpeq("fpr_of", a, ax);

		sc = prng_get_u8(&p);
		sc -= 128;
		a = fpr_scaled(j, sc);
		ax = ldexp((double)j, sc);
		check_fpeq("fpr_scaled", a, ax);

		*(uint64_t *)&j = prng_get_u64(&p);
		a = fpr_scaled(j, -8);
		ax = ldexp((double)j, -8);
		if (fpr_rint(a) != llrint(ax)) {
			fprintf(stderr,
				"ERR (fpr_rint): %.7f -> %lld / %lld\n",
				ax,
				(long long)fpr_rint(a), (long long)llrint(ax));
			exit(EXIT_FAILURE);
		}
		a = fpr_scaled(j, -52);
		ax = ldexp((double)j, -52);
		if (fpr_trunc(a) != (long)ax) {
			fprintf(stderr,
				"ERR (fpr_trunc): %.7f -> %ld / %ld\n",
				ax,
				(long)fpr_trunc(a), (long)ax);
			exit(EXIT_FAILURE);
		}

		a = rand_fp(&p);
		b = rand_fp(&p);
		ax = u64_to_double(a);
		bx = u64_to_double(b);

		for (sc = -60; sc <= 60; sc ++) {
			check_fpeq1("fpr_ldexp", a,
				fpr_ldexp(a, sc), ldexp(ax, sc));
		}

		if (fpr_lt(a, b) != (ax < bx)) {
			fprintf(stderr,
				"ERR (fpr_lt): %.7f / %.7f\n",
				u64_to_double(ax), u64_to_double(bx));
			exit(EXIT_FAILURE);
		}
		if (fpr_lt(a, a) != 0) {
			fprintf(stderr,
				"ERR (fpr_lt): %.7f / (self)\n",
				u64_to_double(ax));
			exit(EXIT_FAILURE);
		}

		check_fpeq2("fpr_add 1", a, b, fpr_add(a, b), ax + bx);
		check_fpeq2("fpr_add 2", b, a, fpr_add(b, a), bx + ax);
		check_fpeq2("fpr_add 3", a, fpr_zero,
			fpr_add(a, fpr_zero), ax + 0.0);
		check_fpeq2("fpr_add 4", fpr_zero, a,
			fpr_add(fpr_zero, a), 0.0 + ax);
		check_fpeq1("fpr_add 5", a, fpr_add(a, fpr_neg(a)), ax + (-ax));
		check_fpeq1("fpr_add 6", a, fpr_add(fpr_neg(a), a), (-ax) + ax);

		check_fpeq2("fpr_sub 1", a, b, fpr_sub(a, b), ax - bx);
		check_fpeq2("fpr_sub 2", b, a, fpr_sub(b, a), bx - ax);
		check_fpeq2("fpr_sub 3", a, fpr_zero,
			fpr_sub(a, fpr_zero), ax - 0.0);
		check_fpeq2("fpr_sub 4", fpr_zero, a,
			fpr_sub(fpr_zero, a), 0.0 - ax);
		check_fpeq("fpr_sub 5", fpr_sub(a, a), ax - ax);

		check_fpeq1("fpr_neg", a, fpr_neg(a), -ax);
		check_fpeq1("fpr_half", a, fpr_half(a), ax * 0.5);
		check_fpeq1("fpr_double", a, fpr_double(a), ax * 2.0);

		check_fpeq2("fpr_mul 1", a, b, fpr_mul(a, b), ax * bx);
		check_fpeq2("fpr_mul 2", a, b, fpr_mul(b, a), bx * ax);
		check_fpeq2("fpr_mul 3", a, fpr_zero,
			fpr_mul(a, fpr_zero), ax * 0.0);
		check_fpeq2("fpr_mul 4", fpr_zero, a,
			fpr_mul(fpr_zero, a), 0.0 * ax);

		if (bx != 0.0) {
			check_fpeq2("fpr_div", a, b, fpr_div(a, b), ax / bx);
		}
		if (fpr_lt(a, fpr_zero)) {
			a = fpr_neg(a);
		}
		check_fpeq1("fpr_sqrt", a, fpr_sqrt(a), sqrt(fabs(ax)));

		if ((ctr & 0x3FF) == 0) {
			printf(".");
			fflush(stdout);
		}
	}

	printf(" done.\n");
	fflush(stdout);
}

#endif

/*
 * Make a polynomial with random coefficients in -512..511 (uniform).
 */
static void
mk_rand_poly(prng *p, fpr *f, unsigned logn)
{
	size_t u, n;

	n = (size_t)1 << logn;
	for (u = 0; u < n; u ++) {
		int32_t x;
		
		x = prng_get_u8(p);
		x = (x << 8) + prng_get_u8(p);
		x &= 0x3FF;
		f[u] = fpr_of(x - 512);
	}
}

static void
test_poly_inner(unsigned logn, uint8_t *tmp, size_t tlen)
{
	unsigned long ctr, num;
	inner_shake256_context rng;
	prng p;
	uint8_t xb;
	size_t n;

	printf("[%u]", logn);
	fflush(stdout);

	n = (size_t)1 << logn;
	if (tlen < 5 * n * sizeof(fpr)) {
		fprintf(stderr, "Insufficient buffer size\n");
		exit(EXIT_FAILURE);
	}
	inner_shake256_init(&rng);
	xb = logn;
	inner_shake256_inject(&rng, &xb, 1);
	inner_shake256_flip(&rng);
	Zf(prng_init)(&p, &rng);
	num = 131072UL >> logn;
	for (ctr = 0; ctr < num; ctr ++) {
		fpr *f, *g, *h;
		fpr *f0, *f1, *g0, *g1;
		size_t u;

		f = (fpr *)tmp;
		g = f + n;
		h = g + n;
		f0 = h + n;
		f1 = f0 + (n >> 1);
		g0 = f1 + (n >> 1);
		g1 = g0 + (n >> 1);
		mk_rand_poly(&p, f, logn);
		memcpy(g, f, n * sizeof *f);
		Zf(FFT)(g, logn);
		Zf(iFFT)(g, logn);
		for (u = 0; u < n; u ++) {
			if (fpr_rint(f[u]) != fpr_rint(g[u])) {
				fprintf(stderr, "FFT/iFFT error\n");
				exit(EXIT_FAILURE);
			}
		}

		mk_rand_poly(&p, g, logn);
		for (u = 0; u < n; u ++) {
			h[u] = fpr_of(0);
		}
		for (u = 0; u < n; u ++) {
			size_t v;

			for (v = 0; v < n; v ++) {
				fpr s;
				size_t k;

				s = fpr_mul(f[u], g[v]);
				k = u + v;
				if (k >= n) {
					k -= n;
					s = fpr_neg(s);
				}
				h[k] = fpr_add(h[k], s);
			}
		}
		Zf(FFT)(f, logn);
		Zf(FFT)(g, logn);
		Zf(poly_mul_fft)(f, g, logn);
		Zf(iFFT)(f, logn);
		for (u = 0; u < n; u ++) {
			if (fpr_rint(f[u]) != fpr_rint(h[u])) {
				fprintf(stderr, "FFT mul error\n");
				exit(EXIT_FAILURE);
			}
		}

		mk_rand_poly(&p, f, logn);
		memcpy(h, f, n * sizeof *f);
		Zf(FFT)(f, logn);
		Zf(poly_split_fft)(f0, f1, f, logn);

		memcpy(g0, f0, (n >> 1) * sizeof *f0);
		memcpy(g1, f1, (n >> 1) * sizeof *f1);
		Zf(iFFT)(g0, logn - 1);
		Zf(iFFT)(g1, logn - 1);
		for (u = 0; u < (n >> 1); u ++) {
			if (fpr_rint(g0[u]) != fpr_rint(h[(u << 1) + 0])
				|| fpr_rint(g1[u]) != fpr_rint(h[(u << 1) + 1]))
			{
				fprintf(stderr, "split error\n");
				exit(EXIT_FAILURE);
			}
		}

		Zf(poly_merge_fft)(g, f0, f1, logn);
		Zf(iFFT)(g, logn);
		for (u = 0; u < n; u ++) {
			if (fpr_rint(g[u]) != fpr_rint(h[u])) {
				fprintf(stderr, "split/merge error\n");
				exit(EXIT_FAILURE);
			}
		}

		if (((ctr + 1) & 0xFF) == 0) {
			printf(".");
			fflush(stdout);
		}
	}
}

static void
test_poly(void)
{
	unsigned logn;
	uint8_t *tmp;
	size_t tlen;

	printf("Test polynomials: ");
	fflush(stdout);
	tlen = 40960;
	tmp = xmalloc(tlen);
	for (logn = 1; logn <= 10; logn ++) {
		test_poly_inner(logn, tmp, tlen);
	}
	xfree(tmp);
	printf(" done.\n");
	fflush(stdout);
}

typedef struct {
	uint8_t v[9];
} u72;

static void
u72_set_zero(u72 *x)
{
	memset(x->v, 0, sizeof x->v);
}

static unsigned
u72_add_small(u72 *x, unsigned d)
{
	size_t u;

	for (u = 0; u < sizeof x->v; u ++) {
		unsigned w;

		w = x->v[u] + d;
		x->v[u] = (w & 0xFF);
		d = w >> 8;
	}
	return d;
}

static unsigned
u72_add(u72 *x, const u72 *y)
{
	size_t u;
	unsigned cc;

	cc = 0;
	for (u = 0; u < sizeof x->v; u ++) {
		unsigned w;

		w = x->v[u] + y->v[u] + cc;
		x->v[u] = (w & 0xFF);
		cc = w >> 8;
	}
	return cc;
}

static void
u72_from_decimal(u72 *x, const char *str)
{
	u72_set_zero(x);
	while (*str != 0) {
		size_t u;
		unsigned cc;

		cc = 0;
		for (u = 0; u < sizeof x->v; u ++) {
			unsigned w;

			w = (x->v[u] * 10) + cc;
			x->v[u] = w & 0xFF;
			cc = w >> 8;
		}
		u72_add_small(x, (*str ++) - '0');
	}
}

/*
 * Expected probability distribution, as specified in the
 * Prest-Ricosset-Rossi paper: "Simple, Fast and Constant-Time Gaussian
 * Sampling over the Integers for Falcon"
 *
 * The sum of these values is exactly 2^72.
 * gaussian0_sampler() uses a CDT that splits the 0..2^72-1 range into
 * ranges of the right size to achieve the relevant probabilities:
 *    P(18) = 1*2^(-72)       -> 0
 *    P(17) = 197*2^(-72)     -> 1..197
 *    P(16) = 28626*2^(-72)   -> 198..28823
 * (etc)
 */
static const char *GAUSSIAN0_DIST[] = {
	"1697680241746640300030",
	"1459943456642912959616",
	 "928488355018011056515",
	 "436693944817054414619",
	 "151893140790369201013",
	  "39071441848292237840",
	   "7432604049020375675",
	   "1045641569992574730",
	    "108788995549429682",
	      "8370422445201343",
	       "476288472308334",
	        "20042553305308",
	          "623729532807",
	           "14354889437",
	             "244322621",
	               "3075302",
	                 "28626",
	                   "197",
	                     "1"
};

static void
prefill_prng(prng *p, const void *buf, size_t len)
{
	memcpy(p->buf.d, buf, len);
	p->ptr = 0;
}

static void
check_gaussian0_sampler(const u72 *x, int r)
{
	prng p;
	int z;

	prefill_prng(&p, x->v, sizeof x->v);
	z = Zf(gaussian0_sampler)(&p);
	if (z != r) {
		size_t u;

		fprintf(stderr,
			"wrong half-Gaussian output %d (exp: %d), val = 0x",
			z, r);
		for (u = sizeof x->v; u > 0; u --) {
			fprintf(stderr, "%02X", x->v[u - 1]);
		}
		fprintf(stderr, "\n");
		exit(EXIT_FAILURE);
	}
}

static void
test_gaussian0_sampler(void)
{
	u72 t, s;
	int i;

	printf("Test half-Gaussian sampler: ");
	fflush(stdout);

	/*
	 * gaussian0_sampler() reads a 72-bit value from the PRNG,
	 * and follows a CDT table. Bottom value is 18; it should be
	 * obtained when the PRNG bytes are all zeros.
	 */
	u72_set_zero(&t);
	check_gaussian0_sampler(&t, 18);

	/*
	 * Each iteration exercises the two extremes of the range:
	 *   t+1, where t is the maximum of the previous range
	 *   t+dist[i], where dist[i] is from the table in the source article
	 */
	for (i = 17; i >= 0; i --) {
		s = t;
		u72_add_small(&s, 1);
		check_gaussian0_sampler(&s, i);
		u72_from_decimal(&s, GAUSSIAN0_DIST[i]);
		u72_add(&t, &s);
		check_gaussian0_sampler(&t, i);

		printf(".");
		fflush(stdout);
	}

	/*
	 * At that point, t is the top value of the highest range; thus,
	 * it should be (2^72)-1. We check it by adding 1: this should
	 * yield a carry.
	 */
	if (u72_add_small(&t, 1) != 1) {
		fprintf(stderr, "wrong distribution sum\n");
		exit(EXIT_FAILURE);
	}

	printf(" done.\n");
	fflush(stdout);
}

static fpr
make_fpr(int64_t m, int sc)
{
	fpr x;

	x = fpr_of(m);
	if (sc > 0) {
		while (sc -- > 0) {
			x = fpr_double(x);
		}
	} else {
		while (sc ++ < 0) {
			x = fpr_half(x);
		}
	}
	return x;
}

/*
 * Custom exponential computation.
 *
 * If |x| >= 512*log(2) then this function returns exactly 0 (this is
 * meant to avoid subnormals or infinites, which are not necessarily
 * supported by the underlying 'fpr' implementation).
 */
static fpr
approximate_exp(fpr x)
{
	/*
	 * We need a few constants, but we cannot make them actual
	 * constants since that depends on how the fpr type is implemented.
	 * Instead, we use a run-once block of code.
	 */
	static fpr RANGE_MIN, RANGE_MAX, P1, P2, P3, P4, P5;
	static int init = 0;

	if (!init) {
		RANGE_MIN = make_fpr(-6243314768165359, -54);
		RANGE_MAX = make_fpr(6243314768165359, -54);
		P1 = make_fpr(6004799503160638, -55);
		P2 = make_fpr(-6405119469862291, -61);
		P3 = make_fpr(4880090809097772, -66);
		P4 = make_fpr(-7807914560613361, -72);
		P5 = make_fpr(6253375523824848, -77);
		init = 1;
	}

	int k;
	fpr t, c;

	/*
	 * First halve the value repeatedly until it is in the
	 * +/-0.5*log(2) range.
	 */
	k = 0;
	for (;;) {
		if (fpr_lt(RANGE_MIN, x) && fpr_lt(x, RANGE_MAX)) {
			break;
		}
		x = fpr_half(x);
		k ++;
	}
	if (k > 10) {
		return fpr_zero;
	}

	/*
	 * Apply the approximation function from fdlibm:
	 *   http://www.netlib.org/fdlibm/e_exp.c
	 */
	t = fpr_sqr(x);
	c = fpr_sub(x, fpr_mul(t,
		fpr_add(P1, fpr_mul(t,
			fpr_add(P2, fpr_mul(t,
				fpr_add(P3, fpr_mul(t,
					fpr_add(P4, fpr_mul(t, P5))))))))));
	x = fpr_sub(fpr_one, fpr_sub(
		fpr_div(fpr_mul(x, c), fpr_sub(c, fpr_two)), x));

	/*
	 * Square repeatedly to cancel the initial halvings.
	 */
	while (k -- > 0) {
		x = fpr_sqr(x);
	}
	return x;
}

/*
 * For given center mu, and isigma = 1/sigma (where sigma is the standard
 * deviation of the distribution for sampling), run the sampler many
 * times, and use a chi square test to compare the result with the
 * expected distribution.
 */
static void
test_sampler_rand(sampler_context *sc, fpr mu, fpr isigma)
{
#define MAX_DEV           30
#define NUM_SAMPLES   100000

	static fpr chi_dt_13, chi_dt_14;
	static int init = 0;

	int z, zmin, zmax, df;
	long ctr, szlo, szhi;
	long zz[1 + (MAX_DEV << 1)];
	fpr rzz[1 + (MAX_DEV << 1)];
	int c;
	fpr s, chi, elo, ehi;

	/*
	 * One-time initialization code to have the chi-square critical
	 * values for 13 and 14 degrees of freedom. We use alpha = 0.01.
	 *
	 * Indeed, when the chi-square test statistic is above the
	 * critical value, then this means that, under the null
	 * hypothesis (i.e. the hypothesis that the sampler really
	 * follows the expected distribution), what we obtained could
	 * have occurred with probability less than alpha. The null
	 * hypothesis is said to be rejected when that probability is
	 * "too low". The traditional significance level is alpha =
	 * 0.05, which means that events which happen less than 1/20th
	 * of the time are deemed "too improbable". But we are going
	 * to call this test_sampler_rand() function more than 20 times,
	 * thus events that occur with probability 1/20 will really
	 * happen. Using alpha = 0.01 appears to let our tests pass.
	 */
	if (!init) {
		chi_dt_13 = make_fpr(7794042105118065, -48); /* 27.69 */
		chi_dt_14 = make_fpr(8202180821348516, -48); /* 29.14 */
		init = 1;
	}

	/*
	 * We call the sampler 100000 times and check that each value is
	 * within +/-30 of the center. We also accumulate the values.
	 */
	c = (int)fpr_trunc(mu);
	for (z = -MAX_DEV; z <= +MAX_DEV; z ++) {
		zz[z + MAX_DEV] = 0;
	}
	for (ctr = 0; ctr < NUM_SAMPLES; ctr ++) {
		z = Zf(sampler)(sc, mu, isigma);
		z -= c;
		if (z < -MAX_DEV || z > +MAX_DEV) {
			fprintf(stderr, "out-of-range sampled value: %d\n", z);
			exit(EXIT_FAILURE);
		}
		zz[z + MAX_DEV] ++;
	}

	/*
	 * Distribution should have approximately the right shape. With
	 * only 100000 samples, we cannot detect small deviations, but we
	 * can still check that the overall shape is proper. Expected
	 * distribution is:
	 *
	 *   P(z) = K*exp(-((z-mu)^2 / 2*(sigma^2)))
	 *
	 * where K is a constant such that the sum over all integers z
	 * is 1.
	 *
	 * We compute into rzz[] the expected number of outcomes (for
	 * the used total number of samples).
	 */
	s = fpr_zero;
	for (z = -MAX_DEV; z <= +MAX_DEV; z ++) {
		fpr x;

		x = fpr_sqr(fpr_sub(fpr_of(z + c), mu));
		x = fpr_mul(x, fpr_sqr(isigma));
		x = fpr_neg(fpr_half(x));
		rzz[z + MAX_DEV] = approximate_exp(x);
		s = fpr_add(rzz[z + MAX_DEV], s);
	}
	s = fpr_div(fpr_of(NUM_SAMPLES), s);
	for (z = -MAX_DEV; z <= +MAX_DEV; z ++) {
		rzz[z + MAX_DEV] = fpr_mul(rzz[z + MAX_DEV], s);
	}

	/*
	 * Now that we have the expected distribution, we can compute a
	 * simple chi-square test over what we actually obtained.
	 *
	 * For better test accuracy, we group the two tails of the
	 * distribution into two 'bins': one for z <= zmin, the other
	 * for z >= zmax. Values zmin and zmax are set so that the
	 * expected number of samples in each bin is at least 5.
	 */
	elo = fpr_zero;
	for (zmin = -MAX_DEV;; zmin ++) {
		elo = fpr_add(elo, rzz[zmin + MAX_DEV]);
		if (!fpr_lt(elo, fpr_of(5))) {
			break;
		}
	}
	ehi = fpr_zero;
	for (zmax = +MAX_DEV;; zmax --) {
		ehi = fpr_add(ehi, rzz[zmax + MAX_DEV]);
		if (!fpr_lt(ehi, fpr_of(5))) {
			break;
		}
	}

	szlo = 0;
	for (z = -MAX_DEV; z <= zmin; z ++) {
		szlo += zz[z + MAX_DEV];
	}
	szhi = 0;
	for (z = zmax; z <= +MAX_DEV; z ++) {
		szhi += zz[z + MAX_DEV];
	}
	chi = fpr_zero;
	for (z = zmin + 1; z <= zmax - 1; z ++) {
		fpr x, e;

		x = fpr_of(zz[z + MAX_DEV]);
		e = rzz[z + MAX_DEV];
		chi = fpr_add(chi, fpr_div(fpr_sqr(fpr_sub(x, e)), e));
	}

	chi = fpr_add(chi, fpr_div(fpr_sqr(fpr_sub(fpr_of(szlo), elo)), elo));
	chi = fpr_add(chi, fpr_div(fpr_sqr(fpr_sub(fpr_of(szhi), ehi)), ehi));

	/*
	 * In practice, (zmin,zmax) = (-6,7) or (-7,7), i.e. we have either
	 * 14 or 15 classes. The number of degrees of freedom is then 13
	 * or 14.
	 */
	df = zmax - zmin;
	if (df == 13) {
		if (!fpr_lt(chi, chi_dt_13)) {
			fprintf(stderr, "chi-square test fail\n");
			exit(EXIT_FAILURE);
		}
	} else if (df == 14) {
		if (!fpr_lt(chi, chi_dt_14)) {
			fprintf(stderr, "chi-square test fail\n");
			exit(EXIT_FAILURE);
		}
	} else {
		fprintf(stderr, "unexpected number of classes: %d\n",
			zmax - zmin + 1);
		exit(EXIT_FAILURE);
	}

#undef MAX_DEV
#undef NUM_SAMPLES
}

static void
test_sampler(void)
{
	inner_shake256_context rng;
	sampler_context sc;
	fpr isigma, mu, muinc;
	int i;

	printf("Test sampler: ");
	fflush(stdout);

	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, (const void *)"test sampler", 12);
	inner_shake256_flip(&rng);
	Zf(prng_init)(&sc.p, &rng);
	sc.sigma_min = fpr_sigma_min[9];

	isigma = fpr_div(fpr_of(10), fpr_of(17));
	mu = fpr_neg(fpr_one);
	muinc = fpr_div(fpr_one, fpr_of(10));
	for (i = 0; i < 21; i ++) {
		test_sampler_rand(&sc, mu, isigma);
		mu = fpr_add(mu, muinc);

		printf(".");
		fflush(stdout);
	}

	printf(" done.\n");
	fflush(stdout);
}

static void
test_sign_self(const int8_t *f, const int8_t *g,
	const int8_t *F, const int8_t *G, const uint16_t *h_src,
	unsigned logn, uint8_t *tmp)
{
	int i;
	size_t n;
	inner_shake256_context rng;
	char buf[20];
	uint16_t *h, *hm, *hm2;
	int16_t *sig;
	uint8_t *tt;
	fpr *expanded_key;

	n = (size_t)1 << logn;
	h = (uint16_t *)tmp;
	hm = h + n;
	sig = (int16_t *)(hm + n);
	hm2 = (uint16_t *)sig;
	tt = (uint8_t *)(sig + n);
	if (logn == 1) {
		tt += 4;
	}

	memcpy(h, h_src, n * sizeof *h);
	Zf(to_ntt_monty)(h, logn);

	/* sprintf(buf, "sign %u", logn); */
	memcpy(buf, "sign 0", 7);
	buf[5] = '0' + logn;

	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, (uint8_t *)buf, strlen(buf));
	inner_shake256_flip(&rng);
	for (i = 0; i < 100; i ++) {
		uint8_t msg[50];  /* nonce + plain */
		inner_shake256_context sc, sc2;
		size_t u;

		inner_shake256_extract(&rng, msg, sizeof msg);

		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, msg, sizeof msg);
		inner_shake256_flip(&sc);
		sc2 = sc;
		Zf(hash_to_point_vartime)(&sc, hm, logn);
		Zf(hash_to_point_ct)(&sc2, hm2, logn, tt);
		for (u = 0; u < n; u ++) {
			if (hm2[u] != hm[u]) {
				fprintf(stderr, "hash_to_point() mismatch\n");
				exit(EXIT_FAILURE);
			}
		}
		Zf(sign_dyn)(sig, &rng, f, g, F, G, hm, logn, tt);
		if (!Zf(verify_raw)(hm, sig, h, logn, tt)) {
			fprintf(stderr, "self signature (dyn) not verified\n");
			exit(EXIT_FAILURE);
		}

		if (i % 10 == 0) {
			printf(".");
			fflush(stdout);
		}
	}

	expanded_key = (fpr *)tt;
	tt = (uint8_t *)expanded_key + (8 * logn + 40) * n;
	Zf(expand_privkey)(expanded_key, f, g, F, G, logn, tt);

	for (i = 0; i < 100; i ++) {
		uint8_t msg[50];  /* nonce + plain */
		inner_shake256_context sc;

		inner_shake256_extract(&rng, msg, sizeof msg);

		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, msg, sizeof msg);
		inner_shake256_flip(&sc);
		Zf(hash_to_point_vartime)(&sc, hm, logn);
		Zf(sign_tree)(sig, &rng, expanded_key, hm, logn, tt);

		if (!Zf(verify_raw)(hm, sig, h, logn, tt)) {
			fprintf(stderr, "self signature (dyn) not verified\n");
			exit(EXIT_FAILURE);
		}

		if (i % 10 == 0) {
			printf(".");
			fflush(stdout);
		}
	}

	printf(" ");
	fflush(stdout);
}

static void
test_sign(void)
{
	uint8_t *tmp;
	size_t tlen;

	printf("Test sign: ");
	fflush(stdout);

	tlen = 178176;
	tmp = xmalloc(tlen);

	test_sign_self(ntru_f_16, ntru_g_16, ntru_F_16, ntru_G_16,
		ntru_h_16, 4, tmp);
	test_sign_self(ntru_f_512, ntru_g_512, ntru_F_512, ntru_G_512,
		ntru_h_512, 9, tmp);
	test_sign_self(ntru_f_1024, ntru_g_1024, ntru_F_1024, ntru_G_1024,
		ntru_h_1024, 10, tmp);

	xfree(tmp);

	printf("done.\n");
	fflush(stdout);
}

static void
test_keygen_inner(unsigned logn, uint8_t *tmp)
{
	size_t n;
	int8_t *f, *g, *F, *G;
	uint16_t *h, *hm, *h2;
	int16_t *sig, *s1;
	uint8_t *tt;
	int i;
	inner_shake256_context rng;
	char buf[20];

	printf("[%u]", logn);
	fflush(stdout);

	/* sprintf(buf, "keygen %u", logn); */
	memcpy(buf, "keygen 0", 9);
	buf[7] = '0' + logn;

	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, (uint8_t *)buf, strlen(buf));
	inner_shake256_flip(&rng);
	n = (size_t)1 << logn;
	f = (int8_t *)tmp;
	g = f + n;
	F = g + n;
	G = F + n;
	h = (uint16_t *)(G + n);
	h2 = h + n;
	hm = h2 + n;
	sig = (int16_t *)(hm + n);
	s1 = sig + n;
	tt = (uint8_t *)(s1 + n);
	if (logn == 1) {
		tt += 4;
	}
	for (i = 0; i < 12; i ++) {
		uint8_t msg[50];  /* nonce + message */
		inner_shake256_context sc;

		Zf(keygen)(&rng, f, g, F, G, h, logn, tt);

		inner_shake256_extract(&rng, msg, sizeof msg);

		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, msg, sizeof msg);
		inner_shake256_flip(&sc);
		Zf(hash_to_point_vartime)(&sc, hm, logn);
		do {
			Zf(sign_dyn)(sig, &rng, f, g, F, G, hm, logn, tt);
			memcpy(s1, tt, n * sizeof *s1);
		} while (!Zf(is_invertible)(sig, logn, tt));
		Zf(to_ntt_monty)(h, logn);
		if (!Zf(verify_raw)(hm, sig, h, logn, tt)) {
			fprintf(stderr, "self signature not verified\n");
			exit(EXIT_FAILURE);
		}
		if (!Zf(verify_recover)(h2, hm, s1, sig, logn, tt)) {
			fprintf(stderr, "self signature recovery failed\n");
			exit(EXIT_FAILURE);
		}
		Zf(to_ntt_monty)(h2, logn);
		check_eq(h, h2, n * sizeof *h, "recovered public key");

		printf(".");
		fflush(stdout);
	}
}

static void
test_keygen(void)
{
	uint8_t *tmp;
	size_t tlen;
	unsigned logn;

	printf("Test keygen: ");
	fflush(stdout);
	tlen = 90112;
	tmp = xmalloc(tlen);
	for (logn = 1; logn <= 10; logn ++) {
		test_keygen_inner(logn, tmp);
	}
	xfree(tmp);
	printf("done.\n");
	fflush(stdout);
}

static void
test_external_API_inner(unsigned logn, shake256_context *rng)
{
	int i;
	void *pubkey, *pubkey2, *privkey, *sig, *sigpad, *sigct, *expkey;
	size_t pubkey_len, privkey_len, sig_len, sigpad_len, sigct_len;
	size_t expkey_len;
	uint8_t *tmpkg, *tmpmp, *tmpsd, *tmpst, *tmpvv, *tmpek;
	size_t tmpkg_len, tmpmp_len, tmpsd_len, tmpst_len, tmpvv_len, tmpek_len;

	printf("[%u]", logn);
	fflush(stdout);

	pubkey_len = FALCON_PUBKEY_SIZE(logn);
	privkey_len = FALCON_PRIVKEY_SIZE(logn);
	sig_len = FALCON_SIG_COMPRESSED_MAXSIZE(logn);
	sigpad_len = FALCON_SIG_PADDED_SIZE(logn);
	sigct_len = FALCON_SIG_CT_SIZE(logn);
	expkey_len = FALCON_EXPANDEDKEY_SIZE(logn);

	pubkey = xmalloc(pubkey_len);
	pubkey2 = xmalloc(pubkey_len);
	privkey = xmalloc(privkey_len);
	sig = xmalloc(sig_len);
	sigpad = xmalloc(sig_len);
	sigct = xmalloc(sigct_len);
	expkey = xmalloc(expkey_len);

	tmpkg_len = FALCON_TMPSIZE_KEYGEN(logn);
	tmpmp_len = FALCON_TMPSIZE_MAKEPUB(logn);
	tmpsd_len = FALCON_TMPSIZE_SIGNDYN(logn);
	tmpst_len = FALCON_TMPSIZE_SIGNTREE(logn);
	tmpvv_len = FALCON_TMPSIZE_VERIFY(logn);
	tmpek_len = FALCON_TMPSIZE_EXPANDPRIV(logn);

	tmpkg = xmalloc(tmpkg_len);
	tmpmp = xmalloc(tmpmp_len);
	tmpsd = xmalloc(tmpsd_len);
	tmpst = xmalloc(tmpst_len);
	tmpvv = xmalloc(tmpvv_len);
	tmpek = xmalloc(tmpek_len);

	for (i = 0; i < 12; i ++) {
		int r;

		memset(privkey, 0, privkey_len);
		memset(pubkey, 0, pubkey_len);
		r = falcon_keygen_make(rng, logn, privkey, privkey_len,
			pubkey, pubkey_len, tmpkg, tmpkg_len);
		if (r != 0) {
			fprintf(stderr, "keygen failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		memset(pubkey2, 0xFF, pubkey_len);
		r = falcon_make_public(pubkey2, pubkey_len,
			privkey, privkey_len, tmpmp, tmpmp_len);
		if (r != 0) {
			fprintf(stderr, "makepub failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		check_eq(pubkey, pubkey2, pubkey_len, "pub / repub");

		r = falcon_get_logn(pubkey, pubkey_len);
		if (r != (int)logn) {
			fprintf(stderr, "get_logn failed: %d\n", r);
			exit(EXIT_FAILURE);
		}

		sig_len = FALCON_SIG_COMPRESSED_MAXSIZE(logn);
		memset(sig, 0, sig_len);
		r = falcon_sign_dyn(rng, sig, &sig_len, FALCON_SIG_COMPRESSED,
			privkey, privkey_len,
			"data1", 5, tmpsd, tmpsd_len);
		if (r != 0) {
			fprintf(stderr, "sign_dyn failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sig, sig_len, FALCON_SIG_COMPRESSED,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			/*
			 * At very low degrees, it may happen that the
			 * alternate data hashes to a point which is close
			 * enough to the correct one that the signature
			 * matches both. Thus, we skip that check for very
			 * low degrees.
			 */
			r = falcon_verify(sig, sig_len, FALCON_SIG_COMPRESSED,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr, "wrong verify err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		sigpad_len = FALCON_SIG_PADDED_SIZE(logn);
		memset(sigpad, 0, sigpad_len);
		r = falcon_sign_dyn(rng, sigpad, &sigpad_len, FALCON_SIG_PADDED,
			privkey, privkey_len,
			"data1", 5, tmpsd, tmpsd_len);
		if (r != 0) {
			fprintf(stderr, "sign_dyn(padded) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (sigpad_len != FALCON_SIG_PADDED_SIZE(logn)) {
			fprintf(stderr, "sign_dyn(padded): wrong length %lu\n",
				(unsigned long)sigpad_len);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sigpad, sigpad_len, FALCON_SIG_PADDED,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify(padded) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			r = falcon_verify(sigpad, sigpad_len, FALCON_SIG_PADDED,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr,
					"wrong verify(padded) err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		sigct_len = FALCON_SIG_CT_SIZE(logn);
		memset(sigct, 0, sigct_len);
		r = falcon_sign_dyn(rng, sigct, &sigct_len, FALCON_SIG_CT,
			privkey, privkey_len,
			"data1", 5, tmpsd, tmpsd_len);
		if (r != 0) {
			fprintf(stderr, "sign_dyn(ct) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (sigct_len != FALCON_SIG_CT_SIZE(logn)) {
			fprintf(stderr, "sign_dyn(ct): wrong length %lu\n",
				(unsigned long)sigct_len);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sigct, sigct_len, FALCON_SIG_CT,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify(ct) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			r = falcon_verify(sigct, sigct_len, FALCON_SIG_CT,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr,
					"wrong verify(ct) err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		r = falcon_expand_privkey(expkey, expkey_len,
			privkey, privkey_len, tmpek, tmpek_len);
		if (r != 0) {
			fprintf(stderr, "expand_privkey failed: %d\n", r);
			exit(EXIT_FAILURE);
		}

		sig_len = FALCON_SIG_COMPRESSED_MAXSIZE(logn);
		memset(sig, 0, sig_len);
		r = falcon_sign_tree(rng, sig, &sig_len, FALCON_SIG_COMPRESSED,
			expkey,
			"data1", 5, tmpst, tmpst_len);
		if (r != 0) {
			fprintf(stderr, "sign_tree failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sig, sig_len, FALCON_SIG_COMPRESSED,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify2 failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			r = falcon_verify(sig, sig_len, FALCON_SIG_COMPRESSED,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr, "wrong verify2 err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		sigpad_len = FALCON_SIG_PADDED_SIZE(logn);
		memset(sigpad, 0, sigpad_len);
		r = falcon_sign_tree(rng, sigpad, &sigpad_len,
			FALCON_SIG_PADDED,
			expkey,
			"data1", 5, tmpst, tmpst_len);
		if (r != 0) {
			fprintf(stderr, "sign_tree(padded) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sigpad, sigpad_len, FALCON_SIG_PADDED,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify2(padded) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			r = falcon_verify(sigpad, sigpad_len, FALCON_SIG_PADDED,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr,
					"wrong verify2(padded) err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		sigct_len = FALCON_SIG_CT_SIZE(logn);
		memset(sigct, 0, sigct_len);
		r = falcon_sign_tree(rng, sigct, &sigct_len, FALCON_SIG_CT,
			expkey,
			"data1", 5, tmpst, tmpst_len);
		if (r != 0) {
			fprintf(stderr, "sign_tree(ct) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		r = falcon_verify(sigct, sigct_len, FALCON_SIG_CT,
			pubkey, pubkey_len, "data1", 5, tmpvv, tmpvv_len);
		if (r != 0) {
			fprintf(stderr, "verify2(ct) failed: %d\n", r);
			exit(EXIT_FAILURE);
		}
		if (logn >= 5) {
			r = falcon_verify(sigct, sigct_len, FALCON_SIG_CT,
				pubkey, pubkey_len, "data2", 5,
				tmpvv, tmpvv_len);
			if (r != FALCON_ERR_BADSIG) {
				fprintf(stderr,
					"wrong verify2(ct) err: %d\n", r);
				exit(EXIT_FAILURE);
			}
		}

		printf(".");
		fflush(stdout);
	}

	xfree(pubkey);
	xfree(pubkey2);
	xfree(privkey);
	xfree(sig);
	xfree(sigpad);
	xfree(sigct);
	xfree(expkey);
	xfree(tmpkg);
	xfree(tmpmp);
	xfree(tmpsd);
	xfree(tmpst);
	xfree(tmpvv);
	xfree(tmpek);
}

static void
test_external_API(void)
{
	unsigned logn;
	shake256_context rng;

	printf("Test external API: ");
	fflush(stdout);

	shake256_init_prng_from_seed(&rng, "external", 8);
	for (logn = 1; logn <= 10; logn ++) {
		test_external_API_inner(logn, &rng);
	}

	printf("done.\n");
	fflush(stdout);
}

#if DO_NIST_TESTS

/* ===================================================================== */
/*
 * Custom perfunctory AES-256 implementation (included to avoid any
 * dependency on OpenSSL). This implementation is for tests only; it
 * is not constant-time.
 */

static inline uint32_t
dec32be(const void *src)
{
	const unsigned char *buf;

	buf = src;
	return ((uint32_t)buf[0] << 24)
		| ((uint32_t)buf[1] << 16)
		| ((uint32_t)buf[2] << 8)
		| (uint32_t)buf[3];
}

static inline void
enc32be(void *dst, uint32_t x)
{
	unsigned char *buf;

	buf = dst;
	buf[0] = (unsigned char)(x >> 24);
	buf[1] = (unsigned char)(x >> 16);
	buf[2] = (unsigned char)(x >> 8);
	buf[3] = (unsigned char)x;
}

static const uint32_t Rcon[] = {
	0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
	0x40000000, 0x80000000, 0x1B000000, 0x36000000
};

/* see inner.h */
static const unsigned char S[] = {
	0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
	0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
	0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
	0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
	0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
	0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
	0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
	0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
	0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
	0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
	0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
	0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
	0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
	0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
	0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
	0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
	0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
	0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
	0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
	0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
	0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
	0xB0, 0x54, 0xBB, 0x16
};

static uint32_t
SubWord(uint32_t x)
{
	return ((uint32_t)S[x >> 24] << 24)
		| ((uint32_t)S[(x >> 16) & 0xFF] << 16)
		| ((uint32_t)S[(x >> 8) & 0xFF] << 8)
		| (uint32_t)S[x & 0xFF];
}

static void
aes256_keysched(uint32_t *skey, const void *key)
{
	int i, j, k;

	for (i = 0; i < 8; i ++) {
		skey[i] = dec32be((const unsigned char *)key + (i << 2));
	}
	for (i = 8, j = 0, k = 0; i < 60; i ++) {
		uint32_t tmp;

		tmp = skey[i - 1];
		if (j == 0) {
			tmp = (tmp << 8) | (tmp >> 24);
			tmp = SubWord(tmp) ^ Rcon[k];
		} else if (j == 4) {
			tmp = SubWord(tmp);
		}
		skey[i] = skey[i - 8] ^ tmp;
		if (++ j == 8) {
			j = 0;
			k ++;
		}
	}
}

static const uint32_t Ssm0[] = {
	0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD,
	0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D,
	0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D,
	0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
	0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7,
	0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A,
	0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4,
	0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
	0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1,
	0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D,
	0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E,
	0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
	0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E,
	0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C,
	0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46,
	0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
	0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7,
	0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81,
	0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE,
	0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
	0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A,
	0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F,
	0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2,
	0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
	0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E,
	0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C,
	0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256,
	0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
	0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4,
	0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7,
	0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA,
	0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
	0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1,
	0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21,
	0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42,
	0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
	0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158,
	0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133,
	0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22,
	0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
	0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631,
	0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11,
	0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A
};

static inline uint32_t
rotr(uint32_t x, int n)
{
	return (x << (32 - n)) | (x >> n);
}

#define SboxExt0(x)   (Ssm0[x])
#define SboxExt1(x)   (rotr(Ssm0[x], 8))
#define SboxExt2(x)   (rotr(Ssm0[x], 16))
#define SboxExt3(x)   (rotr(Ssm0[x], 24))

static void
aes256_encrypt(const uint32_t *skey, void *data)
{
	unsigned char *buf;
	uint32_t s0, s1, s2, s3;
	uint32_t t0, t1, t2, t3;
	unsigned u;

	buf = data;
	s0 = dec32be(buf);
	s1 = dec32be(buf + 4);
	s2 = dec32be(buf + 8);
	s3 = dec32be(buf + 12);
	s0 ^= skey[0];
	s1 ^= skey[1];
	s2 ^= skey[2];
	s3 ^= skey[3];
	for (u = 1; u < 14; u ++) {
		uint32_t v0, v1, v2, v3;

		v0 = SboxExt0(s0 >> 24)
			^ SboxExt1((s1 >> 16) & 0xFF)
			^ SboxExt2((s2 >> 8) & 0xFF)
			^ SboxExt3(s3 & 0xFF);
		v1 = SboxExt0(s1 >> 24)
			^ SboxExt1((s2 >> 16) & 0xFF)
			^ SboxExt2((s3 >> 8) & 0xFF)
			^ SboxExt3(s0 & 0xFF);
		v2 = SboxExt0(s2 >> 24)
			^ SboxExt1((s3 >> 16) & 0xFF)
			^ SboxExt2((s0 >> 8) & 0xFF)
			^ SboxExt3(s1 & 0xFF);
		v3 = SboxExt0(s3 >> 24)
			^ SboxExt1((s0 >> 16) & 0xFF)
			^ SboxExt2((s1 >> 8) & 0xFF)
			^ SboxExt3(s2 & 0xFF);
		s0 = v0;
		s1 = v1;
		s2 = v2;
		s3 = v3;
		s0 ^= skey[u << 2];
		s1 ^= skey[(u << 2) + 1];
		s2 ^= skey[(u << 2) + 2];
		s3 ^= skey[(u << 2) + 3];
	}
	t0 = ((uint32_t)S[s0 >> 24] << 24)
		| ((uint32_t)S[(s1 >> 16) & 0xFF] << 16)
		| ((uint32_t)S[(s2 >> 8) & 0xFF] << 8)
		| (uint32_t)S[s3 & 0xFF];
	t1 = ((uint32_t)S[s1 >> 24] << 24)
		| ((uint32_t)S[(s2 >> 16) & 0xFF] << 16)
		| ((uint32_t)S[(s3 >> 8) & 0xFF] << 8)
		| (uint32_t)S[s0 & 0xFF];
	t2 = ((uint32_t)S[s2 >> 24] << 24)
		| ((uint32_t)S[(s3 >> 16) & 0xFF] << 16)
		| ((uint32_t)S[(s0 >> 8) & 0xFF] << 8)
		| (uint32_t)S[s1 & 0xFF];
	t3 = ((uint32_t)S[s3 >> 24] << 24)
		| ((uint32_t)S[(s0 >> 16) & 0xFF] << 16)
		| ((uint32_t)S[(s1 >> 8) & 0xFF] << 8)
		| (uint32_t)S[s2 & 0xFF];
	s0 = t0 ^ skey[56];
	s1 = t1 ^ skey[57];
	s2 = t2 ^ skey[58];
	s3 = t3 ^ skey[59];
	enc32be(buf, s0);
	enc32be(buf + 4, s1);
	enc32be(buf + 8, s2);
	enc32be(buf + 12, s3);
}

/* ===================================================================== */
/*
 * Perfunctory SHA-1 implementation.
 */

static void
sha1_round_inner(const uint8_t *buf, uint32_t *val)
{
#define F(B, C, D)     ((((C) ^ (D)) & (B)) ^ (D))
#define G(B, C, D)     ((B) ^ (C) ^ (D))
#define H(B, C, D)     (((D) & (C)) | (((D) | (C)) & (B)))
#define I(B, C, D)     G(B, C, D)

#define ROTL(x, n)    (((x) << (n)) | ((x) >> (32 - (n))))

#define K1     ((uint32_t)0x5A827999)
#define K2     ((uint32_t)0x6ED9EBA1)
#define K3     ((uint32_t)0x8F1BBCDC)
#define K4     ((uint32_t)0xCA62C1D6)

	uint32_t m[80];
	uint32_t a, b, c, d, e;
	int i;

	a = val[0];
	b = val[1];
	c = val[2];
	d = val[3];
	e = val[4];
	for (i = 0; i < 16; i ++) {
		m[i] = dec32be(&buf[i << 2]);
	}
	for (i = 16; i < 80; i ++) {
		uint32_t x;

		x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16];
		m[i] = ROTL(x, 1);
	}

	for (i = 0; i < 20; i += 5) {
		e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30);
		d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30);
		c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30);
		b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30);
		a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30);
	}
	for (i = 20; i < 40; i += 5) {
		e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30);
		d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30);
		c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30);
		b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30);
		a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30);
	}
	for (i = 40; i < 60; i += 5) {
		e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30);
		d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30);
		c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30);
		b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30);
		a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30);
	}
	for (i = 60; i < 80; i += 5) {
		e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30);
		d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30);
		c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30);
		b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30);
		a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30);
	}

	val[0] += a;
	val[1] += b;
	val[2] += c;
	val[3] += d;
	val[4] += e;

#undef F
#undef G
#undef H
#undef I
#undef ROTL
#undef K1
#undef K2
#undef K3
#undef K4
}

typedef struct {
	uint8_t buf[64];
	uint32_t val[5];
	uint64_t count;
} sha1_context;

static void
sha1_init(sha1_context *sc)
{
	static const uint32_t IV[5] = {
		0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
	};

	memset(sc->buf, 0, sizeof sc->buf);
	memcpy(sc->val, IV, sizeof sc->val);
	sc->count = 0;
}

static void
sha1_update(sha1_context *sc, const void *data, size_t len)
{
	const uint8_t *buf;
	size_t ptr;

	buf = data;
	ptr = (size_t)sc->count & 63;
	sc->count += (uint64_t)len;
	while (len > 0) {
		size_t clen;

		clen = 64 - ptr;
		if (clen > len) {
			clen = len;
		}
		memcpy(sc->buf + ptr, buf, clen);
		buf += clen;
		len -= clen;
		ptr += clen;
		if (ptr == 64) {
			sha1_round_inner(sc->buf, sc->val);
			ptr = 0;
		}
	}
}

static void
sha1_out(const sha1_context *cc, void *dst)
{
	uint8_t buf[64];
	uint32_t val[5];
	size_t ptr;
	int i;

	ptr = (size_t)cc->count & 63;
	memcpy(buf, cc->buf, ptr);
	memcpy(val, cc->val, sizeof val);
	buf[ptr ++] = 0x80;
	if (ptr > 56) {
		memset(buf + ptr, 0, 64 - ptr);
		sha1_round_inner(buf, val);
		memset(buf, 0, 56);
	} else {
		memset(buf + ptr, 0, 56 - ptr);
	}
	enc32be(buf + 56, (uint32_t)(cc->count >> 29));
	enc32be(buf + 60, (uint32_t)(cc->count << 3));
	sha1_round_inner(buf, val);
	for (i = 0; i < 5; i ++) {
		enc32be((uint8_t *)dst + (i << 2), val[i]);
	}
}

static void
sha1_print_line(sha1_context *sc, const char *s)
{
	char c;

	sha1_update(sc, s, strlen(s));
	c = '\n';
	sha1_update(sc, &c, 1);
}

static void
sha1_print_line_with_int(sha1_context *sc, const char *s, unsigned x)
{
	char tmp[30];
	size_t u;

	sha1_update(sc, s, strlen(s));
	u = sizeof tmp;
	tmp[-- u] = '\n';
	if (x == 0) {
		tmp[-- u] = '0';
	} else {
		while (x != 0) {
			tmp[-- u] = '0' + (x % 10);
			x /= 10;
		}
	}
	sha1_update(sc, tmp + u, (sizeof tmp) - u);
}

static void
sha1_print_line_with_hex(sha1_context *sc,
	const char *s, const void *data, size_t len)
{
	const uint8_t *buf;
	char c;

	sha1_update(sc, s, strlen(s));
	buf = data;
	while (len -- > 0) {
		unsigned b;
		char tmp[2];

		b = *buf ++;
		tmp[0] = "0123456789ABCDEF"[b >> 4];
		tmp[1] = "0123456789ABCDEF"[b & 15];
		sha1_update(sc, tmp, 2);
	}
	c = '\n';
	sha1_update(sc, &c, 1);
}

/* ===================================================================== */
/*
 * NIST test vectors.
 *
 * The code below reproduces the generation of test vectors as per the
 * code provided by NIST for the PQC process; a deterministic PRNG based
 * on AES-256 is used. The test_nist_KAT() function recomputes the NIST
 * vectors and compares the resulting hash value with the expected one.
 */

/*
 * Static state for the AES-based DRBG used in NIST tests.
 */
static uint8_t DRBG_key[32];
static uint8_t DRBG_V[16];

static void
aes256_DRBG_update(const uint8_t *provided_data, uint8_t *key, uint8_t *V)
{
	uint32_t skey[60];
	uint8_t tmp[48];
	int i, j;

	aes256_keysched(skey, key);
	for (i = 0; i < 3; i ++) {
		unsigned cc;

		cc = 1;
		for (j = 15; j >= 0; j --) {
			unsigned w;

			w = V[j] + cc;
			V[j] = (uint8_t)w;
			cc = w >> 8;
		}
		memcpy(tmp + (i << 4), V, 16);
		aes256_encrypt(skey, tmp + (i << 4));
	}
	if (provided_data != NULL) {
		for (i = 0; i < 48; i ++) {
			tmp[i] ^= provided_data[i];
		}
	}
	memcpy(key, tmp, 32);
	memcpy(V, tmp + 32, 16);
}

static void
nist_randombytes_init(uint8_t *entropy_input)
{
	memset(DRBG_key, 0x00, sizeof DRBG_key);
	memset(DRBG_V, 0x00, sizeof DRBG_V);
	aes256_DRBG_update(entropy_input, DRBG_key, DRBG_V);
}

static void
nist_randombytes(uint8_t *buf, size_t len)
{
	while (len > 0) {
		unsigned cc;
		uint32_t skey[60];
		uint8_t tmp[16];
		size_t clen;
		int j;

		cc = 1;
		for (j = 15; j >= 0; j --) {
			unsigned w;

			w = DRBG_V[j] + cc;
			DRBG_V[j] = (uint8_t)w;
			cc = w >> 8;
		}
		aes256_keysched(skey, DRBG_key);
		memcpy(tmp, DRBG_V, 16);
		aes256_encrypt(skey, tmp);
		clen = (len < 16) ? len : 16;
		memcpy(buf, tmp, clen);
		buf += clen;
		len -= clen;
	}
	aes256_DRBG_update(NULL, DRBG_key, DRBG_V);
}

#endif

static void
test_nist_KAT(unsigned logn, const char *srefhash)
{
#if DO_NIST_TESTS
	int i;
	uint8_t entropy_input[48];
	uint8_t hhv[20], hhref[20];
	uint8_t *msg, *sk, *pk, *sm, *tmp;
	size_t n, sk_len, pk_len, over_len;
	fpr *esk;
	sha1_context hhc;

	n = (size_t)1 << logn;
	printf("Test NIST KAT (%zu): ", n);
	fflush(stdout);

	hextobin(hhref, sizeof hhref, srefhash);
	sha1_init(&hhc);

	sk_len = (logn == 9) ? 1281 : 2305;
	pk_len = (logn == 9) ? 897 : 1793;
	over_len = (logn == 9) ? 690 : 1330;

	msg = xmalloc(3300);
	sk = xmalloc(sk_len);
	pk = xmalloc(pk_len);
	sm = xmalloc(3300 + over_len);

	tmp = xmalloc((size_t)84 << logn);
	esk = xmalloc((size_t)(8 * logn + 40) << logn);

	sha1_print_line_with_int(&hhc, "# Falcon-", (unsigned)n);
	sha1_print_line(&hhc, "");

	for (i = 0; i < 48; i ++) {
		entropy_input[i] = i;
	}
	nist_randombytes_init(entropy_input);

	for (i = 0; i < 100; i ++) {
		uint8_t seed[48], seed2[48], nonce[40];
		uint8_t drbg_sav[48];
		size_t mlen, smlen;
		int8_t *f, *g, *F, *G;
		uint16_t *h;
		uint16_t *hm;
		int16_t *sig, *sig2;
		inner_shake256_context sc;
		size_t u, v;

		f = (int8_t *)(tmp + ((size_t)72 << logn));
		g = f + n;
		F = g + n;
		G = F + n;
		h = (uint16_t *)(G + n);
		hm = h + n;
		sig = (int16_t *)(hm + n);
		sig2 = sig + n;

		/*
		 * Generate test seed and message.
		 */
		nist_randombytes(seed, 48);
		mlen = 33 * (i + 1);
		nist_randombytes(msg, mlen);

		/*
		 * Save DRBG state, and reinitialize it with the seed.
		 */
		memcpy(drbg_sav, DRBG_key, 32);
		memcpy(drbg_sav + 32, DRBG_V, 16);
		nist_randombytes_init(seed);

		/*
		 * Do keygen.
		 */
		nist_randombytes(seed2, 48);
		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, seed2, 48);
		inner_shake256_flip(&sc);
		Zf(keygen)(&sc, f, g, F, G, h, logn, tmp);

		/*
		 * Encode private key.
		 */
		sk[0] = 0x50 + logn;
		u = 1;
		v = Zf(trim_i8_encode)(sk + u, sk_len - u,
			f, logn, Zf(max_fg_bits)[logn]);
		if (v == 0) {
			fprintf(stderr, "ERR encoding sk(f)\n");
			exit(EXIT_FAILURE);
		}
		u += v;
		v = Zf(trim_i8_encode)(sk + u, sk_len - u,
			g, logn, Zf(max_fg_bits)[logn]);
		if (v == 0) {
			fprintf(stderr, "ERR encoding sk(g)\n");
			exit(EXIT_FAILURE);
		}
		u += v;
		v = Zf(trim_i8_encode)(sk + u, sk_len - u,
			F, logn, Zf(max_FG_bits)[logn]);
		if (v == 0) {
			fprintf(stderr, "ERR encoding sk(F)\n");
			exit(EXIT_FAILURE);
		}
		u += v;
		if (u != sk_len) {
			fprintf(stderr, "wrong private key length: %zu\n", u);
			exit(EXIT_FAILURE);
		}

		/*
		 * Encode public key.
		 */
		pk[0] = 0x00 + logn;
		v = Zf(modq_encode)(pk + 1, pk_len - 1, h, logn);
		u = 1 + v;
		if (u != pk_len) {
			fprintf(stderr, "wrong public key length: %zu\n", u);
			exit(EXIT_FAILURE);
		}

		/*
		 * Sign the message.
		 */
		nist_randombytes(nonce, 40);
		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, nonce, 40);
		inner_shake256_inject(&sc, msg, mlen);
		inner_shake256_flip(&sc);
		Zf(hash_to_point_vartime)(&sc, hm, logn);

		nist_randombytes(seed2, 48);
		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, seed2, 48);
		inner_shake256_flip(&sc);

		Zf(sign_dyn)(sig, &sc, f, g, F, G, hm, logn, tmp);

		/*
		 * Expand the private key and sign again the message,
		 * and check that the same signature is obtained.
		 */
		Zf(expand_privkey)(esk, f, g, F, G, logn, tmp);
		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, seed2, 48);
		inner_shake256_flip(&sc);
		Zf(sign_tree)(sig2, &sc, esk, hm, logn, tmp);
		check_eq(sig, sig2, n * sizeof *sig, "Sign dyn/tree mismatch");

		/*
		 * Verify the signature.
		 */
		Zf(to_ntt_monty)(h, logn);
		if (!Zf(verify_raw)(hm, sig, h, logn, tmp)) {
			fprintf(stderr, "Invalid signature\n");
			exit(EXIT_FAILURE);
		}

		/*
		 * Encode the signature and bundle it with the message.
		 */
		memcpy(sm + 2, nonce, 40);
		memcpy(sm + 42, msg, mlen);
		sm[42 + mlen] = 0x20 + logn;
		u = Zf(comp_encode)(sm + 43 + mlen, over_len - 43, sig, logn);
		if (u == 0) {
			fprintf(stderr, "Could not encode signature\n");
			exit(EXIT_FAILURE);
		}
		u ++;
		smlen = 42 + mlen + u;
		sm[0] = (uint8_t)(u >> 8);
		sm[1] = (uint8_t)u;

		/*
		 * Restore DRBG state.
		 */
		memcpy(DRBG_key, drbg_sav, 32);
		memcpy(DRBG_V, drbg_sav + 32, 16);

		sha1_print_line_with_int(&hhc, "count = ", (unsigned)i);
		sha1_print_line_with_hex(&hhc, "seed = ", seed, 48);
		sha1_print_line_with_int(&hhc, "mlen = ", (unsigned)mlen);
		sha1_print_line_with_hex(&hhc, "msg = ", msg, mlen);
		sha1_print_line_with_hex(&hhc, "pk = ", pk, pk_len);
		sha1_print_line_with_hex(&hhc, "sk = ", sk, sk_len);
		sha1_print_line_with_int(&hhc, "smlen = ", (unsigned)smlen);
		sha1_print_line_with_hex(&hhc, "sm = ", sm, smlen);
		sha1_print_line(&hhc, "");

		printf(".");
		fflush(stdout);
	}

	xfree(msg);
	xfree(sk);
	xfree(pk);
	xfree(sm);

	xfree(tmp);
	xfree(esk);

	sha1_out(&hhc, hhv);
	printf(" ");
	for (i = 0; i < 20; i ++) {
		printf("%02x", hhv[i]);
	}
	check_eq(hhv, hhref, 20, "NIST KAT (SHA-1 hash)");
	printf(" done.\n");
	fflush(stdout);

#else
	size_t n;

	(void)srefhash;
	n = (size_t)1 << logn;
	printf("Test NIST KAT (%zu): skipped because of incompatible build"
		" options\n", n);
	fflush(stdout);
#endif
}

/* ===================================================================== */

#if 0
/* unused */
static void
test_speed_falcon(unsigned logn, uint8_t *tmp)
{
	size_t n;
	int8_t *f, *g, *F, *G;
	uint16_t *h, *hm;
	fpr *expanded_key;
	int16_t *sig;
	uint8_t *tt, *tt2;
	inner_shake256_context rng;
	uint8_t seed[32];
	unsigned long num;

	n = (size_t)1 << logn;
	printf(" %4zu    ", n);
	fflush(stdout);

	if (!Zf(get_seed)(seed, sizeof seed)) {
		memset(seed, 0, sizeof seed);
		seed[0] = logn;
	}
	inner_shake256_init(&rng);
	inner_shake256_inject(&rng, seed, sizeof seed);
	inner_shake256_flip(&rng);

	f = (int8_t *)tmp;
	g = f + n;
	F = g + n;
	G = F + n;
	h = (uint16_t *)(G + n);
	hm = h + n;
	sig = (int16_t *)(hm + n);
	tt = (uint8_t *)(sig + n);
	if (logn == 1) {
		tt += 4;
	}

	num = 1;
	for (;;) {
		clock_t begin, end;
		unsigned long c;
		double d;

		begin = clock();
		for (c = 0; c < num; c ++) {
			Zf(keygen)(&rng, f, g, F, G, h, logn, tt);
		}
		end = clock();
		d = (double)(end - begin) / (double)CLOCKS_PER_SEC;
		if (d >= 2.0) {
			printf(" %7.2f     ", d * 1000.0 / (double)num);
			fflush(stdout);
			break;
		}
		num <<= 1;
	}

	num = 1;
	for (;;) {
		uint8_t msg[50];  /* nonce + message */
		inner_shake256_context sc;
		clock_t begin, end;
		unsigned long c;
		double d;

		inner_shake256_extract(&rng, msg, sizeof msg);

		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, msg, sizeof msg);
		inner_shake256_flip(&sc);
		Zf(hash_to_point_vartime)(&sc, hm, logn);

		begin = clock();
		for (c = 0; c < num; c ++) {
			Zf(sign_dyn)(sig, &rng, f, g, F, G, hm, logn, tt);
		}
		end = clock();
		d = (double)(end - begin) / (double)CLOCKS_PER_SEC;
		if (d >= 2.0) {
			printf(" %8.2f     ", (double)num / d);
			fflush(stdout);
			break;
		}
		num <<= 1;
	}

	expanded_key = (fpr *)tt;
	tt2 = (uint8_t *)expanded_key + (8 * logn + 40) * n;
	Zf(expand_privkey)(expanded_key, f, g, F, G, logn, tt2);

	num = 1;
	for (;;) {
		uint8_t msg[50];  /* nonce + message */
		inner_shake256_context sc;
		clock_t begin, end;
		unsigned long c;
		double d;

		inner_shake256_extract(&rng, msg, sizeof msg);

		inner_shake256_init(&sc);
		inner_shake256_inject(&sc, msg, sizeof msg);
		inner_shake256_flip(&sc);
		Zf(hash_to_point_vartime)(&sc, hm, logn);

		begin = clock();
		for (c = 0; c < num; c ++) {
			Zf(sign_tree)(sig, &rng, expanded_key, hm, logn, tt2);
		}
		end = clock();
		d = (double)(end - begin) / (double)CLOCKS_PER_SEC;
		if (d >= 2.0) {
			printf(" %8.2f     ", (double)num / d);
			fflush(stdout);
			break;
		}
		num <<= 1;
	}

	Zf(to_ntt_monty)(h, logn);

	num = 1;
	for (;;) {
		clock_t begin, end;
		unsigned long c;
		double d;

		begin = clock();
		for (c = 0; c < num; c ++) {
			Zf(verify_raw)(hm, sig, h, logn, tt);
		}
		end = clock();
		d = (double)(end - begin) / (double)CLOCKS_PER_SEC;
		if (d >= 2.0) {
			printf("%9.2f\n", (double)num / d);
			fflush(stdout);
			break;
		}
		num <<= 1;
	}
}

static void
test_speed(void)
{
	size_t tlen;
	uint8_t *tmp;

	tlen = 182272;
	tmp = xmalloc(tlen);
	printf("degree   keygen(ms)   sign/s(dyn)   sign/s(tree)   vrfy/s\n");
	fflush(stdout);
	test_speed_falcon(8, tmp);
	test_speed_falcon(9, tmp);
	test_speed_falcon(10, tmp);
	xfree(tmp);
}
#endif

int
main(void)
{
	unsigned old;

	old = set_fpu_cw(2);

	test_SHAKE256();
	test_codec();
	test_vrfy();
	test_RNG();
	test_FP_block();
	test_poly();
	test_gaussian0_sampler();
	test_sampler();
	test_sign();
	test_keygen();
	test_external_API();
	test_nist_KAT(9, "a57400cbaee7109358859a56c735a3cf048a9da2");
	test_nist_KAT(10, "affdeb3aa83bf9a2039fa9c17d65fd3e3b9828e2");
	/* test_speed(); */

	set_fpu_cw(old);
	return 0;
}
