strongswan/src/libstrongswan/plugins/bliss/bliss_sampler.c

252 lines
4.3 KiB
C

/*
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "bliss_sampler.h"
typedef struct private_bliss_sampler_t private_bliss_sampler_t;
#include <crypto/xofs/xof_bitspender.h>
/**
* Private data of a bliss_sampler_t object.
*/
struct private_bliss_sampler_t {
/**
* Public interface.
*/
bliss_sampler_t public;
/**
* BLISS parameter the rejection sampling is to be based on
*/
const bliss_param_set_t *set;
/**
* Bitspender used for random rejection sampling
*/
xof_bitspender_t *bitspender;
};
METHOD(bliss_sampler_t, bernoulli_exp, bool,
private_bliss_sampler_t *this, uint32_t x, bool *accepted)
{
uint32_t x_mask;
uint8_t u;
const uint8_t *c;
int i;
x_mask = 1 << (this->set->c_rows - 1);
c = this->set->c;
c += (this->set->c_rows - 1) * this->set->c_cols;
while (x_mask > 0)
{
if (x & x_mask)
{
for (i = 0; i < this->set->c_cols; i++)
{
if (!this->bitspender->get_byte(this->bitspender, &u))
{
return FALSE;
}
if (u < c[i])
{
break;
}
else if (u > c[i])
{
*accepted = FALSE;
return TRUE;
}
}
}
x_mask >>= 1;
c -= this->set->c_cols;
}
*accepted = TRUE;
return TRUE;
}
METHOD(bliss_sampler_t, bernoulli_cosh, bool,
private_bliss_sampler_t *this, int32_t x, bool *accepted)
{
uint32_t u;
x = 2 * (x < 0 ? -x : x);
while (TRUE)
{
if (!bernoulli_exp(this, x, accepted))
{
return FALSE;
}
if (*accepted)
{
return TRUE;
}
if (!this->bitspender->get_bits(this->bitspender, 1, &u))
{
return FALSE;
}
if (u)
{
continue;
}
if (!bernoulli_exp(this, x, accepted))
{
return FALSE;
}
if (!(*accepted))
{
return TRUE;
}
}
}
#define MAX_SAMPLE_INDEX 16
METHOD(bliss_sampler_t, pos_binary, bool,
private_bliss_sampler_t *this, uint32_t *x)
{
uint32_t u, i;
while (TRUE)
{
for (i = 0; i <= MAX_SAMPLE_INDEX; i++)
{
if (!this->bitspender->get_bits(this->bitspender,
i ? (2*i - 1) : 1, &u))
{
return FALSE;
}
if (u == 0)
{
*x = i;
return TRUE;
}
if ((u >> 1) != 0)
{
break;
}
}
if (i > MAX_SAMPLE_INDEX)
{
return FALSE;
}
}
}
METHOD(bliss_sampler_t, gaussian, bool,
private_bliss_sampler_t *this, int32_t *z)
{
uint32_t u, x, y, z_pos;
bool accepted;
while (TRUE)
{
if (!pos_binary(this, &x))
{
return FALSE;
}
do
{
if (!this->bitspender->get_bits(this->bitspender,
this->set->k_sigma_bits, &y))
{
return FALSE;
}
}
while (y >= this->set->k_sigma);
if (!bernoulli_exp(this, y * (y + 2*this->set->k_sigma * x), &accepted))
{
return FALSE;
}
if (accepted)
{
if (!this->bitspender->get_bits(this->bitspender, 1, &u))
{
return FALSE;
}
if (x || y || u)
{
break;
}
}
}
z_pos = this->set->k_sigma * x + y;
*z = u ? z_pos : -z_pos;
return TRUE;
}
METHOD(bliss_sampler_t, sign, bool,
private_bliss_sampler_t *this, bool *positive)
{
uint32_t u;
if (!this->bitspender->get_bits(this->bitspender, 1, &u))
{
return FALSE;
}
*positive = u;
return TRUE;
}
METHOD(bliss_sampler_t, destroy, void,
private_bliss_sampler_t *this)
{
this->bitspender->destroy(this->bitspender);
free(this);
}
/**
* See header.
*/
bliss_sampler_t *bliss_sampler_create(ext_out_function_t alg, chunk_t seed,
const bliss_param_set_t *set)
{
private_bliss_sampler_t *this;
xof_bitspender_t *bitspender;
bitspender = xof_bitspender_create(alg, seed, FALSE);
if (!bitspender)
{
return NULL;
}
INIT(this,
.public = {
.bernoulli_exp = _bernoulli_exp,
.bernoulli_cosh = _bernoulli_cosh,
.pos_binary = _pos_binary,
.gaussian = _gaussian,
.sign = _sign,
.destroy = _destroy,
},
.set = set,
.bitspender = bitspender,
);
return &this->public;
}