218 lines
4.6 KiB
C
218 lines
4.6 KiB
C
/*
|
|
* Copyright (C) 2016 Andreas Steffen
|
|
* HSR Hochschule fuer Technik Rapperswil
|
|
*
|
|
* Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann,
|
|
* and Peter Schwabe.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
*/
|
|
|
|
#include "newhope_reconciliation.h"
|
|
|
|
typedef struct private_newhope_reconciliation_t private_newhope_reconciliation_t;
|
|
|
|
/**
|
|
* Private data of an newhope_reconciliation_t object.
|
|
*/
|
|
struct private_newhope_reconciliation_t {
|
|
|
|
/**
|
|
* Public newhope_reconciliation_t interface.
|
|
*/
|
|
newhope_reconciliation_t public;
|
|
|
|
/**
|
|
* Array sizes
|
|
*/
|
|
int n, n4;
|
|
|
|
/**
|
|
* Multiples of modulus q
|
|
*/
|
|
int32_t q, q2, q4, q8, q16;
|
|
};
|
|
|
|
|
|
static inline int32_t rec_abs(int32_t v)
|
|
{
|
|
int32_t mask = v >> 31;
|
|
|
|
return (v ^ mask) - mask;
|
|
}
|
|
|
|
/**
|
|
* Auxiliary function used by help_reconcile() method
|
|
*/
|
|
static int32_t rec_f(private_newhope_reconciliation_t *this,
|
|
int32_t v, uint8_t r, int32_t *v0, int32_t *v1)
|
|
{
|
|
int32_t x, xit, t, b;
|
|
|
|
x = 8 * v + 2 * r;
|
|
|
|
/* compute t = x/q */
|
|
b = x * 2730;
|
|
t = b >> 25;
|
|
b = x - t * this->q;
|
|
b = this->q - 1 - b;
|
|
b >>= 31;
|
|
t -= b;
|
|
|
|
r = t & 0x01;
|
|
xit = (t >> 1);
|
|
*v0 = xit + r ; /* v0 = round(x/(2q)) */
|
|
|
|
t -= 1;
|
|
r = t & 0x01;
|
|
*v1 = ( t>> 1) + r;
|
|
|
|
return rec_abs(x - (*v0) * this->q2);
|
|
}
|
|
|
|
/**
|
|
* Auxiliary function used by reconcile() method
|
|
*/
|
|
static int32_t rec_g(private_newhope_reconciliation_t *this, int32_t x)
|
|
{
|
|
int32_t t, r, b;
|
|
|
|
/* t = x/(4*q) */
|
|
b = x * 2730;
|
|
t = b >> 27;
|
|
b = x - t * this->q4;
|
|
b = this->q4 - 1 - b;
|
|
b >>= 31;
|
|
t -= b;
|
|
|
|
r = t & 0x01;
|
|
t = (t >> 1) + r; /* t = round(x/(8q)) */
|
|
t *= this->q8;
|
|
|
|
return abs(t - x);
|
|
}
|
|
|
|
METHOD(newhope_reconciliation_t, help_reconcile, uint8_t*,
|
|
private_newhope_reconciliation_t *this, uint32_t *v, uint8_t *rbits)
|
|
{
|
|
int32_t v0[4], v1[4], v_tmp[4], k;
|
|
int i, i0, i1, i2, i3, j;
|
|
uint8_t *r, rbit;
|
|
|
|
/* allocate output vector */
|
|
r = (uint8_t*)malloc(this->n);
|
|
|
|
for (i = 0; i < this->n4/8; i++)
|
|
{
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
i0 = 8*i + j;
|
|
i1 = i0 + this->n4;
|
|
i2 = i1 + this->n4;
|
|
i3 = i2 + this->n4;
|
|
|
|
/* iterate through all 256 random bits */
|
|
rbit = (rbits[i] >> j) & 0x01;
|
|
|
|
k = rec_f(this, v[i0], rbit, &v0[0], &v1[0]);
|
|
k += rec_f(this, v[i1], rbit, &v0[1], &v1[1]);
|
|
k += rec_f(this, v[i2], rbit, &v0[2], &v1[2]);
|
|
k += rec_f(this, v[i3], rbit, &v0[3], &v1[3]);
|
|
|
|
k = (this->q2 - 1 - k) >> 31;
|
|
|
|
v_tmp[0] = ((~k) & v0[0]) ^ (k & v1[0]);
|
|
v_tmp[1] = ((~k) & v0[1]) ^ (k & v1[1]);
|
|
v_tmp[2] = ((~k) & v0[2]) ^ (k & v1[2]);
|
|
v_tmp[3] = ((~k) & v0[3]) ^ (k & v1[3]);
|
|
|
|
r[i0] = (v_tmp[0] - v_tmp[3]) & 0x03;
|
|
r[i1] = (v_tmp[1] - v_tmp[3]) & 0x03;
|
|
r[i2] = (v_tmp[2] - v_tmp[3]) & 0x03;
|
|
r[i3] = (v_tmp[3] - k + v_tmp[3]) & 0x03;
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
METHOD(newhope_reconciliation_t, reconcile, chunk_t,
|
|
private_newhope_reconciliation_t *this, uint32_t *v, uint8_t *r)
|
|
{
|
|
size_t key_len;
|
|
uint8_t *key;
|
|
int32_t tmp[4], t;
|
|
int i, i0, i1, i2, i3, j;
|
|
|
|
key_len = this->n4 / 8;
|
|
key = (uint8_t*)malloc(key_len);
|
|
memset(key, 0x00, key_len);
|
|
|
|
for (i = 0; i < key_len; i++)
|
|
{
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
i0 = 8*i + j;
|
|
i1 = i0 + this->n4;
|
|
i2 = i1 + this->n4;
|
|
i3 = i2 + this->n4;
|
|
|
|
tmp[0] = this->q16 + 8 * (int32_t)v[i0] -
|
|
this->q * (2*r[i0] + r[i3]);
|
|
tmp[1] = this->q16 + 8 * (int32_t)v[i1] -
|
|
this->q * (2*r[i1] + r[i3]);
|
|
tmp[2] = this->q16 + 8 * (int32_t)v[i2] -
|
|
this->q * (2*r[i2] + r[i3]);
|
|
tmp[3] = this->q16 + 8 * (int32_t)v[i3] -
|
|
this->q * ( r[i3]);
|
|
|
|
t = rec_g(this, tmp[0]) + rec_g(this, tmp[1]) +
|
|
rec_g(this, tmp[2]) + rec_g(this, tmp[3]) - this->q8;
|
|
|
|
key[i] |= ((t >> 31) & 0x01) << j;
|
|
}
|
|
}
|
|
|
|
return chunk_create(key, key_len);
|
|
}
|
|
|
|
METHOD(newhope_reconciliation_t, destroy, void,
|
|
private_newhope_reconciliation_t *this)
|
|
{
|
|
free(this);
|
|
}
|
|
|
|
/*
|
|
* Described in header.
|
|
*/
|
|
newhope_reconciliation_t *newhope_reconciliation_create(int n, int32_t q)
|
|
{
|
|
private_newhope_reconciliation_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.help_reconcile = _help_reconcile,
|
|
.reconcile = _reconcile,
|
|
.destroy = _destroy,
|
|
},
|
|
.n = n,
|
|
.n4 = n / 4,
|
|
.q = q,
|
|
.q2 = 2 * q,
|
|
.q4 = 4 * q,
|
|
.q8 = 8 * q,
|
|
.q16 = 16 * q,
|
|
);
|
|
|
|
return &this->public;
|
|
}
|