[btr] Only print debug message if we're really increasing the wrap buffer.
[paraslash.git] / fec.c
1 /** \file fec.c Forward error correction based on Vandermonde matrices. */
2
3 /*
4 * 980624
5 * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
6 *
7 * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
8 * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
9 * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials
20 * provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
34 */
35
36 #include <regex.h>
37
38 #include "para.h"
39 #include "error.h"
40 #include "portable_io.h"
41 #include "string.h"
42 #include "fec.h"
43
44 /** Code over GF(256). */
45 #define GF_BITS 8
46 /** The largest number in GF(256) */
47 #define GF_SIZE ((1 << GF_BITS) - 1)
48
49 /*
50 * To speed up computations, we have tables for logarithm, exponent and inverse
51 * of a number.
52 */
53
54 /** Index->poly form conversion table. */
55 static unsigned char gf_exp[2 * GF_SIZE];
56
57 /** Poly->index form conversion table. */
58 static int gf_log[GF_SIZE + 1];
59
60 /** Inverse of a field element. */
61 static unsigned char inverse[GF_SIZE + 1];
62
63 /**
64 * The multiplication table.
65 *
66 * We use a table for multiplication as well. It takes 64K, no big deal even on
67 * a PDA, especially because it can be pre-initialized and put into a ROM.
68 *
69 * \sa \ref gf_mul.
70 */
71 static unsigned char gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
72
73 /** Multiply two GF numbers. */
74 #define gf_mul(x,y) gf_mul_table[x][y]
75
76 /* Compute x % GF_SIZE without a slow divide. */
77 static inline unsigned char modnn(int x)
78 {
79 while (x >= GF_SIZE) {
80 x -= GF_SIZE;
81 x = (x >> GF_BITS) + (x & GF_SIZE);
82 }
83 return x;
84 }
85
86 static void init_mul_table(void)
87 {
88 int i, j;
89 for (i = 0; i < GF_SIZE + 1; i++)
90 for (j = 0; j < GF_SIZE + 1; j++)
91 gf_mul_table[i][j] =
92 gf_exp[modnn(gf_log[i] + gf_log[j])];
93
94 for (j = 0; j < GF_SIZE + 1; j++)
95 gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
96 }
97
98 static unsigned char *alloc_matrix(int rows, int cols)
99 {
100 return para_malloc(rows * cols);
101 }
102
103 /*
104 * Initialize the data structures used for computations in GF.
105 *
106 * This generates GF(2**GF_BITS) from the irreducible polynomial p(X) in
107 * p[0]..p[m].
108 *
109 * Lookup tables:
110 * index->polynomial form gf_exp[] contains j= \alpha^i;
111 * polynomial form -> index form gf_log[ j = \alpha^i ] = i
112 * \alpha=x is the primitive element of GF(2^m)
113 *
114 * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
115 * multiplication of two numbers can be resolved without calling modnn
116 */
117 static void generate_gf(void)
118 {
119 int i;
120 unsigned char mask = 1;
121 char *pp = "101110001"; /* The primitive polynomial 1+x^2+x^3+x^4+x^8 */
122 gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
123
124 /*
125 * first, generate the (polynomial representation of) powers of \alpha,
126 * which are stored in gf_exp[i] = \alpha ** i .
127 * At the same time build gf_log[gf_exp[i]] = i .
128 * The first GF_BITS powers are simply bits shifted to the left.
129 */
130 for (i = 0; i < GF_BITS; i++, mask <<= 1) {
131 gf_exp[i] = mask;
132 gf_log[gf_exp[i]] = i;
133 /*
134 * If pp[i] == 1 then \alpha ** i occurs in poly-repr
135 * gf_exp[GF_BITS] = \alpha ** GF_BITS
136 */
137 if (pp[i] == '1')
138 gf_exp[GF_BITS] ^= mask;
139 }
140 /*
141 * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can also
142 * compute its inverse.
143 */
144 gf_log[gf_exp[GF_BITS]] = GF_BITS;
145 /*
146 * Poly-repr of \alpha ** (i+1) is given by poly-repr of \alpha ** i
147 * shifted left one-bit and accounting for any \alpha ** GF_BITS term
148 * that may occur when poly-repr of \alpha ** i is shifted.
149 */
150 mask = 1 << (GF_BITS - 1);
151 for (i = GF_BITS + 1; i < GF_SIZE; i++) {
152 if (gf_exp[i - 1] >= mask)
153 gf_exp[i] =
154 gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
155 else
156 gf_exp[i] = gf_exp[i - 1] << 1;
157 gf_log[gf_exp[i]] = i;
158 }
159 /*
160 * log(0) is not defined, so use a special value
161 */
162 gf_log[0] = GF_SIZE;
163 /* set the extended gf_exp values for fast multiply */
164 for (i = 0; i < GF_SIZE; i++)
165 gf_exp[i + GF_SIZE] = gf_exp[i];
166
167 inverse[0] = 0; /* 0 has no inverse. */
168 inverse[1] = 1;
169 for (i = 2; i <= GF_SIZE; i++)
170 inverse[i] = gf_exp[GF_SIZE - gf_log[i]];
171 }
172
173 /** How often the loop is unrolled. */
174 #define UNROLL 16
175
176 /*
177 * Compute dst[] = dst[] + c * src[]
178 *
179 * This is used often, so better optimize it! Currently the loop is unrolled 16
180 * times. The case c=0 is also optimized, whereas c=1 is not.
181 */
182 static void addmul(unsigned char *dst1, const unsigned char const *src1,
183 unsigned char c, int sz)
184 {
185 if (c == 0)
186 return;
187 unsigned char *dst = dst1, *lim = &dst[sz - UNROLL + 1],
188 *col = gf_mul_table[c];
189 const unsigned char const *src = src1;
190
191 for (; dst < lim; dst += UNROLL, src += UNROLL) {
192 dst[0] ^= col[src[0]];
193 dst[1] ^= col[src[1]];
194 dst[2] ^= col[src[2]];
195 dst[3] ^= col[src[3]];
196 dst[4] ^= col[src[4]];
197 dst[5] ^= col[src[5]];
198 dst[6] ^= col[src[6]];
199 dst[7] ^= col[src[7]];
200 dst[8] ^= col[src[8]];
201 dst[9] ^= col[src[9]];
202 dst[10] ^= col[src[10]];
203 dst[11] ^= col[src[11]];
204 dst[12] ^= col[src[12]];
205 dst[13] ^= col[src[13]];
206 dst[14] ^= col[src[14]];
207 dst[15] ^= col[src[15]];
208 }
209 lim += UNROLL - 1;
210 for (; dst < lim; dst++, src++) /* final components */
211 *dst ^= col[*src];
212 }
213
214 /*
215 * Compute C = AB where A is n*k, B is k*m, C is n*m
216 */
217 static void matmul(unsigned char *a, unsigned char *b, unsigned char *c,
218 int n, int k, int m)
219 {
220 int row, col, i;
221
222 for (row = 0; row < n; row++) {
223 for (col = 0; col < m; col++) {
224 unsigned char *pa = &a[row * k], *pb = &b[col], acc = 0;
225 for (i = 0; i < k; i++, pa++, pb += m)
226 acc ^= gf_mul(*pa, *pb);
227 c[row * m + col] = acc;
228 }
229 }
230 }
231
232 /** Swap two numbers. */
233 #define FEC_SWAP(a,b) {typeof(a) tmp = a; a = b; b = tmp;}
234
235 /*
236 * Compute the inverse of a matrix.
237 *
238 * k is the size of the matrix 'src' (Gauss-Jordan, adapted from Numerical
239 * Recipes in C). Returns negative on errors.
240 */
241 static int invert_mat(unsigned char *src, int k)
242 {
243 int irow, icol, row, col, ix, error;
244 int *indxc = para_malloc(k * sizeof(int));
245 int *indxr = para_malloc(k * sizeof(int));
246 int *ipiv = para_malloc(k * sizeof(int)); /* elements used as pivots */
247 unsigned char c, *p, *id_row = alloc_matrix(1, k),
248 *temp_row = alloc_matrix(1, k);
249
250 memset(id_row, 0, k);
251 memset(ipiv, 0, k * sizeof(int));
252
253 for (col = 0; col < k; col++) {
254 unsigned char *pivot_row;
255 /*
256 * Zeroing column 'col', look for a non-zero element.
257 * First try on the diagonal, if it fails, look elsewhere.
258 */
259 irow = icol = -1;
260 if (ipiv[col] != 1 && src[col * k + col] != 0) {
261 irow = col;
262 icol = col;
263 goto found_piv;
264 }
265 for (row = 0; row < k; row++) {
266 if (ipiv[row] != 1) {
267 for (ix = 0; ix < k; ix++) {
268 if (ipiv[ix] == 0) {
269 if (src[row * k + ix] != 0) {
270 irow = row;
271 icol = ix;
272 goto found_piv;
273 }
274 } else if (ipiv[ix] > 1) {
275 error = -E_FEC_PIVOT;
276 goto fail;
277 }
278 }
279 }
280 }
281 error = -E_FEC_PIVOT;
282 if (icol == -1)
283 goto fail;
284 found_piv:
285 ++(ipiv[icol]);
286 /*
287 * swap rows irow and icol, so afterwards the diagonal element
288 * will be correct. Rarely done, not worth optimizing.
289 */
290 if (irow != icol)
291 for (ix = 0; ix < k; ix++)
292 FEC_SWAP(src[irow * k + ix], src[icol * k + ix]);
293 indxr[col] = irow;
294 indxc[col] = icol;
295 pivot_row = &src[icol * k];
296 error = -E_FEC_SINGULAR;
297 c = pivot_row[icol];
298 if (c == 0)
299 goto fail;
300 if (c != 1) { /* otherwise this is a NOP */
301 /*
302 * this is done often , but optimizing is not so
303 * fruitful, at least in the obvious ways (unrolling)
304 */
305 c = inverse[c];
306 pivot_row[icol] = 1;
307 for (ix = 0; ix < k; ix++)
308 pivot_row[ix] = gf_mul(c, pivot_row[ix]);
309 }
310 /*
311 * from all rows, remove multiples of the selected row to zero
312 * the relevant entry (in fact, the entry is not zero because
313 * we know it must be zero). (Here, if we know that the
314 * pivot_row is the identity, we can optimize the addmul).
315 */
316 id_row[icol] = 1;
317 if (memcmp(pivot_row, id_row, k) != 0) {
318 for (p = src, ix = 0; ix < k; ix++, p += k) {
319 if (ix != icol) {
320 c = p[icol];
321 p[icol] = 0;
322 addmul(p, pivot_row, c, k);
323 }
324 }
325 }
326 id_row[icol] = 0;
327 }
328 for (col = k - 1; col >= 0; col--) {
329 if (indxr[col] < 0 || indxr[col] >= k)
330 PARA_CRIT_LOG("AARGH, indxr[col] %d\n", indxr[col]);
331 else if (indxc[col] < 0 || indxc[col] >= k)
332 PARA_CRIT_LOG("AARGH, indxc[col] %d\n", indxc[col]);
333 else if (indxr[col] != indxc[col]) {
334 for (row = 0; row < k; row++) {
335 FEC_SWAP(src[row * k + indxr[col]],
336 src[row * k + indxc[col]]);
337 }
338 }
339 }
340 error = 0;
341 fail:
342 free(indxc);
343 free(indxr);
344 free(ipiv);
345 free(id_row);
346 free(temp_row);
347 return error;
348 }
349
350 /*
351 * Invert a Vandermonde matrix.
352 *
353 * It assumes that the matrix is not singular and _IS_ a Vandermonde matrix.
354 * Only uses the second column of the matrix, containing the p_i's.
355 *
356 * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but largely
357 * revised for GF purposes.
358 */
359 static void invert_vdm(unsigned char *src, int k)
360 {
361 int i, j, row, col;
362 unsigned char *b, *c, *p, t, xx;
363
364 if (k == 1) /* degenerate */
365 return;
366 /*
367 * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
368 * b holds the coefficient for the matrix inversion
369 */
370 c = para_malloc(k);
371 b = para_malloc(k);
372 p = para_malloc(k);
373
374 for (j = 1, i = 0; i < k; i++, j += k) {
375 c[i] = 0;
376 p[i] = src[j];
377 }
378 /*
379 * construct coeffs recursively. We know c[k] = 1 (implicit) and start
380 * P_0 = x - p_0, then at each stage multiply by x - p_i generating P_i
381 * = x P_{i-1} - p_i P_{i-1} After k steps we are done.
382 */
383 c[k - 1] = p[0]; /* really -p(0), but x = -x in GF(2^m) */
384 for (i = 1; i < k; i++) {
385 unsigned char p_i = p[i];
386 for (j = k - 1 - (i - 1); j < k - 1; j++)
387 c[j] ^= gf_mul(p_i, c[j + 1]);
388 c[k - 1] ^= p_i;
389 }
390
391 for (row = 0; row < k; row++) {
392 /*
393 * synthetic division etc.
394 */
395 xx = p[row];
396 t = 1;
397 b[k - 1] = 1; /* this is in fact c[k] */
398 for (i = k - 2; i >= 0; i--) {
399 b[i] = c[i + 1] ^ gf_mul(xx, b[i + 1]);
400 t = gf_mul(xx, t) ^ b[i];
401 }
402 for (col = 0; col < k; col++)
403 src[col * k + row] = gf_mul(inverse[t], b[col]);
404 }
405 free(c);
406 free(b);
407 free(p);
408 }
409
410 static int fec_initialized;
411
412 static void init_fec(void)
413 {
414 generate_gf();
415 init_mul_table();
416 fec_initialized = 1;
417 }
418
419 /** Internal FEC parameters. */
420 struct fec_parms {
421 /** Number of data slices. */
422 int k;
423 /** Number of slices (including redundant slices). */
424 int n;
425 /** The encoding matrix, computed by init_fec(). */
426 unsigned char *enc_matrix;
427 };
428
429 /**
430 * Deallocate a fec params structure.
431 *
432 * \param p The structure to free.
433 */
434 void fec_free(struct fec_parms *p)
435 {
436 if (!p)
437 return;
438 free(p->enc_matrix);
439 free(p);
440 }
441
442 /**
443 * Create a new encoder and return an opaque descriptor to it.
444 *
445 * \param k Number of input slices.
446 * \param n Number of output slices.
447 * \param result On success the Fec descriptor is returned here.
448 *
449 * \return Standard.
450 *
451 * This creates the k*n encoding matrix. It is computed starting with a
452 * Vandermonde matrix, and then transformed into a systematic matrix.
453 */
454 int fec_new(int k, int n, struct fec_parms **result)
455 {
456 int row, col;
457 unsigned char *p, *tmp_m;
458 struct fec_parms *parms;
459
460 if (!fec_initialized)
461 init_fec();
462
463 if (k < 1 || k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n)
464 return -E_FEC_PARMS;
465 parms = para_malloc(sizeof(struct fec_parms));
466 parms->k = k;
467 parms->n = n;
468 parms->enc_matrix = alloc_matrix(n, k);
469 tmp_m = alloc_matrix(n, k);
470 /*
471 * fill the matrix with powers of field elements, starting from 0.
472 * The first row is special, cannot be computed with exp. table.
473 */
474 tmp_m[0] = 1;
475 for (col = 1; col < k; col++)
476 tmp_m[col] = 0;
477 for (p = tmp_m + k, row = 0; row < n - 1; row++, p += k) {
478 for (col = 0; col < k; col++)
479 p[col] = gf_exp[modnn(row * col)];
480 }
481
482 /*
483 * quick code to build systematic matrix: invert the top
484 * k*k vandermonde matrix, multiply right the bottom n-k rows
485 * by the inverse, and construct the identity matrix at the top.
486 */
487 invert_vdm(tmp_m, k); /* much faster than invert_mat */
488 matmul(tmp_m + k * k, tmp_m, parms->enc_matrix + k * k, n - k, k, k);
489 /*
490 * the upper matrix is I so do not bother with a slow multiply
491 */
492 memset(parms->enc_matrix, 0, k * k);
493 for (p = parms->enc_matrix, col = 0; col < k; col++, p += k + 1)
494 *p = 1;
495 free(tmp_m);
496 *result = parms;
497 return 0;
498 }
499
500 /**
501 * Compute one encoded slice of the given input.
502 *
503 * \param parms The fec parameters returned earlier by fec_new().
504 * \param src The \a k data slices to encode.
505 * \param dst Result pointer.
506 * \param idx The index of the slice to compute.
507 * \param sz The size of the input data packets.
508 *
509 * Encode the \a k slices of size \a sz given by \a src and store the output
510 * slice number \a idx in \a dst.
511 */
512 void fec_encode(struct fec_parms *parms, const unsigned char * const *src,
513 unsigned char *dst, int idx, int sz)
514 {
515 int i, k = parms->k;
516 unsigned char *p;
517
518 assert(idx <= parms->n);
519
520 if (idx < k) {
521 memcpy(dst, src[idx], sz);
522 return;
523 }
524 p = &(parms->enc_matrix[idx * k]);
525 memset(dst, 0, sz);
526 for (i = 0; i < k; i++)
527 addmul(dst, src[i], p[i], sz);
528 }
529
530 /* Move src packets in their position. */
531 static int shuffle(unsigned char **data, int *idx, int k)
532 {
533 int i;
534
535 for (i = 0; i < k;) {
536 if (idx[i] >= k || idx[i] == i)
537 i++;
538 else { /* put index and data at the right position */
539 int c = idx[i];
540
541 if (idx[c] == c) /* conflict */
542 return -E_FEC_BAD_IDX;
543 FEC_SWAP(idx[i], idx[c]);
544 FEC_SWAP(data[i], data[c]);
545 }
546 }
547 return 0;
548 }
549
550 /*
551 * Construct the decoding matrix given the indices. The encoding matrix must
552 * already be allocated.
553 */
554 static int build_decode_matrix(struct fec_parms *parms, int *idx,
555 unsigned char **result)
556 {
557 int ret = -E_FEC_BAD_IDX, i, k = parms->k;
558 unsigned char *p, *matrix = alloc_matrix(k, k);
559
560 for (i = 0, p = matrix; i < k; i++, p += k) {
561 if (idx[i] >= parms->n) /* invalid index */
562 goto err;
563 if (idx[i] < k) {
564 memset(p, 0, k);
565 p[i] = 1;
566 } else
567 memcpy(p, &(parms->enc_matrix[idx[i] * k]), k);
568 }
569 ret = invert_mat(matrix, k);
570 if (ret < 0)
571 goto err;
572 *result = matrix;
573 return 0;
574 err:
575 free(matrix);
576 *result = NULL;
577 return ret;
578 }
579
580 /**
581 * Decode one slice from the group of received slices.
582 *
583 * \param parms Pointer to fec params structure.
584 * \param data Pointers to received packets.
585 * \param idx Pointer to packet indices (gets modified).
586 * \param sz Size of each packet.
587 *
588 * \return Zero on success, -1 on errors.
589 *
590 * The \a data vector of received slices and the indices of slices are used to
591 * produce the correct output slice. The data slices are modified in-place.
592 */
593 int fec_decode(struct fec_parms *parms, unsigned char **data, int *idx,
594 int sz)
595 {
596 unsigned char *m_dec, **slice;
597 int ret, row, col, k = parms->k;
598
599 ret = shuffle(data, idx, k);
600 if (ret < 0)
601 return ret;
602 ret = build_decode_matrix(parms, idx, &m_dec);
603 if (ret < 0)
604 return ret;
605 /* do the actual decoding */
606 slice = para_malloc(k * sizeof(unsigned char *));
607 for (row = 0; row < k; row++) {
608 if (idx[row] >= k) {
609 slice[row] = para_calloc(sz);
610 for (col = 0; col < k; col++)
611 addmul(slice[row], data[col],
612 m_dec[row * k + col], sz);
613 }
614 }
615 /* move slices to their final destination */
616 for (row = 0; row < k; row++) {
617 if (idx[row] >= k) {
618 memcpy(data[row], slice[row], sz);
619 free(slice[row]);
620 }
621 }
622 free(slice);
623 free(m_dec);
624 return 0;
625 }