// Reed-Solomon encoding/erasure decoding // Fast version on GF(2^n_field) using Walsh transform // Implementation of the algorithms described in // Efficient erasure decoding of Reed-Solomon codes // http://arxiv.org/abs/0901.1886v1 // (c) 2009 Frederic didier. // Any feedback is very welcome. For any question, comments, // see http://algo.epfl.ch/~didier/reed_solomon.html or email // frederic.didier@epfl.ch // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. 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 AUTHORS ``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 AUTHORS // 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 "reed_solomon.h" #include "stdlib.h" #include "stdio.h" // ************************************************ // ************************************************ int n_field; int n_walsh; int N_field; int N_walsh; int modulo; // GF tables symbol *log_table; symbol *exp_table; // Encoding/Decoding product symbol *product; symbol *product_enc; // Used to compute product symbol *log_walsh; symbol *pos; // extra memory needed for fast evaluation symbol *coeff, *t_coeff; symbol *inverse, *t_inverse; void memory_init() { log_table = (symbol *)malloc(sizeof(symbol)*N_field); exp_table = (symbol *)malloc(sizeof(symbol)*2*N_field); product = (symbol *)malloc(sizeof(symbol)*N_walsh); product_enc = (symbol *)malloc(sizeof(symbol)*N_walsh); log_walsh = (symbol *)malloc(sizeof(symbol)*N_walsh); pos = (symbol *)malloc(sizeof(symbol)*N_walsh); inverse = t_inverse = (symbol *) malloc(sizeof(symbol) * N_walsh * n_field + 8); coeff = t_coeff = (symbol *) malloc(sizeof(symbol) * N_walsh * n_field + 8); // align memory for SSE operation while ((int)(inverse) & 0xf) inverse++; while ((int)(coeff) & 0xf) coeff++; } void memory_clear() { free(log_table); free(exp_table); free(product); free(product_enc); free(log_walsh); free(pos); free(t_inverse); free(t_coeff); } // ************************************************ // ************************************************ // compute the tables for the finite field operations // exp_table is twice the needed size so we do not need to // perform a modulo each time. // list of some primitive polynomials int primitive[] = { 0,1,6, 0,3,7, 0,2,3,4,8, 0,4,9, 0,3,10, 0,2,11, 0,1,4,6,12, 0,1,3,4,13, 0,1,11,12,14, 0,1,15, 0,1,3,12,16, 0,3,17, 0,3,20, 0,3,25, 100 // fallback }; // will be set to the primitive poly of the field // used only by the fast algorithm version int *poly; int weight; void fill_table() { int i; // put the primitive poly in mask int temp=0; int mask=0; int index=0; while (1) { if (primitive[index]==0) { mask=0; temp=index; } mask ^= 1 << primitive[index]; if (primitive[index]>=n_field) break; index++; } // used for the fast version only poly = &primitive[temp]; weight = index-temp; if (primitive[index]!=n_field) { printf("primitive poly for GF %d not found !\n", n_field); } // clock the lfsr (multiply by X) // fill the table int state=1; for (i=0; i>n_field) state^=mask; if (state>>n_field!=0) exit(0); } // small change so we have bijection log_table[0]=0; log_table[1]=modulo; exp_table[2*modulo]=1; } // ************************************************ // ************************************************ void walsh_mod(symbol *vect, int size); void compute_product(); void walsh_field(symbol *vect); // ************************************************ // ************************************************ void log_walsh_init() { int i; for (i=0; i>j)&1; } // precompute the Walsh transforms of the inverse walsh_field(inverse); // everything is even if n_walsh=16 // divide by two so computation fit on 16 bits! // otherwise, multiply by power of two, so // shift factor is always 15. if (n_walsh==16) for (i=0; i>= 1; else { for (i=0; i31 || nw > nf) { printf("incorrect field parameters\n"); exit(0); } n_field = nf; n_walsh = nw; N_field = 1<>n_field); // b = (b & modulo) + (b>>n_field); // on GF 2^16 a = a + (a>>16); b = b + (b>>16); vect[i]=a; vect[i+step]=b; i++; } i+=step; } step<<=1; } } // ************************************************ // ************************************************ // compute the product (3) of the paper // return in product the logarithm of the product void compute_product() { int i; // initialisation for (i=0; i 16 // otherwise int is ok. for (i=0; imodulo) t-= modulo; product[j] = t; } } } // ******************************************************* // ******************************************************* // Perform a Walsh transform // Nothing special this time, except that we do not // have to worry about any overflow since in our use, // only the bit n_walsh will be important // // special version that do n_field transforms at once. // one of the limiting part in the complexity void walsh_field_generic(symbol *vect) { int i,j; int step=n_field; int size=n_field * N_walsh; while (step (A+B, A-B) // where sizeof A = sizeof B = s*32 bits void walsh_step(symbol *p, symbol *q, int s) { while (s--) { __asm__ __volatile__ ( "movdqa (%%esi), %%xmm0\n" "movdqa 16(%%esi), %%xmm1\n" "movdqa 32(%%esi), %%xmm2\n" "movdqa 48(%%esi), %%xmm3\n" "movdqa (%%edi), %%xmm4\n" "movdqa 16(%%edi), %%xmm5\n" "movdqa 32(%%edi), %%xmm6\n" "movdqa 48(%%edi), %%xmm7\n" "psubw %%xmm4, %%xmm0\n" "psubw %%xmm5, %%xmm1\n" "psubw %%xmm6, %%xmm2\n" "psubw %%xmm7, %%xmm3\n" "psllw $1,%%xmm4\n" "psllw $1,%%xmm5\n" "psllw $1,%%xmm6\n" "psllw $1,%%xmm7\n" "paddw %%xmm0, %%xmm4\n" "paddw %%xmm1, %%xmm5\n" "paddw %%xmm2, %%xmm6\n" "paddw %%xmm3, %%xmm7\n" "movdqa %%xmm4, (%%esi)\n" "movdqa %%xmm5, 16(%%esi)\n" "movdqa %%xmm6, 32(%%esi)\n" "movdqa %%xmm7, 48(%%esi)\n" "movdqa %%xmm0, (%%edi)\n" "movdqa %%xmm1, 16(%%edi)\n" "movdqa %%xmm2, 32(%%edi)\n" "movdqa %%xmm3, 48(%%edi)\n" : : "S"(p), "D"(q) : "memory"); p += 32; q += 32; } } // Perform a Walsh step (A,B) -> (A+B, A-B) // where sizeof A = sizeof B = s*16 bits void walsh_step_simple(symbol *p, symbol *q, int s) { while (s--) { __asm__ __volatile__ ( "movdqa (%%esi), %%xmm0\n" "movdqa 16(%%esi), %%xmm1\n" "movdqa (%%edi), %%xmm4\n" "movdqa 16(%%edi), %%xmm5\n" "psubw %%xmm4, %%xmm0\n" "psubw %%xmm5, %%xmm1\n" "psllw $1,%%xmm4\n" "psllw $1,%%xmm5\n" "paddw %%xmm0, %%xmm4\n" "paddw %%xmm1, %%xmm5\n" "movdqa %%xmm4, (%%esi)\n" "movdqa %%xmm5, 16(%%esi)\n" "movdqa %%xmm0, (%%edi)\n" "movdqa %%xmm1, 16(%%edi)\n" : : "S"(p), "D"(q) : "memory"); p += 16; q += 16; } } // iterative DFS void walsh_field_iter(symbol *p, int size) { int i; size/=4; for (i=0; i>= 1; }; // next bloc p += 4*NFIELD; } } // Recursive version void walsh_field_rec(symbol *p, int size) { // if (size==2) return walsh_step_simple(p,p+n_field,1); if (size==4) return walsh_end(p); size /= 2; symbol *q = p + size*NFIELD; walsh_field_rec(p,size); walsh_field_rec(q,size); // walsh_step_simple(p,q,size); walsh_step(p,q,size/2); } void walsh_field(symbol *vect) { return walsh_field_iter(vect, N_walsh); return walsh_field_rec(vect, N_walsh); int i,j; int step=n_field; int size=n_field * N_walsh; while (step>=1; // we are interested only in the parity // so no need to add &1; } } // compute the Walsh transforms of the coefficient walsh_field(coeff); // multiply with precomputed Walsh transform of the inverse field_product(); // walsh transform again walsh_field(coeff); // put decoded symbol in place // final multiplication by the product temp = coeff + K*n_field; for (i=0; i>= 1; t ^= *(temp++); } if (t) t = exp_table[log_table[t] + product_enc[K+i]]; parity[i*S + j] = t; } } } void fast_decode(int K, int S, int *positions, symbol *data, symbol *packets) { int i,j,k; // copy the systematic pieces in place for (i=0; i>=1; // we are interested only in the parity // so no need to add &1; } } // compute the Walsh transforms of the coefficient walsh_field(coeff); // multiply with precomputed Walsh transform of the inverse field_product(); // walsh transform again walsh_field(coeff); // put decoded symbol in place // final multiplication by the product for (i=0; i>= 1; t ^= *(temp++); } if (t) t = exp_table[log_table[t] + product[i]]; packets[i*S + j] = t; } } }