434 lines
14 KiB
C
434 lines
14 KiB
C
/* * Copyright (c) 2013, Kevin Greenan (kmgreen2@gmail.com)
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY
|
|
* THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <dlfcn.h>
|
|
#include <alg_sig.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#define GALOIS_SINGLE_MULTIPLY "galois_single_multiply"
|
|
#define GALOIS_UNINIT "galois_uninit_field"
|
|
|
|
int valid_gf_w[] = { 8, 16, -1 };
|
|
int valid_pairs[][2] = { { 8, 32}, {16, 32}, {16, 64}, {-1, -1} };
|
|
|
|
galois_single_multiply_func get_galois_multi_func(void *handle) {
|
|
/*
|
|
* ISO C forbids casting a void* to a function pointer.
|
|
* Since dlsym return returns a void*, we use this union to
|
|
* "transform" the void* to a function pointer.
|
|
*/
|
|
union {
|
|
galois_single_multiply_func fptr;
|
|
void *vptr;
|
|
} func_handle = {.vptr = NULL};
|
|
func_handle.vptr = dlsym(handle, GALOIS_SINGLE_MULTIPLY);
|
|
return func_handle.fptr;
|
|
}
|
|
|
|
void stub_galois_uninit_field(int w){}
|
|
|
|
galois_uninit_field_func get_galois_uninit_func(void *handle) {
|
|
/*
|
|
* ISO C forbids casting a void* to a function pointer.
|
|
* Since dlsym return returns a void*, we use this union to
|
|
* "transform" the void* to a function pointer.
|
|
*/
|
|
union {
|
|
galois_uninit_field_func fptr;
|
|
void *vptr;
|
|
} func_handle = {.vptr = NULL};
|
|
func_handle.vptr = dlsym(handle, GALOIS_UNINIT);
|
|
return func_handle.fptr;
|
|
}
|
|
|
|
|
|
void *get_jerasure_sohandle()
|
|
{
|
|
return dlopen(JERASURE_SONAME, RTLD_LAZY | RTLD_LOCAL);
|
|
}
|
|
|
|
int load_gf_functions(void *sohandle, struct jerasure_mult_routines *routines)
|
|
{
|
|
routines->galois_single_multiply = get_galois_multi_func(sohandle);
|
|
routines->galois_uninit_field = get_galois_uninit_func(sohandle);
|
|
if (NULL == routines->galois_single_multiply) {
|
|
return -1;
|
|
}
|
|
/**
|
|
* It is possible that the underlying Jerasure implementation
|
|
* is old (pre-jerasure.org). If so, there is not an uninit
|
|
* function, so these tests will fail.
|
|
*
|
|
* Since nothing is using alg_sig at the moment, we stub the
|
|
* uninit function to unblock the tests. Once we plug the internal
|
|
* GF functions into alg_sig, this can jsut go away.
|
|
*/
|
|
if (NULL == routines->galois_uninit_field) {
|
|
routines->galois_uninit_field = &stub_galois_uninit_field;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
alg_sig_t *init_alg_sig_w8(void *jerasure_sohandle, int sig_len)
|
|
{
|
|
alg_sig_t *alg_sig_handle;
|
|
int num_gf_lr_table_syms;
|
|
int i;
|
|
int w = 8;
|
|
int alpha = 2, beta = 4, gamma = 8;
|
|
int num_components = sig_len / w;
|
|
|
|
alg_sig_handle = (alg_sig_t *)malloc(sizeof(alg_sig_t));
|
|
if (NULL == alg_sig_handle) {
|
|
return NULL;
|
|
}
|
|
|
|
alg_sig_handle->jerasure_sohandle = jerasure_sohandle;
|
|
|
|
if (load_gf_functions(alg_sig_handle->jerasure_sohandle, &(alg_sig_handle->mult_routines)) < 0) {
|
|
free(alg_sig_handle);
|
|
return NULL;
|
|
}
|
|
|
|
alg_sig_handle->sig_len = sig_len;
|
|
alg_sig_handle->gf_w = w;
|
|
|
|
num_gf_lr_table_syms = 1 << (w >> 1);
|
|
|
|
if (num_components >= 4) {
|
|
alg_sig_handle->tbl1_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl1_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl2_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl2_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl3_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl3_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
}
|
|
|
|
/*
|
|
* Note that \alpha = 2
|
|
* Note that \beta = 4 (\alpha ^ 2)
|
|
* Note that \gamme = 8 (\alpha ^ 3)
|
|
*/
|
|
for (i = 0; i < 16; i++) {
|
|
if (num_components >= 4) {
|
|
alg_sig_handle->tbl1_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char)(i << 4) & 0xf0, alpha, w);
|
|
alg_sig_handle->tbl1_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char) i, alpha, w);
|
|
|
|
alg_sig_handle->tbl2_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char) (i << 4) & 0xf0, beta, w);
|
|
alg_sig_handle->tbl2_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char) i, beta, w);
|
|
|
|
alg_sig_handle->tbl3_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char) (i << 4) & 0xf0, gamma, w);
|
|
alg_sig_handle->tbl3_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned char) i, gamma, w);
|
|
}
|
|
}
|
|
|
|
return alg_sig_handle;
|
|
}
|
|
|
|
static
|
|
alg_sig_t *init_alg_sig_w16(void *jerasure_sohandle, int sig_len)
|
|
{
|
|
alg_sig_t *alg_sig_handle;
|
|
int num_gf_lr_table_syms;
|
|
int i;
|
|
int w = 16;
|
|
int alpha = 2, beta = 4, gamma = 8;
|
|
int num_components = sig_len / w;
|
|
|
|
if (NULL == jerasure_sohandle) {
|
|
return NULL;
|
|
}
|
|
|
|
alg_sig_handle = (alg_sig_t *)malloc(sizeof(alg_sig_t));
|
|
if (NULL == alg_sig_handle) {
|
|
return NULL;
|
|
}
|
|
|
|
alg_sig_handle->jerasure_sohandle = jerasure_sohandle;
|
|
|
|
if (load_gf_functions(alg_sig_handle->jerasure_sohandle, &(alg_sig_handle->mult_routines)) < 0) {
|
|
free(alg_sig_handle);
|
|
return NULL;
|
|
}
|
|
|
|
alg_sig_handle->sig_len = sig_len;
|
|
alg_sig_handle->gf_w = w;
|
|
|
|
num_gf_lr_table_syms = 1 << (w >> 1);
|
|
|
|
if (num_components >= 2) {
|
|
alg_sig_handle->tbl1_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl1_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
}
|
|
|
|
if (num_components >= 4) {
|
|
alg_sig_handle->tbl2_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl2_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl3_l = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
alg_sig_handle->tbl3_r = (int*)malloc(sizeof(int) * num_gf_lr_table_syms);
|
|
}
|
|
|
|
/*
|
|
* Note that \alpha = 2
|
|
* Note that \beta = 4 (\alpha ^ 2 MOD 2^16)
|
|
* Note that \gamme = 8 (\alpha ^ 3 MOD 2^16)
|
|
*/
|
|
for (i = 0; i < 256; i++) {
|
|
alg_sig_handle->tbl1_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) (i << 8), alpha, w);
|
|
alg_sig_handle->tbl1_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) i, alpha, w);
|
|
|
|
if (num_components >= 4) {
|
|
alg_sig_handle->tbl2_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) (i << 8), beta, w);
|
|
alg_sig_handle->tbl2_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) i, beta, w);
|
|
|
|
alg_sig_handle->tbl3_l[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) (i << 8), gamma, w);
|
|
alg_sig_handle->tbl3_r[i] = alg_sig_handle->mult_routines.galois_single_multiply((unsigned short) i, gamma, w);
|
|
}
|
|
}
|
|
|
|
return alg_sig_handle;
|
|
}
|
|
|
|
alg_sig_t *init_alg_sig(int sig_len, int gf_w)
|
|
{
|
|
int i=0;
|
|
void *jerasure_sohandle = get_jerasure_sohandle();
|
|
|
|
if (NULL == jerasure_sohandle) {
|
|
fprintf (stderr, "Could not open Jerasure backend. Install Jerasure or fix LD_LIBRARY_PATH. Passing.\n");
|
|
return NULL;
|
|
}
|
|
|
|
while (valid_pairs[i][0] > -1) {
|
|
if (gf_w == valid_pairs[i][0] &&
|
|
sig_len == valid_pairs[i][1]) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (valid_pairs[i][0] == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
if (gf_w == 8) {
|
|
return init_alg_sig_w8(jerasure_sohandle, sig_len);
|
|
} else if (gf_w == 16) {
|
|
return init_alg_sig_w16(jerasure_sohandle, sig_len);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void destroy_alg_sig(alg_sig_t* alg_sig_handle)
|
|
{
|
|
if (alg_sig_handle == NULL) {
|
|
return;
|
|
}
|
|
if (alg_sig_handle->gf_w == 0) {
|
|
free(alg_sig_handle);
|
|
return;
|
|
}
|
|
|
|
alg_sig_handle->mult_routines.galois_uninit_field(alg_sig_handle->gf_w);
|
|
dlclose(alg_sig_handle->jerasure_sohandle);
|
|
|
|
int num_components = alg_sig_handle->sig_len / alg_sig_handle->gf_w;
|
|
|
|
free(alg_sig_handle->tbl1_l);
|
|
free(alg_sig_handle->tbl1_r);
|
|
if (num_components >= 4) {
|
|
free(alg_sig_handle->tbl2_l);
|
|
free(alg_sig_handle->tbl2_r);
|
|
free(alg_sig_handle->tbl3_l);
|
|
free(alg_sig_handle->tbl3_r);
|
|
}
|
|
|
|
free(alg_sig_handle);
|
|
}
|
|
|
|
|
|
static
|
|
int compute_w8_alg_sig_32(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
int i;
|
|
|
|
if (len == 0) {
|
|
bzero(sig, 4);
|
|
return 0;
|
|
}
|
|
|
|
sig[0] = buf[len-1];
|
|
sig[1] = buf[len-1];
|
|
sig[2] = buf[len-1];
|
|
sig[3] = buf[len-1];
|
|
|
|
/**
|
|
* This is the loop to optimize. It is currently optimized enough : using Horner's alg.,
|
|
* shortened mult. tables, and other tricks.
|
|
*/
|
|
for (i = len - 2; i >= 0; i--) {
|
|
sig[0] ^= buf[i];
|
|
sig[1] = (buf[i] ^ (alg_sig_handle->tbl1_l[(sig[1] >> 4) & 0x0f] ^ alg_sig_handle->tbl1_r[sig[1] & 0x0f]));
|
|
sig[2] = (buf[i] ^ (alg_sig_handle->tbl2_l[(sig[2] >> 4) & 0x0f] ^ alg_sig_handle->tbl2_r[sig[2] & 0x0f]));
|
|
sig[3] = (buf[i] ^ (alg_sig_handle->tbl3_l[(sig[3] >> 4) & 0x0f] ^ alg_sig_handle->tbl3_r[sig[3] & 0x0f]));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int compute_w16_alg_sig_64(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
int bit_mask;
|
|
int adj_len = len / 2;
|
|
int i;
|
|
unsigned short *_buf = (unsigned short *)buf;
|
|
unsigned short sig_buf[4];
|
|
|
|
if (len == 0) {
|
|
bzero(sig, 8);
|
|
return 0;
|
|
}
|
|
|
|
switch (len % 2) {
|
|
case 1:
|
|
bit_mask = 0x00ff;
|
|
break;
|
|
default:
|
|
bit_mask = 0xffff;
|
|
break;
|
|
}
|
|
|
|
if (len % 2 > 0) {
|
|
adj_len++;
|
|
}
|
|
|
|
// Account for buffer not being uint16_t aligned
|
|
sig_buf[0] = (_buf[adj_len - 1] & bit_mask);
|
|
sig_buf[1] = (_buf[adj_len - 1] & bit_mask);
|
|
sig_buf[2] = (_buf[adj_len - 1] & bit_mask);
|
|
sig_buf[3] = (_buf[adj_len - 1] & bit_mask);
|
|
|
|
/**
|
|
* This is the loop to optimize. It is currently optimized enough : using Horner's alg.,
|
|
* shortened mult. tables, and other tricks.
|
|
*/
|
|
for (i = adj_len - 2; i >= 0; i--) {
|
|
sig_buf[0] ^= _buf[i];
|
|
sig_buf[1] = (_buf[i] ^ (alg_sig_handle->tbl1_l[(sig_buf[1] >> 8) & 0x00ff] ^ alg_sig_handle->tbl1_r[sig_buf[1] & 0x00ff]));
|
|
sig_buf[2] = (_buf[i] ^ (alg_sig_handle->tbl2_l[(sig_buf[2] >> 8) & 0x00ff] ^ alg_sig_handle->tbl2_r[sig_buf[2] & 0x00ff]));
|
|
sig_buf[3] = (_buf[i] ^ (alg_sig_handle->tbl3_l[(sig_buf[3] >> 8) & 0x00ff] ^ alg_sig_handle->tbl3_r[sig_buf[3] & 0x00ff]));
|
|
}
|
|
|
|
sig[0] = (char) (sig_buf[0] & 0x000ff);
|
|
sig[1] = (char) ((sig_buf[0] >> 8) & 0x000ff);
|
|
sig[2] = (char) (sig_buf[1] & 0x00ff);
|
|
sig[3] = (char) ((sig_buf[1] >> 8) & 0x00ff);
|
|
sig[4] = (char) (sig_buf[2] & 0x00ff);
|
|
sig[5] = (char) ((sig_buf[2] >> 8) & 0x00ff);
|
|
sig[6] = (char) (sig_buf[3] & 0x00ff);
|
|
sig[7] = (char) ((sig_buf[3] >> 8) & 0x00ff);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int compute_w16_alg_sig_32(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
int bit_mask;
|
|
int adj_len = len / 2;
|
|
int i;
|
|
unsigned short *_buf = (unsigned short *)buf;
|
|
unsigned short sig_buf[2];
|
|
|
|
if (len == 0) {
|
|
bzero(sig, 8);
|
|
return 0;
|
|
}
|
|
|
|
switch (len % 2) {
|
|
case 1:
|
|
bit_mask = 0x00ff;
|
|
break;
|
|
default:
|
|
bit_mask = 0xffff;
|
|
break;
|
|
}
|
|
|
|
if (len % 2 > 0) {
|
|
adj_len++;
|
|
}
|
|
|
|
// Account for buffer not being uint16_t aligned
|
|
sig_buf[0] = (_buf[adj_len - 1] & bit_mask);
|
|
sig_buf[1] = (_buf[adj_len - 1] & bit_mask);
|
|
|
|
/**
|
|
* This is the loop to optimize. It is currently optimized enough : using Horner's alg.,
|
|
* shortened mult. tables, and other tricks.
|
|
*/
|
|
for (i = adj_len - 2; i >= 0; i--) {
|
|
sig_buf[0] ^= _buf[i];
|
|
sig_buf[1] = (_buf[i] ^ (alg_sig_handle->tbl1_l[(sig_buf[1] >> 8) & 0x00ff] ^ alg_sig_handle->tbl1_r[sig_buf[1] & 0x00ff]));
|
|
}
|
|
|
|
sig[0] = (char) (sig_buf[0] & 0x000ff);
|
|
sig[1] = (char) ((sig_buf[0] >> 8) & 0x000ff);
|
|
sig[2] = (char) (sig_buf[1] & 0x00ff);
|
|
sig[3] = (char) ((sig_buf[1] >> 8) & 0x00ff);
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int compute_alg_sig_32(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
if (alg_sig_handle->gf_w == 8) {
|
|
return compute_w8_alg_sig_32(alg_sig_handle, buf, len, sig);
|
|
} else if (alg_sig_handle->gf_w == 16) {
|
|
return compute_w16_alg_sig_32(alg_sig_handle, buf, len, sig);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static
|
|
int compute_alg_sig_64(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
if (alg_sig_handle->gf_w == 16) {
|
|
return compute_w16_alg_sig_64(alg_sig_handle, buf, len, sig);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int compute_alg_sig(alg_sig_t *alg_sig_handle, char *buf, int len, char *sig)
|
|
{
|
|
if (alg_sig_handle->sig_len == 32) {
|
|
return compute_alg_sig_32(alg_sig_handle, buf, len, sig);
|
|
} else if (alg_sig_handle->sig_len == 64) {
|
|
return compute_alg_sig_64(alg_sig_handle, buf, len, sig);
|
|
}
|
|
return -1;
|
|
}
|