#include <stdlib.h>
#include <string.h>
#include "normEncoderMDP.h"
#include "galois.h"
#ifdef SIMULATE
#include "normMessage.h"
#endif
NormEncoderMDP::NormEncoderMDP()
: npar(0), vector_size(0),
gen_poly(NULL), scratch(NULL)
{
}
NormEncoderMDP::~NormEncoderMDP()
{
if (gen_poly) Destroy();
}
bool NormEncoderMDP::Init(unsigned int numData, unsigned int numParity, UINT16 vecSizeMax)
{
ASSERT((numData + numParity) <= 255);
if ((numData + numParity) > 255) return false; if (gen_poly) Destroy();
npar = numParity;
#ifdef SIMULATE
vecSizeMax = MIN(SIM_PAYLOAD_MAX, vecSizeMax);
#endif
vector_size = vecSizeMax;
if(!CreateGeneratorPolynomial())
{
PLOG(PL_FATAL, "NormEncoderMDP: Error creating gen_poly polynomial!\n");
return false;
}
if(!(scratch = new unsigned char[vecSizeMax]))
{
PLOG(PL_FATAL, "NormEncoderMDP: Error allocating memory for encoder scratch space: %s\n",
GetErrorString());
Destroy();
return false;
}
return true;
}
void NormEncoderMDP::Destroy()
{
if(NULL != scratch)
{
delete[] scratch;
scratch = NULL;
}
if (NULL != gen_poly)
{
delete[] gen_poly;
gen_poly = NULL;
}
}
bool NormEncoderMDP::CreateGeneratorPolynomial()
{
unsigned char *tp, *tp1, *tp2;
int degree = 2*npar;
if(gen_poly) delete[] gen_poly;
if(!(gen_poly = new unsigned char[npar+1]))
{
PLOG(PL_FATAL, "NormEncoderMDP: Error allocating memory for gen_poly polynomial: %s\n",
GetErrorString());
return false;
}
if(!(tp = new unsigned char[2*degree]))
{
PLOG(PL_FATAL, "NormEncoderMDP: Error allocating memory while computing gen_poly: %s\n",
GetErrorString());
delete[] gen_poly;
return false;
}
if(!(tp1 = new unsigned char[2*degree]))
{
delete[] tp;
delete[] gen_poly;
PLOG(PL_FATAL, "NormEncoderMDP: Error allocating memory while computing gen_poly: %s\n",
GetErrorString());
return false;
}
if(!(tp2 = new unsigned char[2*degree]))
{
delete[] tp1;
delete[] tp;
delete[] gen_poly;
PLOG(PL_FATAL, "NormEncoderMDP: Error allocating memory while computing gen_poly: %s\n",
GetErrorString());
return false;
}
memset(tp1, 0, degree*sizeof(unsigned char));
tp1[0] = 1;
for (unsigned int n = 1; n <= npar; n++)
{
memset(tp, 0, degree*sizeof(unsigned char));
tp[0] = gexp(n); tp[1] = 1;
memset(gen_poly, 0, (npar+1)*sizeof(unsigned char));
for (int i = 0; i < degree; i++)
{
memset(&tp2[degree], 0, degree*sizeof(unsigned char));
int j;
for(j=0; j<degree; j++) tp2[j]=gmult(tp1[j], tp[i]);
for (j = (degree*2)-1; j >= i; j--)
tp2[j] = tp2[j-i];
memset(tp2, 0, i*sizeof(unsigned char));
for(unsigned int x=0; x < (npar+1); x++) gen_poly[x] ^= tp2[x];
}
memcpy(tp1, gen_poly, (npar+1)*sizeof(unsigned char));
memset(&tp1[npar+1], 0, (2*degree)-(npar+1));
}
delete[] tp2;
delete[] tp1;
delete[] tp;
return true;
}
void NormEncoderMDP::Encode(unsigned int , const char* data, char** pVec)
{
int i, j;
unsigned char *userData, *LSFR1, *LSFR2, *pVec0;
int npar_minus_one = npar - 1;
unsigned char* genPoly = &gen_poly[npar_minus_one];
ASSERT(NULL != scratch);
UINT16 vecSize = vector_size;
memcpy(scratch, pVec[0], vecSize);
if (npar > 1)
{
for(i = 0; i < npar_minus_one; i++)
{
pVec0 = scratch;
userData = (unsigned char*) data;
LSFR1 = (unsigned char*) pVec[i];
LSFR2 = (unsigned char*) pVec[i+1];
for(j = 0; j < vecSize; j++)
*LSFR1++ = *LSFR2++ ^
gmult(*genPoly, (*userData++ ^ *pVec0++));
genPoly--;
}
}
pVec0 = scratch;
userData = (unsigned char*) data;
LSFR1 = (unsigned char*) pVec[npar_minus_one];
for(j = 0; j < vecSize; j++)
*LSFR1++ = gmult(*genPoly, (*userData++ ^ *pVec0++));
}
NormDecoderMDP::NormDecoderMDP()
: npar(0), vector_size(0), lambda(NULL),
s_vec(NULL), o_vec(NULL), scratch(NULL)
{
}
NormDecoderMDP::~NormDecoderMDP()
{
if (NULL != lambda) Destroy();
}
bool NormDecoderMDP::Init(unsigned int numData, unsigned int numParity, UINT16 vecSizeMax)
{
ASSERT((numData + numParity) <= 255);
if ((numData + numParity) > 255) return false;
#ifdef SIMULATE
vecSizeMax = MIN(SIM_PAYLOAD_MAX, vecSizeMax);
#endif
if (lambda) Destroy();
npar = numParity;
vector_size = vecSizeMax;
if(!(lambda = new unsigned char[2*npar]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for lambda: %s\n",
GetErrorString());
return(false);
}
if(!(s_vec = new unsigned char*[npar]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for s_vec ptr: %s\n",
GetErrorString());
Destroy();
return(false);
}
unsigned int i;
for(i=0; i < npar; i++)
{
if(!(s_vec[i] = new unsigned char[vecSizeMax]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for new s_vec: %s\n",
GetErrorString());
Destroy();
return(false);
}
}
if(!(o_vec = new unsigned char*[npar]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for new o_vec ptr: %s\n",
GetErrorString());
Destroy();
return(false);
}
for(i=0; i < npar; i++)
{
if(!(o_vec[i] = new unsigned char[vecSizeMax]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for new o_vec: %s",
GetErrorString());
Destroy();
return(false);
}
}
if (!(scratch = new unsigned char[vecSizeMax]))
{
PLOG(PL_FATAL, "NormDecoderMDP: Error allocating memory for scratch space: %s",
GetErrorString());
}
memset(scratch, 0, vecSizeMax*sizeof(unsigned char));
return(true);
}
void NormDecoderMDP::Destroy()
{
if (scratch)
{
delete[] scratch;
scratch = NULL;
}
if(o_vec)
{
for(unsigned int i=0; i<npar; i++)
if (o_vec[i]) delete[] o_vec[i];
delete[] o_vec;
o_vec = NULL;
}
if(s_vec)
{
for(unsigned int i = 0; i < npar; i++)
if (s_vec[i]) delete[] s_vec[i];
delete[] s_vec;
s_vec = NULL;
}
if (lambda)
{
delete[] lambda;
lambda = NULL;
}
}
int NormDecoderMDP::Decode(char** dVec, unsigned int numData, unsigned int erasureCount, unsigned int* erasureLocs)
{
ASSERT(NULL != lambda);
ASSERT(erasureCount && (erasureCount <= npar));
unsigned int nvecs = npar + numData;
UINT16 vecSize = vector_size;
unsigned int i;
for (i = 0; i < npar; i++)
{
int X = gexp(i+1);
unsigned char* synVec = s_vec[i];
memset(synVec, 0, vecSize*sizeof(char));
for(unsigned int j = 0; j < nvecs; j++)
{
unsigned char* data = dVec[j] ? (unsigned char*)dVec[j] : scratch;
unsigned char* S = synVec;
for (int n = 0; n < vecSize; n++)
{
*S = *data++ ^ gmult(X, *S);
S++;
}
}
}
unsigned int degree = 2*npar;
unsigned int nvecsMinusOne = nvecs - 1;
memset(lambda, 0, degree*sizeof(char));
lambda[0] = 1;
for (i = 0; i < erasureCount; i++)
{
int X = gexp(nvecsMinusOne - erasureLocs[i]);
for(int j = (degree-1); j > 0; j--)
lambda[j] = lambda[j] ^ gmult(X, lambda[j-1]);
}
for(i = 0; i < npar; i++)
{
int k = i;
memset(o_vec[i], 0, vecSize*sizeof(char));
for(unsigned int j = 0; j <= i; j++)
{
unsigned char* Omega = o_vec[i];
unsigned char* S = s_vec[j];
int Lk = lambda[k--];
for(UINT16 n = 0; n < vecSize; n++)
*Omega++ ^= gmult(*S++, Lk);
}
}
for (i = 0; i < erasureCount; i++)
{
if (erasureLocs[i] >= numData) break;
unsigned int k = nvecsMinusOne - erasureLocs[i];
int denom = 0;
unsigned int j;
for (j = 1; j < degree; j += 2)
denom ^= gmult(lambda[j], gexp(((255-k)*(j-1)) % 255));
denom = ginv(denom);
unsigned char* eVec = (unsigned char*)dVec[erasureLocs[i]];
for (j = 0; j < npar; j++)
{
unsigned char* data = eVec;
unsigned char* Omega = o_vec[j];
int X = gexp(((255-k)*j) % 255);
for(int n = 0; n < vecSize; n++)
*data++ ^= gmult(*Omega++, X);
}
unsigned char* data = eVec;
for(int n = 0; n < vecSize; n++)
{
*data = gmult(*data, denom);
data++;
}
}
return erasureCount;
}