Repository URL to install this package:
|
Version:
3.15.0 ▾
|
#include "modexp_utils.h"
#include "siphash.h"
#include "endianess.h"
#include "siphash.c"
void expand_seed(uint64_t seed_in, void* seed_out, size_t out_len)
{
uint8_t counter[4];
uint8_t seed_in_b[16];
uint32_t i;
for (i=0; i<8; i++) {
seed_in_b[2*i] = seed_in_b[2*i+1] = (uint8_t)(seed_in >> (i*8));
}
#define SIPHASH_LEN 16
for (i=0 ;; i++, out_len-=SIPHASH_LEN) {
STORE_U32_LITTLE(counter, i);
if (out_len<SIPHASH_LEN)
break;
siphash(counter, 4, seed_in_b, seed_out, SIPHASH_LEN);
seed_out = (uint8_t*)seed_out + SIPHASH_LEN;
}
if (out_len>0) {
uint8_t buffer[SIPHASH_LEN];
siphash(counter, 4, seed_in_b, buffer, SIPHASH_LEN);
memcpy(seed_out, buffer, out_len);
}
#undef SIPHASH_LEN
}
struct BitWindow_LR init_bit_window_lr(unsigned window_size, const uint8_t *exp, size_t exp_len)
{
struct BitWindow_LR bw;
bw.window_size = window_size;
bw.nr_windows = (unsigned)((exp_len*8+window_size-1)/window_size);
bw.tg = (unsigned)((exp_len*8) % window_size);
if (bw.tg == 0) {
bw.tg = window_size;
}
bw.available = 8;
bw.scan_exp = 0;
bw.exp = exp;
return bw;
}
struct BitWindow_RL init_bit_window_rl(unsigned window_size, const uint8_t *exp, size_t exp_len)
{
struct BitWindow_RL bw;
bw.window_size = window_size;
bw.nr_windows = (unsigned)((exp_len*8+window_size-1)/window_size);
bw.bytes_left = (unsigned)exp_len;
bw.bits_left = 8;
bw.cursor = exp + (exp_len-1);
return bw;
}
unsigned get_next_digit_lr(struct BitWindow_LR *bw)
{
unsigned tc, index;
/** Possibly move to the next byte **/
if (bw->available == 0) {
bw->available = 8;
bw->scan_exp++;
}
/** Try to consume as much as possible from the current byte **/
tc = MIN(bw->tg, bw->available);
index = ((unsigned)bw->exp[bw->scan_exp] >> ((unsigned)bw->available - tc)) & ((1U << tc) - 1);
bw->available -= tc;
bw->tg -= tc;
/** A few bits (<8) might still be needed from the next byte **/
if (bw->tg > 0) {
bw->scan_exp++;
index = (index << bw->tg) | ((unsigned)bw->exp[bw->scan_exp] >> (8 - bw->tg));
bw->available = 8 - bw->tg;
}
bw->tg = bw->window_size;
return index;
}
unsigned get_next_digit_rl(struct BitWindow_RL *bw)
{
unsigned res, tg, bits_used;
if (bw->bytes_left == 0)
return 0;
assert(bw->bits_left > 0);
res = (unsigned)(*(bw->cursor) >> (8 - bw->bits_left)) & (unsigned)((1U<<bw->window_size) - 1);
bits_used = MIN(bw->bits_left, bw->window_size);
tg = bw->window_size - bits_used;
bw->bits_left -= bits_used;
if (bw->bits_left == 0) {
bw->bits_left = 8;
if (--bw->bytes_left == 0)
return res;
bw->cursor--;
}
if (tg>0) {
res |= (*(bw->cursor) & ((1U<<tg) - 1)) << bits_used;
bw->bits_left -= tg;
}
return res;
}
#define CACHE_LINE_SIZE 64U
/**
* Spread a number of equally-sized arrays in memory, to minimize cache
* side-channel when one of them has to be accessed through a secret index.
*
* Each array is broken up in pieces, and pieces from all array collected
* and fit into one or more 64 byte cache lines. One cache line contains
* one piece taken from each array at the same offset.
*
* We assume that access to a byte in the cache line can be performed without
* leaking its position.
*
* nr_array is a power of two, 64 at most
*/
int scatter(ProtMemory** pprot, const void *arrays[], uint8_t nr_arrays, size_t array_len, uint64_t seed)
{
ProtMemory *prot;
unsigned piece_len;
unsigned cache_lines;
unsigned remaining;
unsigned i, j;
unsigned mask;
if (nr_arrays>CACHE_LINE_SIZE || (nr_arrays & 1) == 1 || array_len == 0)
return ERR_VALUE;
for (i=nr_arrays; (i & 1)==0; i>>=1);
if (i != 1)
return ERR_VALUE;
piece_len = CACHE_LINE_SIZE / nr_arrays;
cache_lines = ((unsigned)array_len + piece_len - 1) / piece_len;
*pprot = prot = (ProtMemory*)calloc(1, sizeof(ProtMemory));
if (NULL == prot)
return ERR_MEMORY;
prot->scramble = (uint16_t*)calloc(cache_lines, sizeof(prot->scramble[0]));
if (NULL == prot->scramble) {
free(prot);
return ERR_MEMORY;
}
expand_seed(seed, prot->scramble, cache_lines*sizeof(prot->scramble[0]));
prot->scattered = (uint8_t*)align_alloc(cache_lines*CACHE_LINE_SIZE, CACHE_LINE_SIZE);
if (NULL == prot->scattered) {
free(prot->scramble);
free(prot);
return ERR_MEMORY;
}
prot->nr_arrays = nr_arrays;
prot->array_len = (unsigned)array_len;
remaining = (unsigned)array_len;
mask = (unsigned)(nr_arrays - 1);
for (i=0; i<cache_lines; i++) {
uint8_t *cache_line;
unsigned offset;
cache_line = (uint8_t*)prot->scattered + i*CACHE_LINE_SIZE;
offset = i*piece_len;
for (j=0; j<nr_arrays; j++) {
unsigned s;
unsigned obf;
uint8_t *dst, *src;
obf = (j*((prot->scramble[i] >> 8) | 1) + (prot->scramble[i] & 0xFF)) & mask;
s = MIN(piece_len, remaining);
dst = cache_line + piece_len*obf;
src = (uint8_t*)arrays[j] + offset;
memcpy(dst, src, s);
}
remaining -= piece_len;
}
return 0;
}
void gather(void *out, const ProtMemory *prot, unsigned index)
{
unsigned piece_len;
unsigned cache_lines;
unsigned remaining;
unsigned offset;
unsigned i;
unsigned mask;
piece_len = CACHE_LINE_SIZE / prot->nr_arrays;
cache_lines = (prot->array_len + piece_len - 1) / piece_len;
remaining = prot->array_len;
mask = prot->nr_arrays - 1;
offset = 0;
for (i=0; i<cache_lines; i++) {
uint8_t *cache_line;
unsigned obf;
obf = (index*((prot->scramble[i] >> 8) | 1) + (prot->scramble[i] & 0xFF)) & mask;
cache_line = (uint8_t*)prot->scattered + i*CACHE_LINE_SIZE;
memcpy((uint8_t*)out + offset, cache_line + piece_len*obf, MIN(piece_len, remaining));
remaining -= piece_len;
offset += piece_len;
}
}
void free_scattered(ProtMemory *prot)
{
if (prot) {
free(prot->scramble);
align_free(prot->scattered);
}
free(prot);
}