NORM-mirror/common/normEncoder.cpp

438 lines
12 KiB
C++

/*********************************************************************
*
* AUTHORIZATION TO USE AND DISTRIBUTE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that:
*
* (1) source code distributions retain this paragraph in its entirety,
*
* (2) distributions including binary code include this paragraph in
* its entirety in the documentation or other materials provided
* with the distribution, and
*
* (3) all advertising materials mentioning features or use of this
* software display the following acknowledgment:
*
* "This product includes software written and developed
* by Brian Adamson and Joe Macker of the Naval Research
* Laboratory (NRL)."
*
* The name of NRL, the name(s) of NRL employee(s), or any entity
* of the United States Government may not be used to endorse or
* promote products derived from this software, nor does the
* inclusion of the NRL written and developed software directly or
* indirectly suggest NRL or United States Government endorsement
* of this product.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include "normEncoder.h"
#include "galois.h" // for Galois math routines
#ifdef SIMULATE
#include "normMessage.h"
#endif // SIMULATE
NormEncoder::NormEncoder()
: npar(0), vector_size(0),
gen_poly(NULL), scratch(NULL)
{
} // end NormEncoder::NormEncoder()
NormEncoder::~NormEncoder()
{
if (gen_poly) Destroy();
}
bool NormEncoder::Init(int numParity, int vecSizeMax)
{
// Debugging assertions
ASSERT((numParity>=0)&&(numParity<129));
ASSERT(vecSizeMax >= 0);
if (gen_poly) Destroy();
npar = numParity;
#ifdef SIMULATE
vecSizeMax = MIN(SIM_PAYLOAD_MAX+1, vecSizeMax);
#endif // SIMUATE
vector_size = vecSizeMax;
// Create gen_poly polynomial
if(!CreateGeneratorPolynomial())
{
DMSG(0, "NormEncoder: Error creating gen_poly polynomial!\n");
return false;
}
// Allocate scratch space for encoding
if(!(scratch = new unsigned char[vecSizeMax]))
{
DMSG(0, "NormEncoder: Error allocating memory for encoder scratch space: %s\n",
GetErrorString());
Destroy();
return false;
}
return true;
} // end NormEncoder::Init()
// Free memory allocated for encoder state (Encoder must be re-inited before use)
void NormEncoder::Destroy()
{
if(NULL != scratch)
{
delete[] scratch;
scratch = NULL;
}
if (NULL != gen_poly)
{
delete[] gen_poly;
gen_poly = NULL;
}
} // end NormEncoder::Destroy()
bool NormEncoder::CreateGeneratorPolynomial()
{
unsigned char *tp, *tp1, *tp2;
int degree = 2*npar;
if(gen_poly) delete[] gen_poly;
if(!(gen_poly = new unsigned char[npar+1]))
{
DMSG(0, "NormEncoder: Error allocating memory for gen_poly polynomial: %s\n",
GetErrorString());
return false;
}
/* Allocate memory for temporary polynomial arrays */
if(!(tp = new unsigned char[2*degree]))
{
DMSG(0, "NormEncoder: 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;
DMSG(0, "NormEncoder: 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;
DMSG(0, "NormEncoder: Error allocating memory while computing gen_poly: %s\n",
GetErrorString());
return false;
}
// multiply (x + a^n) for n = 1 to npar
memset(tp1, 0, degree*sizeof(unsigned char));
tp1[0] = 1;
for (int n = 1; n <= npar; n++)
{
memset(tp, 0, degree*sizeof(unsigned char));
tp[0] = gexp(n); // set up x+a^n
tp[1] = 1;
// Polynomial multiplication
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;
// Scale tp2 by p1[i]
for(j=0; j<degree; j++) tp2[j]=gmult(tp1[j], tp[i]);
// Mult(shift) tp2 right by i
for (j = (degree*2)-1; j >= i; j--) tp2[j] = tp2[j-i];
memset(tp2, 0, i*sizeof(unsigned char));
// Add into partial product
for(j=0; j < (npar+1); j++) gen_poly[j] ^= tp2[j];
}
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;
} // end NormEncoder::CreateGeneratorPolynomial()
// Encode data vectors one at a time. The user of this function
// must keep track of when parity is ready for transmission
// Parity data is written to list of parity vectors supplied by caller
void NormEncoder::Encode(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(scratch); // Make sure it's been init'd first
// Assumes parity vectors are zero-filled at block start !!!
// Copy pVec[0] for use in calculations
#ifdef SIMULATE
UINT16 vecSize = MIN(SIM_PAYLOAD_MAX+1, vector_size);
#else
UINT16 vecSize = vector_size;
#endif // if/else SIMULATE
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++));
} // end NormEncoder::Encode()
/********************************************************************************
* NormDecoder implementation routines
*/
NormDecoder::NormDecoder()
: npar(0), vector_size(0), lambda(NULL),
s_vec(NULL), o_vec(NULL), scratch(NULL)
{
}
NormDecoder::~NormDecoder()
{
if (lambda) Destroy();
}
bool NormDecoder::Init(int numParity, int vecSizeMax)
{
// Debugging assertions
ASSERT((numParity>=0)&&(numParity<=128));
ASSERT(vecSizeMax >= 0);
#ifdef SIMULATE
vecSizeMax = MIN(SIM_PAYLOAD_MAX+1, vecSizeMax);
#endif // SIMUATE
if (lambda) Destroy(); // Check if already inited ...
npar = numParity;
vector_size = vecSizeMax;
if(!(lambda = new unsigned char[2*npar]))
{
DMSG(0, "NormDecoder: Error allocating memory for lambda: %s\n",
GetErrorString());
return(false);
}
/* Allocate memory for s_vec ptr and the syndrome vectors */
if(!(s_vec = new unsigned char*[npar]))
{
DMSG(0, "NormDecoder: Error allocating memory for s_vec ptr: %s\n",
GetErrorString());
Destroy();
return(false);
}
int i;
for(i=0; i < npar; i++)
{
if(!(s_vec[i] = new unsigned char[vecSizeMax]))
{
DMSG(0, "NormDecoder: Error allocating memory for new s_vec: %s\n",
GetErrorString());
Destroy();
return(false);
}
}
/* Allocate memory for the o_vec ptr and the Omega vectors */
if(!(o_vec = new unsigned char*[npar]))
{
DMSG(0, "NormDecoder: 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]))
{
DMSG(0, "NormDecoder: Error allocating memory for new o_vec: %s",
GetErrorString());
Destroy();
return(false);
}
}
if (!(scratch = new unsigned char[vecSizeMax]))
{
DMSG(0, "NormDecoder: Error allocating memory for scratch space: %s",
GetErrorString());
}
memset(scratch, 0, vecSizeMax*sizeof(unsigned char));
return(true);
} // end NormDecoder::Init()
void NormDecoder::Destroy()
{
if (scratch)
{
delete[] scratch;
scratch = NULL;
}
if(o_vec)
{
for(int i=0; i<npar; i++)
if (o_vec[i]) delete[] o_vec[i];
delete[] o_vec;
o_vec = NULL;
}
if(s_vec)
{
for(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;
}
} // end NormDecoder::Destroy()
// This will crash & burn if (erasureCount > npar)
int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* erasureLocs)
{
// Debugging assertions
ASSERT(lambda);
ASSERT(erasureCount && (erasureCount<=npar));
// (A) Compute syndrome vectors
// First zero out erasure vectors (MDP provides zero-filled vecs)
// Then calculate syndrome (based on zero value erasures)
int nvecs = npar + ndata;
#ifdef SIMULATE
int vecSize = MIN(SIM_PAYLOAD_MAX+1, vector_size);
#else
int vecSize = vector_size;
#endif // if/else SIMUATE
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(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++;
}
}
}
// (B) Init lambda (the erasure locator polynomial)
int degree = 2*npar;
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]);
}
// (C) Compute modified Omega using lambda
for(i = 0; i < npar; i++)
{
int k = i;
memset(o_vec[i], 0, vecSize*sizeof(char));
int m = i + 1;
for(int j = 0; j < m; j++)
{
unsigned char* Omega = o_vec[i];
unsigned char* S = s_vec[j];
int Lk = lambda[k--];
for(int n = 0; n < vecSize; n++)
*Omega++ ^= gmult(*S++, Lk);
}
}
// (D) Finally, fill in the erasures
for (i = 0; i < erasureCount; i++)
{
// Only fill _data_ erasures
if (erasureLocs[i] >= ndata) break;//return erasureCount;
// evaluate lambda' (derivative) at alpha^(-i)
// ( all odd powers disappear)
int k = nvecsMinusOne - erasureLocs[i];
int denom = 0;
int j;
for (j = 1; j < degree; j += 2)
denom ^= gmult(lambda[j], gexp(((255-k)*(j-1)) % 255));
// Invert for use computing error value below
denom = ginv(denom);
// Now evaluate Omega at alpha^(-i) (numerator)
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);
}
// Scale numerator with denominator
unsigned char* data = eVec;
for(int n = 0; n < vecSize; n++)
{
*data = gmult(*data, denom);
data++;
}
}
return erasureCount;
} // end NormDecoder::Decode()