#if defined(_KERNEL) || defined(_STANDALONE)
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: entpool.c,v 1.1 2020/04/30 03:28:19 riastradh Exp $");
#endif
#include "entpool.h"
#include ENTPOOL_HEADER
#if defined(_KERNEL) || defined(_STANDALONE)
#include <sys/types.h>
#include <lib/libkern/libkern.h>
#define ASSERT KASSERT
#else
#include <sys/cdefs.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#define ASSERT assert
#define CTASSERT __CTASSERT
#endif
#define secret
#define arraycount(A) (sizeof(A)/sizeof((A)[0]))
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define RATE ENTPOOL_RATE
static void
stir(struct entpool *P)
{
size_t i;
for (i = 0; i < arraycount(P->s.w); i++)
P->s.w[i] = ENTPOOL_WTOH(P->s.w[i]);
ENTPOOL_PERMUTE(P->s.w);
for (i = 0; i < arraycount(P->s.w); i++)
P->s.w[i] = ENTPOOL_HTOW(P->s.w[i]);
P->i = 0;
}
void
entpool_enter(struct entpool *P, const void *buf, size_t len)
{
const uint8_t *p = buf;
size_t n = len, n1 = n;
ASSERT(P->i <= RATE-1);
while (n1) {
if (P->i == RATE-1)
stir(P);
ASSERT(P->i < RATE-1);
P->s.u8[P->i++] ^= (n1 >= 0x80 ? 0x80 : 0) | (n1 & 0x7f);
n1 >>= 7;
}
while (n --> 0) {
if (P->i == RATE-1)
stir(P);
ASSERT(P->i < RATE-1);
P->s.u8[P->i++] ^= *p++;
}
if (P->i == RATE-1)
stir(P);
ASSERT(P->i < RATE-1);
}
bool
entpool_enter_nostir(struct entpool *P, const void *buf, size_t len)
{
const uint8_t *p = buf;
size_t n0, n;
ASSERT(P->i <= RATE-1);
if (P->i == RATE-1)
return false;
ASSERT(P->i < RATE-1);
n = n0 = MIN(127, MIN(len, RATE-1 - P->i - 1));
P->s.u8[P->i++] ^= n;
while (n --> 0)
P->s.u8[P->i++] ^= *p++;
ASSERT(P->i <= RATE-1);
return (n0 == len);
}
void
entpool_stir(struct entpool *P)
{
ASSERT(P->i <= RATE-1);
if (P->i == RATE-1)
stir(P);
ASSERT(P->i < RATE-1);
}
void
entpool_extract(struct entpool *P, secret void *buf, size_t len)
{
uint8_t *p = buf;
size_t n = len;
ASSERT(P->i <= RATE-1);
if (P->i != 0)
stir(P);
ASSERT(P->i == 0);
while (n >= RATE-1) {
memcpy(p, P->s.u8, RATE-1);
memset(P->s.u8, 0, RATE-1);
P->s.u8[RATE-1] ^= 0x80;
stir(P);
p += RATE-1;
n -= RATE-1;
}
if (n) {
ASSERT(n < RATE-1);
memcpy(p, P->s.u8, n);
memset(P->s.u8, 0, RATE-1);
P->s.u8[RATE-1] ^= 0x80;
stir(P);
}
}
#if ENTPOOL_SMALL
#define KATLEN 15
static const uint8_t known_answers[][KATLEN] = {
[0] = {
0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61,
0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11,
},
[1] = {
0x74,0x15,0x16,0x49,0x31,0x07,0x77,0xa1,
0x3b,0x4d,0x78,0xc6,0x5d,0xef,0x87,
},
[2] = {
0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25,
0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84,
},
[3] = {
0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25,
0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84,
},
[4] = {
0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61,
0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11,
},
[5] = {
0xa9,0x3c,0x3c,0xac,0x5f,0x6d,0x80,0xdc,
0x33,0x0c,0xb2,0xe3,0xdd,0x55,0x31,
},
[6] = {
0x2e,0x69,0x1a,0x2a,0x2d,0x09,0xd4,0x5e,
0x49,0xcc,0x8c,0xb2,0x0b,0xcc,0x42,
},
[7] = {
0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25,
0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84,
},
[8] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
},
[9] = {
0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61,
0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11,
},
[10] = {
0x2e,0x69,0x1a,0x2a,0x2d,0x09,0xd4,0x5e,
0x49,0xcc,0x8c,0xb2,0x0b,0xcc,0x42,
},
[11] = {
0x6f,0xfd,0xd2,0x29,0x78,0x46,0xc0,0x7d,
0xc7,0xf2,0x0a,0x2b,0x72,0xd6,0xc6,
},
[12] = {
0x86,0xf0,0xc1,0xf9,0x95,0x0f,0xc9,0x12,
0xde,0x38,0x39,0x10,0x1f,0x8c,0xc4,
},
};
#else
#define KATLEN 16
static const uint8_t known_answers[][KATLEN] = {
[0] = {
0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07,
0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce,
},
[1] = {
0x57,0x49,0x6e,0x28,0x7f,0xaa,0xee,0x6c,
0xa8,0xb0,0xf5,0x0b,0x87,0xae,0xd6,0xd6,
},
[2] = {
0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8,
0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50,
},
[3] = {
0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8,
0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50,
},
[4] = {
0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07,
0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce,
},
[5] = {
0x95,0x23,0x77,0xe4,0x84,0xeb,0xaa,0x2e,
0x6a,0x99,0xc2,0x52,0x06,0x6d,0xdf,0xea,
},
[6] = {
0x8c,0xdd,0x1b,0xaf,0x0e,0xf6,0xe9,0x1d,
0x51,0x33,0x68,0x38,0x8d,0xad,0x55,0x84,
},
[7] = {
0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8,
0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50,
},
[8] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
},
[9] = {
0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07,
0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce,
},
[10] = {
0x8c,0xdd,0x1b,0xaf,0x0e,0xf6,0xe9,0x1d,
0x51,0x33,0x68,0x38,0x8d,0xad,0x55,0x84,
},
[11] = {
0xf6,0xc1,0x14,0xbb,0x13,0x0a,0xaf,0xed,
0xca,0x0b,0x35,0x2c,0xf1,0x2b,0x1a,0x85,
},
[12] = {
0xf9,0x4b,0x05,0xd1,0x8b,0xcd,0xb3,0xd0,
0x77,0x27,0xfe,0x46,0xf9,0x33,0xb2,0xa2,
},
};
#endif
#define KAT_BEGIN(P, n) memset(P, 0, sizeof(*(P)))
#define KAT_ERROR() return -1
#define KAT_END(P, n) do \
{ \
uint8_t KAT_ACTUAL[KATLEN]; \
entpool_extract(P, KAT_ACTUAL, KATLEN); \
if (memcmp(KAT_ACTUAL, known_answers[n], KATLEN)) \
return -1; \
} while (0)
int
entpool_selftest(void)
{
struct entpool pool, *P = &pool;
uint8_t sample[1] = {0xff};
uint8_t scratch[RATE];
const uint8_t zero[RATE] = {0};
KAT_BEGIN(P, 0);
entpool_stir(P);
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 0);
KAT_BEGIN(P, 1);
entpool_stir(P);
#if ENTPOOL_SMALL
entpool_enter(P, zero, RATE-3);
#else
entpool_enter(P, zero, RATE-4);
#endif
entpool_stir(P);
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 1);
KAT_BEGIN(P, 2);
entpool_stir(P);
#if ENTPOOL_SMALL
if (!entpool_enter_nostir(P, zero, RATE-2))
KAT_ERROR();
#else
if (!entpool_enter_nostir(P, zero, 127))
KAT_ERROR();
if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1))
KAT_ERROR();
#endif
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 2);
KAT_BEGIN(P, 3);
entpool_stir(P);
#if ENTPOOL_SMALL
if (!entpool_enter_nostir(P, zero, RATE-2))
KAT_ERROR();
#else
CTASSERT(127 <= RATE-2);
if (!entpool_enter_nostir(P, zero, 127))
KAT_ERROR();
if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1))
KAT_ERROR();
#endif
entpool_stir(P);
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 3);
KAT_BEGIN(P, 4);
entpool_stir(P);
if (!entpool_enter_nostir(P, sample, 1))
KAT_ERROR();
entpool_stir(P);
KAT_END(P, 4);
KAT_BEGIN(P, 5);
entpool_stir(P);
#if ENTPOOL_SMALL
entpool_enter(P, zero, RATE-3);
#else
entpool_enter(P, zero, RATE-4);
#endif
entpool_stir(P);
if (entpool_enter_nostir(P, sample, 1))
KAT_ERROR();
entpool_stir(P);
KAT_END(P, 5);
KAT_BEGIN(P, 6);
entpool_stir(P);
#if ENTPOOL_SMALL
if (!entpool_enter_nostir(P, zero, RATE-2))
KAT_ERROR();
#else
CTASSERT(127 <= RATE-2);
if (!entpool_enter_nostir(P, zero, 127))
KAT_ERROR();
if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1))
KAT_ERROR();
#endif
if (entpool_enter_nostir(P, sample, 1))
KAT_ERROR();
entpool_stir(P);
KAT_END(P, 6);
KAT_BEGIN(P, 7);
entpool_stir(P);
#if ENTPOOL_SMALL
if (!entpool_enter_nostir(P, zero, RATE-2))
KAT_ERROR();
#else
CTASSERT(127 <= RATE-2);
if (!entpool_enter_nostir(P, zero, 127))
KAT_ERROR();
if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1))
KAT_ERROR();
#endif
entpool_stir(P);
if (!entpool_enter_nostir(P, sample, 1))
KAT_ERROR();
entpool_stir(P);
KAT_END(P, 7);
KAT_BEGIN(P, 8);
entpool_stir(P);
KAT_END(P, 8);
KAT_BEGIN(P, 9);
entpool_stir(P);
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 9);
KAT_BEGIN(P, 10);
entpool_stir(P);
#if ENTPOOL_SMALL
if (!entpool_enter_nostir(P, zero, RATE-2))
KAT_ERROR();
#else
CTASSERT(127 <= RATE-2);
if (!entpool_enter_nostir(P, zero, 127))
KAT_ERROR();
if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1))
KAT_ERROR();
#endif
KAT_END(P, 10);
KAT_BEGIN(P, 11);
entpool_stir(P);
entpool_extract(P, scratch, RATE-1 + 1);
entpool_stir(P);
KAT_END(P, 11);
KAT_BEGIN(P, 12);
entpool_stir(P);
entpool_extract(P, scratch, 1);
entpool_stir(P);
entpool_enter(P, sample, 1);
entpool_stir(P);
KAT_END(P, 12);
return 0;
}
#if ENTPOOL_TEST
int
main(void)
{
return entpool_selftest();
}
#endif
#if ENTPOOL_GENKAT
#include <stdio.h>
struct event {
enum { IN, OUT, STOP } t;
uint8_t b[RATE-1];
};
static const struct event *const cases[] = {
[0] = (const struct event[]) {
{IN, {1, 0xff}},
{STOP, {0}},
},
[1] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-3, [RATE-2] = 1}},
#else
{IN, {0x80|((RATE-4)&0x7f), (RATE-4)>>7, [RATE-2] = 1}},
#endif
{IN, {0xff}},
{STOP, {0}},
},
[2] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-2}},
#else
{IN, {127, [128] = RATE-2 - 127 - 1}},
#endif
{IN, {1, 0xff}},
{STOP, {0}},
},
[3] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-2}},
#else
{IN, {127, [128] = RATE-2 - 127 - 1}},
#endif
{IN, {1, 0xff}},
{STOP, {0}},
},
[4] = (const struct event[]) {
{IN, {1, 0xff}},
{STOP, {0}},
},
[5] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-3, [RATE-2] = 0 }},
#else
{IN, {0x80|((RATE-4)&0x7f), (RATE-4)>>7,
[RATE-2] = 0 }},
#endif
{STOP, {0}},
},
[6] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-2}},
#else
{IN, {127, [128] = RATE-2 - 127 - 1}},
#endif
{STOP, {0}},
},
[7] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-2}},
#else
{IN, {127, [128] = RATE-2 - 127 - 1}},
#endif
{IN, {1, 0xff}},
{STOP, {0}},
},
[8] = (const struct event[]) {
{STOP, {0}},
},
[9] = (const struct event[]) {
{IN, {1, 0xff}},
{STOP, {0}},
},
[10] = (const struct event[]) {
#if ENTPOOL_SMALL
{IN, {RATE-2}},
#else
{IN, {127, [128] = RATE-2 - 127 - 1}},
#endif
{STOP, {0}},
},
[11] = (const struct event[]) {
{OUT, {0}},
{OUT, {0}},
{STOP, {0}},
},
[12] = (const struct event[]) {
{OUT, {0}},
{IN, {1, 0xff}},
{STOP, {0}},
},
};
static void
compute(uint8_t output[KATLEN], const struct event *events)
{
union {
uint8_t b[ENTPOOL_SIZE];
ENTPOOL_WORD w[ENTPOOL_SIZE/sizeof(ENTPOOL_WORD)];
} u;
unsigned i, j, k;
memset(&u.b, 0, sizeof u.b);
for (i = 0;; i++) {
if (events[i].t == STOP)
break;
for (j = 0; j < sizeof(events[i].b); j++)
u.b[j] ^= events[i].b[j];
if (events[i].t == OUT) {
memset(u.b, 0, RATE-1);
u.b[RATE-1] ^= 0x80;
}
for (k = 0; k < arraycount(u.w); k++)
u.w[k] = ENTPOOL_WTOH(u.w[k]);
ENTPOOL_PERMUTE(u.w);
for (k = 0; k < arraycount(u.w); k++)
u.w[k] = ENTPOOL_HTOW(u.w[k]);
}
for (j = 0; j < KATLEN; j++)
output[j] = u.b[j];
}
int
main(void)
{
uint8_t output[KATLEN];
unsigned i, j;
printf("static const uint8_t known_answers[][KATLEN] = {\n");
for (i = 0; i < arraycount(cases); i++) {
printf("\t[%u] = {\n", i);
compute(output, cases[i]);
for (j = 0; j < KATLEN; j++) {
if (j % 8 == 0)
printf("\t\t");
printf("0x%02hhx,", output[j]);
if (j % 8 == 7)
printf("\n");
}
if ((KATLEN % 8) != 0)
printf("\n");
printf("\t},\n");
}
printf("};\n");
fflush(stdout);
return ferror(stdout);
}
#endif