xref: /isa-l/erasure_code/erasure_code_test.c (revision 300260a4d902423a8a69f0f7d74e6abaa33ded27)
100c1efc1SGreg Tucker /**********************************************************************
200c1efc1SGreg Tucker   Copyright(c) 2011-2015 Intel Corporation All rights reserved.
300c1efc1SGreg Tucker 
400c1efc1SGreg Tucker   Redistribution and use in source and binary forms, with or without
500c1efc1SGreg Tucker   modification, are permitted provided that the following conditions
600c1efc1SGreg Tucker   are met:
700c1efc1SGreg Tucker     * Redistributions of source code must retain the above copyright
800c1efc1SGreg Tucker       notice, this list of conditions and the following disclaimer.
900c1efc1SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
1000c1efc1SGreg Tucker       notice, this list of conditions and the following disclaimer in
1100c1efc1SGreg Tucker       the documentation and/or other materials provided with the
1200c1efc1SGreg Tucker       distribution.
1300c1efc1SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
1400c1efc1SGreg Tucker       contributors may be used to endorse or promote products derived
1500c1efc1SGreg Tucker       from this software without specific prior written permission.
1600c1efc1SGreg Tucker 
1700c1efc1SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1800c1efc1SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1900c1efc1SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2000c1efc1SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2100c1efc1SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2200c1efc1SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2300c1efc1SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2400c1efc1SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2500c1efc1SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2600c1efc1SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2700c1efc1SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2800c1efc1SGreg Tucker **********************************************************************/
2900c1efc1SGreg Tucker 
3000c1efc1SGreg Tucker #include <stdio.h>
3100c1efc1SGreg Tucker #include <stdlib.h>
3200c1efc1SGreg Tucker #include <string.h> // for memset, memcmp
33402bd4f7STomasz Kantecki #include <assert.h>
3400c1efc1SGreg Tucker #include "erasure_code.h"
35112dd72cSGreg Tucker #include "test.h"
3600c1efc1SGreg Tucker 
3700c1efc1SGreg Tucker #define TEST_LEN  8192
3800c1efc1SGreg Tucker #define TEST_SIZE (TEST_LEN / 2)
3900c1efc1SGreg Tucker 
4000c1efc1SGreg Tucker #ifndef TEST_SOURCES
4100c1efc1SGreg Tucker #define TEST_SOURCES 127
4200c1efc1SGreg Tucker #endif
4300c1efc1SGreg Tucker #ifndef RANDOMS
4400c1efc1SGreg Tucker #define RANDOMS 200
4500c1efc1SGreg Tucker #endif
4600c1efc1SGreg Tucker 
4700c1efc1SGreg Tucker #define MMAX TEST_SOURCES
4800c1efc1SGreg Tucker #define KMAX TEST_SOURCES
4900c1efc1SGreg Tucker 
5000c1efc1SGreg Tucker #define EFENCE_TEST_MIN_SIZE 16
514f2d148aSRoy Oursler #define EFENCE_TEST_MAX_SIZE EFENCE_TEST_MIN_SIZE + 0x100
5200c1efc1SGreg Tucker 
5300c1efc1SGreg Tucker #ifdef EC_ALIGNED_ADDR
5400c1efc1SGreg Tucker // Define power of 2 range to check ptr, len alignment
5500c1efc1SGreg Tucker #define PTR_ALIGN_CHK_B 0
5600c1efc1SGreg Tucker #define LEN_ALIGN_CHK_B 0 // 0 for aligned only
5700c1efc1SGreg Tucker #else
5800c1efc1SGreg Tucker // Define power of 2 range to check ptr, len alignment
5900c1efc1SGreg Tucker #define PTR_ALIGN_CHK_B 32
6000c1efc1SGreg Tucker #define LEN_ALIGN_CHK_B 32 // 0 for aligned only
6100c1efc1SGreg Tucker #endif
6200c1efc1SGreg Tucker 
6300c1efc1SGreg Tucker #ifndef TEST_SEED
6400c1efc1SGreg Tucker #define TEST_SEED 11
6500c1efc1SGreg Tucker #endif
6600c1efc1SGreg Tucker 
6700c1efc1SGreg Tucker typedef unsigned char u8;
6800c1efc1SGreg Tucker 
69*300260a4SMarcel Cornu void
dump(unsigned char * buf,int len)70*300260a4SMarcel Cornu dump(unsigned char *buf, int len)
7100c1efc1SGreg Tucker {
7200c1efc1SGreg Tucker         int i;
7300c1efc1SGreg Tucker         for (i = 0; i < len;) {
7400c1efc1SGreg Tucker                 printf(" %2x", 0xff & buf[i++]);
7500c1efc1SGreg Tucker                 if (i % 32 == 0)
7600c1efc1SGreg Tucker                         printf("\n");
7700c1efc1SGreg Tucker         }
7800c1efc1SGreg Tucker         printf("\n");
7900c1efc1SGreg Tucker }
8000c1efc1SGreg Tucker 
81*300260a4SMarcel Cornu void
dump_matrix(unsigned char ** s,int k,int m)82*300260a4SMarcel Cornu dump_matrix(unsigned char **s, int k, int m)
8300c1efc1SGreg Tucker {
8400c1efc1SGreg Tucker         int i, j;
8500c1efc1SGreg Tucker         for (i = 0; i < k; i++) {
8600c1efc1SGreg Tucker                 for (j = 0; j < m; j++) {
8700c1efc1SGreg Tucker                         printf(" %2x", s[i][j]);
8800c1efc1SGreg Tucker                 }
8900c1efc1SGreg Tucker                 printf("\n");
9000c1efc1SGreg Tucker         }
9100c1efc1SGreg Tucker         printf("\n");
9200c1efc1SGreg Tucker }
9300c1efc1SGreg Tucker 
94*300260a4SMarcel Cornu void
dump_u8xu8(unsigned char * s,int k,int m)95*300260a4SMarcel Cornu dump_u8xu8(unsigned char *s, int k, int m)
9600c1efc1SGreg Tucker {
9700c1efc1SGreg Tucker         int i, j;
9800c1efc1SGreg Tucker         for (i = 0; i < k; i++) {
9900c1efc1SGreg Tucker                 for (j = 0; j < m; j++) {
10000c1efc1SGreg Tucker                         printf(" %2x", 0xff & s[j + (i * m)]);
10100c1efc1SGreg Tucker                 }
10200c1efc1SGreg Tucker                 printf("\n");
10300c1efc1SGreg Tucker         }
10400c1efc1SGreg Tucker         printf("\n");
10500c1efc1SGreg Tucker }
10600c1efc1SGreg Tucker 
10700c1efc1SGreg Tucker // Generate Random errors
108*300260a4SMarcel Cornu static void
gen_err_list(unsigned char * src_err_list,unsigned char * src_in_err,int * pnerrs,int * pnsrcerrs,int k,int m)109*300260a4SMarcel Cornu gen_err_list(unsigned char *src_err_list, unsigned char *src_in_err, int *pnerrs, int *pnsrcerrs,
110*300260a4SMarcel Cornu              int k, int m)
11100c1efc1SGreg Tucker {
11200c1efc1SGreg Tucker         int i, err;
11300c1efc1SGreg Tucker         int nerrs = 0, nsrcerrs = 0;
11400c1efc1SGreg Tucker 
11500c1efc1SGreg Tucker         for (i = 0, nerrs = 0, nsrcerrs = 0; i < m && nerrs < m - k; i++) {
11600c1efc1SGreg Tucker                 err = 1 & rand();
11700c1efc1SGreg Tucker                 src_in_err[i] = err;
11800c1efc1SGreg Tucker                 if (err) {
11900c1efc1SGreg Tucker                         src_err_list[nerrs++] = i;
12000c1efc1SGreg Tucker                         if (i < k) {
12100c1efc1SGreg Tucker                                 nsrcerrs++;
12200c1efc1SGreg Tucker                         }
12300c1efc1SGreg Tucker                 }
12400c1efc1SGreg Tucker         }
12500c1efc1SGreg Tucker         if (nerrs == 0) { // should have at least one error
126*300260a4SMarcel Cornu                 while ((err = (rand() % KMAX)) >= m)
127*300260a4SMarcel Cornu                         ;
12800c1efc1SGreg Tucker                 src_err_list[nerrs++] = err;
12900c1efc1SGreg Tucker                 src_in_err[err] = 1;
13000c1efc1SGreg Tucker                 if (err < k)
13100c1efc1SGreg Tucker                         nsrcerrs = 1;
13200c1efc1SGreg Tucker         }
13300c1efc1SGreg Tucker         *pnerrs = nerrs;
13400c1efc1SGreg Tucker         *pnsrcerrs = nsrcerrs;
13500c1efc1SGreg Tucker         return;
13600c1efc1SGreg Tucker }
13700c1efc1SGreg Tucker 
13800c1efc1SGreg Tucker #define NO_INVERT_MATRIX -2
13900c1efc1SGreg Tucker // Generate decode matrix from encode matrix
140*300260a4SMarcel Cornu static int
gf_gen_decode_matrix(unsigned char * encode_matrix,unsigned char * decode_matrix,unsigned char * invert_matrix,unsigned int * decode_index,unsigned char * src_err_list,unsigned char * src_in_err,int nerrs,int nsrcerrs,int k,int m)141*300260a4SMarcel Cornu gf_gen_decode_matrix(unsigned char *encode_matrix, unsigned char *decode_matrix,
142*300260a4SMarcel Cornu                      unsigned char *invert_matrix, unsigned int *decode_index,
143*300260a4SMarcel Cornu                      unsigned char *src_err_list, unsigned char *src_in_err, int nerrs,
144*300260a4SMarcel Cornu                      int nsrcerrs, int k, int m)
14500c1efc1SGreg Tucker {
14600c1efc1SGreg Tucker         int i, j, p;
14700c1efc1SGreg Tucker         int r;
14800c1efc1SGreg Tucker         unsigned char *backup, *b, s;
14900c1efc1SGreg Tucker         int incr = 0;
15000c1efc1SGreg Tucker 
15100c1efc1SGreg Tucker         b = malloc(MMAX * KMAX);
15200c1efc1SGreg Tucker         backup = malloc(MMAX * KMAX);
15300c1efc1SGreg Tucker 
15400c1efc1SGreg Tucker         if (b == NULL || backup == NULL) {
15500c1efc1SGreg Tucker                 printf("Test failure! Error with malloc\n");
15600c1efc1SGreg Tucker                 free(b);
15700c1efc1SGreg Tucker                 free(backup);
15800c1efc1SGreg Tucker                 return -1;
15900c1efc1SGreg Tucker         }
16000c1efc1SGreg Tucker         // Construct matrix b by removing error rows
16100c1efc1SGreg Tucker         for (i = 0, r = 0; i < k; i++, r++) {
16200c1efc1SGreg Tucker                 while (src_in_err[r])
16300c1efc1SGreg Tucker                         r++;
16400c1efc1SGreg Tucker                 for (j = 0; j < k; j++) {
16500c1efc1SGreg Tucker                         b[k * i + j] = encode_matrix[k * r + j];
16600c1efc1SGreg Tucker                         backup[k * i + j] = encode_matrix[k * r + j];
16700c1efc1SGreg Tucker                 }
16800c1efc1SGreg Tucker                 decode_index[i] = r;
16900c1efc1SGreg Tucker         }
17000c1efc1SGreg Tucker         incr = 0;
17100c1efc1SGreg Tucker         while (gf_invert_matrix(b, invert_matrix, k) < 0) {
17200c1efc1SGreg Tucker                 if (nerrs == (m - k)) {
17300c1efc1SGreg Tucker                         free(b);
17400c1efc1SGreg Tucker                         free(backup);
17500c1efc1SGreg Tucker                         printf("BAD MATRIX\n");
17600c1efc1SGreg Tucker                         return NO_INVERT_MATRIX;
17700c1efc1SGreg Tucker                 }
17800c1efc1SGreg Tucker                 incr++;
17900c1efc1SGreg Tucker                 memcpy(b, backup, MMAX * KMAX);
18000c1efc1SGreg Tucker                 for (i = nsrcerrs; i < nerrs - nsrcerrs; i++) {
18100c1efc1SGreg Tucker                         if (src_err_list[i] == (decode_index[k - 1] + incr)) {
18200c1efc1SGreg Tucker                                 // skip the erased parity line
18300c1efc1SGreg Tucker                                 incr++;
18400c1efc1SGreg Tucker                                 continue;
18500c1efc1SGreg Tucker                         }
18600c1efc1SGreg Tucker                 }
18700c1efc1SGreg Tucker                 if (decode_index[k - 1] + incr >= m) {
18800c1efc1SGreg Tucker                         free(b);
18900c1efc1SGreg Tucker                         free(backup);
19000c1efc1SGreg Tucker                         printf("BAD MATRIX\n");
19100c1efc1SGreg Tucker                         return NO_INVERT_MATRIX;
19200c1efc1SGreg Tucker                 }
19300c1efc1SGreg Tucker                 decode_index[k - 1] += incr;
19400c1efc1SGreg Tucker                 for (j = 0; j < k; j++)
19500c1efc1SGreg Tucker                         b[k * (k - 1) + j] = encode_matrix[k * decode_index[k - 1] + j];
19600c1efc1SGreg Tucker         };
19700c1efc1SGreg Tucker 
19800c1efc1SGreg Tucker         for (i = 0; i < nsrcerrs; i++) {
19900c1efc1SGreg Tucker                 for (j = 0; j < k; j++) {
20000c1efc1SGreg Tucker                         decode_matrix[k * i + j] = invert_matrix[k * src_err_list[i] + j];
20100c1efc1SGreg Tucker                 }
20200c1efc1SGreg Tucker         }
20300c1efc1SGreg Tucker         /* src_err_list from encode_matrix * invert of b for parity decoding */
20400c1efc1SGreg Tucker         for (p = nsrcerrs; p < nerrs; p++) {
20500c1efc1SGreg Tucker                 for (i = 0; i < k; i++) {
20600c1efc1SGreg Tucker                         s = 0;
20700c1efc1SGreg Tucker                         for (j = 0; j < k; j++)
20800c1efc1SGreg Tucker                                 s ^= gf_mul(invert_matrix[j * k + i],
20900c1efc1SGreg Tucker                                             encode_matrix[k * src_err_list[p] + j]);
21000c1efc1SGreg Tucker 
21100c1efc1SGreg Tucker                         decode_matrix[k * p + i] = s;
21200c1efc1SGreg Tucker                 }
21300c1efc1SGreg Tucker         }
21400c1efc1SGreg Tucker         free(b);
21500c1efc1SGreg Tucker         free(backup);
21600c1efc1SGreg Tucker         return 0;
21700c1efc1SGreg Tucker }
21800c1efc1SGreg Tucker 
219*300260a4SMarcel Cornu int
main(int argc,char * argv[])220*300260a4SMarcel Cornu main(int argc, char *argv[])
22100c1efc1SGreg Tucker {
222a3e26043SPablo de Lara         int re = -1;
22300c1efc1SGreg Tucker         int i, j, p, rtest, m, k;
22400c1efc1SGreg Tucker         int nerrs, nsrcerrs;
22500c1efc1SGreg Tucker         void *buf;
22600c1efc1SGreg Tucker         unsigned int decode_index[MMAX];
227a3e26043SPablo de Lara         unsigned char *temp_buffs[TEST_SOURCES] = { NULL }, *buffs[TEST_SOURCES] = { NULL };
228*300260a4SMarcel Cornu         unsigned char *encode_matrix = NULL, *decode_matrix = NULL, *invert_matrix = NULL,
229*300260a4SMarcel Cornu                       *g_tbls = NULL;
23000c1efc1SGreg Tucker         unsigned char src_in_err[TEST_SOURCES], src_err_list[TEST_SOURCES];
23100c1efc1SGreg Tucker         unsigned char *recov[TEST_SOURCES];
23200c1efc1SGreg Tucker 
23300c1efc1SGreg Tucker         int rows, align, size;
23400c1efc1SGreg Tucker         unsigned char *efence_buffs[TEST_SOURCES];
23500c1efc1SGreg Tucker         unsigned int offset;
23600c1efc1SGreg Tucker         u8 *ubuffs[TEST_SOURCES];
23700c1efc1SGreg Tucker         u8 *temp_ubuffs[TEST_SOURCES];
23800c1efc1SGreg Tucker 
23900c1efc1SGreg Tucker         printf("erasure_code_test: %dx%d ", TEST_SOURCES, TEST_LEN);
24000c1efc1SGreg Tucker         srand(TEST_SEED);
24100c1efc1SGreg Tucker 
24200c1efc1SGreg Tucker         // Allocate the arrays
24300c1efc1SGreg Tucker         for (i = 0; i < TEST_SOURCES; i++) {
24400c1efc1SGreg Tucker                 if (posix_memalign(&buf, 64, TEST_LEN)) {
24500c1efc1SGreg Tucker                         printf("alloc error: Fail");
246a3e26043SPablo de Lara                         goto exit;
24700c1efc1SGreg Tucker                 }
24800c1efc1SGreg Tucker                 buffs[i] = buf;
24900c1efc1SGreg Tucker         }
25000c1efc1SGreg Tucker 
25100c1efc1SGreg Tucker         for (i = 0; i < TEST_SOURCES; i++) {
25200c1efc1SGreg Tucker                 if (posix_memalign(&buf, 64, TEST_LEN)) {
25300c1efc1SGreg Tucker                         printf("alloc error: Fail");
254a3e26043SPablo de Lara                         goto exit;
25500c1efc1SGreg Tucker                 }
25600c1efc1SGreg Tucker                 temp_buffs[i] = buf;
25700c1efc1SGreg Tucker         }
25800c1efc1SGreg Tucker 
25900c1efc1SGreg Tucker         // Test erasure code by encode and recovery
26000c1efc1SGreg Tucker 
26100c1efc1SGreg Tucker         encode_matrix = malloc(MMAX * KMAX);
26200c1efc1SGreg Tucker         decode_matrix = malloc(MMAX * KMAX);
26300c1efc1SGreg Tucker         invert_matrix = malloc(MMAX * KMAX);
26400c1efc1SGreg Tucker         g_tbls = malloc(KMAX * TEST_SOURCES * 32);
265*300260a4SMarcel Cornu         if (encode_matrix == NULL || decode_matrix == NULL || invert_matrix == NULL ||
266*300260a4SMarcel Cornu             g_tbls == NULL) {
26700c1efc1SGreg Tucker                 printf("Test failure! Error with malloc\n");
268a3e26043SPablo de Lara                 goto exit;
26900c1efc1SGreg Tucker         }
27000c1efc1SGreg Tucker         // Pick a first test
27100c1efc1SGreg Tucker         m = 9;
27200c1efc1SGreg Tucker         k = 5;
273402bd4f7STomasz Kantecki         assert((m <= MMAX) && (k <= KMAX));
27400c1efc1SGreg Tucker 
27500c1efc1SGreg Tucker         // Make random data
27600c1efc1SGreg Tucker         for (i = 0; i < k; i++)
27700c1efc1SGreg Tucker                 for (j = 0; j < TEST_LEN; j++)
27800c1efc1SGreg Tucker                         buffs[i][j] = rand();
27900c1efc1SGreg Tucker 
28000c1efc1SGreg Tucker         // Generate encode matrix encode_matrix
28100c1efc1SGreg Tucker         // The matrix generated by gf_gen_rs_matrix
28200c1efc1SGreg Tucker         // is not always invertable.
28300c1efc1SGreg Tucker         gf_gen_rs_matrix(encode_matrix, m, k);
28400c1efc1SGreg Tucker 
28500c1efc1SGreg Tucker         // Generate g_tbls from encode matrix encode_matrix
28600c1efc1SGreg Tucker         ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
28700c1efc1SGreg Tucker 
28800c1efc1SGreg Tucker         // Perform matrix dot_prod for EC encoding
28900c1efc1SGreg Tucker         // using g_tbls from encode matrix encode_matrix
29000c1efc1SGreg Tucker         ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]);
29100c1efc1SGreg Tucker 
29200c1efc1SGreg Tucker         // Choose random buffers to be in erasure
29300c1efc1SGreg Tucker         memset(src_in_err, 0, TEST_SOURCES);
29400c1efc1SGreg Tucker         gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
29500c1efc1SGreg Tucker 
29600c1efc1SGreg Tucker         // Generate decode matrix
297*300260a4SMarcel Cornu         re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index,
298*300260a4SMarcel Cornu                                   src_err_list, src_in_err, nerrs, nsrcerrs, k, m);
29900c1efc1SGreg Tucker         if (re != 0) {
30000c1efc1SGreg Tucker                 printf("Fail to gf_gen_decode_matrix\n");
301a3e26043SPablo de Lara                 goto exit;
30200c1efc1SGreg Tucker         }
30300c1efc1SGreg Tucker         // Pack recovery array as list of valid sources
30400c1efc1SGreg Tucker         // Its order must be the same as the order
30500c1efc1SGreg Tucker         // to generate matrix b in gf_gen_decode_matrix
30600c1efc1SGreg Tucker         for (i = 0; i < k; i++) {
30700c1efc1SGreg Tucker                 recov[i] = buffs[decode_index[i]];
30800c1efc1SGreg Tucker         }
30900c1efc1SGreg Tucker 
31000c1efc1SGreg Tucker         // Recover data
31100c1efc1SGreg Tucker         ec_init_tables(k, nerrs, decode_matrix, g_tbls);
31200c1efc1SGreg Tucker         ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
31300c1efc1SGreg Tucker         for (i = 0; i < nerrs; i++) {
31400c1efc1SGreg Tucker 
31500c1efc1SGreg Tucker                 if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) {
31600c1efc1SGreg Tucker                         printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs);
31700c1efc1SGreg Tucker                         printf(" - erase list = ");
31800c1efc1SGreg Tucker                         for (j = 0; j < nerrs; j++)
31900c1efc1SGreg Tucker                                 printf(" %d", src_err_list[j]);
32000c1efc1SGreg Tucker                         printf(" - Index = ");
32100c1efc1SGreg Tucker                         for (p = 0; p < k; p++)
32200c1efc1SGreg Tucker                                 printf(" %d", decode_index[p]);
32300c1efc1SGreg Tucker                         printf("\nencode_matrix:\n");
32400c1efc1SGreg Tucker                         dump_u8xu8((u8 *) encode_matrix, m, k);
32500c1efc1SGreg Tucker                         printf("inv b:\n");
32600c1efc1SGreg Tucker                         dump_u8xu8((u8 *) invert_matrix, k, k);
32700c1efc1SGreg Tucker                         printf("\ndecode_matrix:\n");
32800c1efc1SGreg Tucker                         dump_u8xu8((u8 *) decode_matrix, m, k);
32900c1efc1SGreg Tucker                         printf("recov %d:", src_err_list[i]);
33000c1efc1SGreg Tucker                         dump(temp_buffs[k + i], 25);
33100c1efc1SGreg Tucker                         printf("orig   :");
33200c1efc1SGreg Tucker                         dump(buffs[src_err_list[i]], 25);
333a3e26043SPablo de Lara                         re = -1;
334a3e26043SPablo de Lara                         goto exit;
33500c1efc1SGreg Tucker                 }
33600c1efc1SGreg Tucker         }
33700c1efc1SGreg Tucker 
33800c1efc1SGreg Tucker         // Pick a first test
33900c1efc1SGreg Tucker         m = 9;
34000c1efc1SGreg Tucker         k = 5;
341a3e26043SPablo de Lara         if (m > MMAX || k > KMAX) {
342a3e26043SPablo de Lara                 re = -1;
343a3e26043SPablo de Lara                 goto exit;
344a3e26043SPablo de Lara         }
34500c1efc1SGreg Tucker 
34600c1efc1SGreg Tucker         // Make random data
34700c1efc1SGreg Tucker         for (i = 0; i < k; i++)
34800c1efc1SGreg Tucker                 for (j = 0; j < TEST_LEN; j++)
34900c1efc1SGreg Tucker                         buffs[i][j] = rand();
35000c1efc1SGreg Tucker 
35100c1efc1SGreg Tucker         // The matrix generated by gf_gen_cauchy1_matrix
35200c1efc1SGreg Tucker         // is always invertable.
35300c1efc1SGreg Tucker         gf_gen_cauchy1_matrix(encode_matrix, m, k);
35400c1efc1SGreg Tucker 
35500c1efc1SGreg Tucker         // Generate g_tbls from encode matrix encode_matrix
35600c1efc1SGreg Tucker         ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
35700c1efc1SGreg Tucker 
35800c1efc1SGreg Tucker         // Perform matrix dot_prod for EC encoding
35900c1efc1SGreg Tucker         // using g_tbls from encode matrix encode_matrix
36000c1efc1SGreg Tucker         ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]);
36100c1efc1SGreg Tucker 
36200c1efc1SGreg Tucker         // Choose random buffers to be in erasure
36300c1efc1SGreg Tucker         memset(src_in_err, 0, TEST_SOURCES);
36400c1efc1SGreg Tucker         gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
36500c1efc1SGreg Tucker 
36600c1efc1SGreg Tucker         // Generate decode matrix
367*300260a4SMarcel Cornu         re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index,
368*300260a4SMarcel Cornu                                   src_err_list, src_in_err, nerrs, nsrcerrs, k, m);
36900c1efc1SGreg Tucker         if (re != 0) {
37000c1efc1SGreg Tucker                 printf("Fail to gf_gen_decode_matrix\n");
371a3e26043SPablo de Lara                 goto exit;
37200c1efc1SGreg Tucker         }
37300c1efc1SGreg Tucker         // Pack recovery array as list of valid sources
37400c1efc1SGreg Tucker         // Its order must be the same as the order
37500c1efc1SGreg Tucker         // to generate matrix b in gf_gen_decode_matrix
37600c1efc1SGreg Tucker         for (i = 0; i < k; i++) {
37700c1efc1SGreg Tucker                 recov[i] = buffs[decode_index[i]];
37800c1efc1SGreg Tucker         }
37900c1efc1SGreg Tucker 
38000c1efc1SGreg Tucker         // Recover data
38100c1efc1SGreg Tucker         ec_init_tables(k, nerrs, decode_matrix, g_tbls);
38200c1efc1SGreg Tucker         ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
38300c1efc1SGreg Tucker         for (i = 0; i < nerrs; i++) {
38400c1efc1SGreg Tucker 
38500c1efc1SGreg Tucker                 if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) {
38600c1efc1SGreg Tucker                         printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs);
38700c1efc1SGreg Tucker                         printf(" - erase list = ");
38800c1efc1SGreg Tucker                         for (j = 0; j < nerrs; j++)
38900c1efc1SGreg Tucker                                 printf(" %d", src_err_list[j]);
39000c1efc1SGreg Tucker                         printf(" - Index = ");
39100c1efc1SGreg Tucker                         for (p = 0; p < k; p++)
39200c1efc1SGreg Tucker                                 printf(" %d", decode_index[p]);
39300c1efc1SGreg Tucker                         printf("\nencode_matrix:\n");
39400c1efc1SGreg Tucker                         dump_u8xu8((u8 *) encode_matrix, m, k);
39500c1efc1SGreg Tucker                         printf("inv b:\n");
39600c1efc1SGreg Tucker                         dump_u8xu8((u8 *) invert_matrix, k, k);
39700c1efc1SGreg Tucker                         printf("\ndecode_matrix:\n");
39800c1efc1SGreg Tucker                         dump_u8xu8((u8 *) decode_matrix, m, k);
39900c1efc1SGreg Tucker                         printf("recov %d:", src_err_list[i]);
40000c1efc1SGreg Tucker                         dump(temp_buffs[k + i], 25);
40100c1efc1SGreg Tucker                         printf("orig   :");
40200c1efc1SGreg Tucker                         dump(buffs[src_err_list[i]], 25);
403a3e26043SPablo de Lara                         re = -1;
404a3e26043SPablo de Lara                         goto exit;
40500c1efc1SGreg Tucker                 }
40600c1efc1SGreg Tucker         }
40700c1efc1SGreg Tucker 
40800c1efc1SGreg Tucker         // Do more random tests
40900c1efc1SGreg Tucker         for (rtest = 0; rtest < RANDOMS; rtest++) {
410*300260a4SMarcel Cornu                 while ((m = (rand() % MMAX)) < 2)
411*300260a4SMarcel Cornu                         ;
412*300260a4SMarcel Cornu                 while ((k = (rand() % KMAX)) >= m || k < 1)
413*300260a4SMarcel Cornu                         ;
41400c1efc1SGreg Tucker 
41500c1efc1SGreg Tucker                 if (m > MMAX || k > KMAX)
41600c1efc1SGreg Tucker                         continue;
41700c1efc1SGreg Tucker 
41800c1efc1SGreg Tucker                 // Make random data
41900c1efc1SGreg Tucker                 for (i = 0; i < k; i++)
42000c1efc1SGreg Tucker                         for (j = 0; j < TEST_LEN; j++)
42100c1efc1SGreg Tucker                                 buffs[i][j] = rand();
42200c1efc1SGreg Tucker 
42300c1efc1SGreg Tucker                 // The matrix generated by gf_gen_cauchy1_matrix
42400c1efc1SGreg Tucker                 // is always invertable.
42500c1efc1SGreg Tucker                 gf_gen_cauchy1_matrix(encode_matrix, m, k);
42600c1efc1SGreg Tucker 
42700c1efc1SGreg Tucker                 // Make parity vects
42800c1efc1SGreg Tucker                 // Generate g_tbls from encode matrix a
42900c1efc1SGreg Tucker                 ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
43000c1efc1SGreg Tucker                 // Perform matrix dot_prod for EC encoding
43100c1efc1SGreg Tucker                 // using g_tbls from encode matrix a
43200c1efc1SGreg Tucker                 ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]);
43300c1efc1SGreg Tucker 
43400c1efc1SGreg Tucker                 // Random errors
43500c1efc1SGreg Tucker                 memset(src_in_err, 0, TEST_SOURCES);
43600c1efc1SGreg Tucker                 gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
43700c1efc1SGreg Tucker 
43800c1efc1SGreg Tucker                 // Generate decode matrix
439*300260a4SMarcel Cornu                 re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index,
440*300260a4SMarcel Cornu                                           src_err_list, src_in_err, nerrs, nsrcerrs, k, m);
44100c1efc1SGreg Tucker                 if (re != 0) {
44200c1efc1SGreg Tucker                         printf("Fail to gf_gen_decode_matrix\n");
443a3e26043SPablo de Lara                         goto exit;
44400c1efc1SGreg Tucker                 }
44500c1efc1SGreg Tucker                 // Pack recovery array as list of valid sources
44600c1efc1SGreg Tucker                 // Its order must be the same as the order
44700c1efc1SGreg Tucker                 // to generate matrix b in gf_gen_decode_matrix
44800c1efc1SGreg Tucker                 for (i = 0; i < k; i++) {
44900c1efc1SGreg Tucker                         recov[i] = buffs[decode_index[i]];
45000c1efc1SGreg Tucker                 }
45100c1efc1SGreg Tucker 
45200c1efc1SGreg Tucker                 // Recover data
45300c1efc1SGreg Tucker                 ec_init_tables(k, nerrs, decode_matrix, g_tbls);
45400c1efc1SGreg Tucker                 ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
45500c1efc1SGreg Tucker 
45600c1efc1SGreg Tucker                 for (i = 0; i < nerrs; i++) {
45700c1efc1SGreg Tucker 
45800c1efc1SGreg Tucker                         if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) {
45900c1efc1SGreg Tucker                                 printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs);
46000c1efc1SGreg Tucker                                 printf(" - erase list = ");
46100c1efc1SGreg Tucker                                 for (j = 0; j < nerrs; j++)
46200c1efc1SGreg Tucker                                         printf(" %d", src_err_list[j]);
46300c1efc1SGreg Tucker                                 printf(" - Index = ");
46400c1efc1SGreg Tucker                                 for (p = 0; p < k; p++)
46500c1efc1SGreg Tucker                                         printf(" %d", decode_index[p]);
46600c1efc1SGreg Tucker                                 printf("\nencode_matrix:\n");
46700c1efc1SGreg Tucker                                 dump_u8xu8((u8 *) encode_matrix, m, k);
46800c1efc1SGreg Tucker                                 printf("inv b:\n");
46900c1efc1SGreg Tucker                                 dump_u8xu8((u8 *) invert_matrix, k, k);
47000c1efc1SGreg Tucker                                 printf("\ndecode_matrix:\n");
47100c1efc1SGreg Tucker                                 dump_u8xu8((u8 *) decode_matrix, m, k);
47200c1efc1SGreg Tucker                                 printf("orig data:\n");
47300c1efc1SGreg Tucker                                 dump_matrix(buffs, m, 25);
47400c1efc1SGreg Tucker                                 printf("orig   :");
47500c1efc1SGreg Tucker                                 dump(buffs[src_err_list[i]], 25);
47600c1efc1SGreg Tucker                                 printf("recov %d:", src_err_list[i]);
47700c1efc1SGreg Tucker                                 dump(temp_buffs[k + i], 25);
478a3e26043SPablo de Lara                                 re = -1;
479a3e26043SPablo de Lara                                 goto exit;
48000c1efc1SGreg Tucker                         }
48100c1efc1SGreg Tucker                 }
4822ca781dfSPablo de Lara #ifdef TEST_VERBOSE
48300c1efc1SGreg Tucker                 putchar('.');
4842ca781dfSPablo de Lara #endif
48500c1efc1SGreg Tucker         }
48600c1efc1SGreg Tucker 
48700c1efc1SGreg Tucker         // Run tests at end of buffer for Electric Fence
48800c1efc1SGreg Tucker         k = 16;
48900c1efc1SGreg Tucker         align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
490a3e26043SPablo de Lara         if (k > KMAX) {
491a3e26043SPablo de Lara                 re = -1;
492a3e26043SPablo de Lara                 goto exit;
493a3e26043SPablo de Lara         }
49400c1efc1SGreg Tucker 
49500c1efc1SGreg Tucker         for (rows = 1; rows <= 16; rows++) {
49600c1efc1SGreg Tucker                 m = k + rows;
497a3e26043SPablo de Lara                 if (m > MMAX) {
498a3e26043SPablo de Lara                         re = -1;
499a3e26043SPablo de Lara                         goto exit;
500a3e26043SPablo de Lara                 }
50100c1efc1SGreg Tucker 
50200c1efc1SGreg Tucker                 // Make random data
50300c1efc1SGreg Tucker                 for (i = 0; i < k; i++)
50400c1efc1SGreg Tucker                         for (j = 0; j < TEST_LEN; j++)
50500c1efc1SGreg Tucker                                 buffs[i][j] = rand();
50600c1efc1SGreg Tucker 
5074f2d148aSRoy Oursler                 for (size = EFENCE_TEST_MIN_SIZE; size <= EFENCE_TEST_MAX_SIZE; size += align) {
50800c1efc1SGreg Tucker                         for (i = 0; i < m; i++) { // Line up TEST_SIZE from end
50900c1efc1SGreg Tucker                                 efence_buffs[i] = buffs[i] + TEST_LEN - size;
51000c1efc1SGreg Tucker                         }
51100c1efc1SGreg Tucker 
51200c1efc1SGreg Tucker                         // The matrix generated by gf_gen_cauchy1_matrix
51300c1efc1SGreg Tucker                         // is always invertable.
51400c1efc1SGreg Tucker                         gf_gen_cauchy1_matrix(encode_matrix, m, k);
51500c1efc1SGreg Tucker 
51600c1efc1SGreg Tucker                         // Make parity vects
51700c1efc1SGreg Tucker                         // Generate g_tbls from encode matrix a
51800c1efc1SGreg Tucker                         ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
51900c1efc1SGreg Tucker                         // Perform matrix dot_prod for EC encoding
52000c1efc1SGreg Tucker                         // using g_tbls from encode matrix a
52100c1efc1SGreg Tucker                         ec_encode_data(size, k, m - k, g_tbls, efence_buffs, &efence_buffs[k]);
52200c1efc1SGreg Tucker 
52300c1efc1SGreg Tucker                         // Random errors
52400c1efc1SGreg Tucker                         memset(src_in_err, 0, TEST_SOURCES);
52500c1efc1SGreg Tucker                         gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
52600c1efc1SGreg Tucker 
52700c1efc1SGreg Tucker                         // Generate decode matrix
528*300260a4SMarcel Cornu                         re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix,
529*300260a4SMarcel Cornu                                                   decode_index, src_err_list, src_in_err, nerrs,
530*300260a4SMarcel Cornu                                                   nsrcerrs, k, m);
53100c1efc1SGreg Tucker                         if (re != 0) {
53200c1efc1SGreg Tucker                                 printf("Fail to gf_gen_decode_matrix\n");
533a3e26043SPablo de Lara                                 goto exit;
53400c1efc1SGreg Tucker                         }
53500c1efc1SGreg Tucker                         // Pack recovery array as list of valid sources
53600c1efc1SGreg Tucker                         // Its order must be the same as the order
53700c1efc1SGreg Tucker                         // to generate matrix b in gf_gen_decode_matrix
53800c1efc1SGreg Tucker                         for (i = 0; i < k; i++) {
53900c1efc1SGreg Tucker                                 recov[i] = efence_buffs[decode_index[i]];
54000c1efc1SGreg Tucker                         }
54100c1efc1SGreg Tucker 
54200c1efc1SGreg Tucker                         // Recover data
54300c1efc1SGreg Tucker                         ec_init_tables(k, nerrs, decode_matrix, g_tbls);
54400c1efc1SGreg Tucker                         ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]);
54500c1efc1SGreg Tucker 
54600c1efc1SGreg Tucker                         for (i = 0; i < nerrs; i++) {
54700c1efc1SGreg Tucker 
548*300260a4SMarcel Cornu                                 if (0 != memcmp(temp_buffs[k + i], efence_buffs[src_err_list[i]],
54900c1efc1SGreg Tucker                                                 size)) {
550*300260a4SMarcel Cornu                                         printf("Efence: Fail error recovery (%d, %d, %d)\n", m, k,
551*300260a4SMarcel Cornu                                                nerrs);
55200c1efc1SGreg Tucker 
55300c1efc1SGreg Tucker                                         printf("size = %d\n", size);
55400c1efc1SGreg Tucker 
55500c1efc1SGreg Tucker                                         printf("Test erase list = ");
55600c1efc1SGreg Tucker                                         for (j = 0; j < nerrs; j++)
55700c1efc1SGreg Tucker                                                 printf(" %d", src_err_list[j]);
55800c1efc1SGreg Tucker                                         printf(" - Index = ");
55900c1efc1SGreg Tucker                                         for (p = 0; p < k; p++)
56000c1efc1SGreg Tucker                                                 printf(" %d", decode_index[p]);
56100c1efc1SGreg Tucker                                         printf("\nencode_matrix:\n");
56200c1efc1SGreg Tucker                                         dump_u8xu8((u8 *) encode_matrix, m, k);
56300c1efc1SGreg Tucker                                         printf("inv b:\n");
56400c1efc1SGreg Tucker                                         dump_u8xu8((u8 *) invert_matrix, k, k);
56500c1efc1SGreg Tucker                                         printf("\ndecode_matrix:\n");
56600c1efc1SGreg Tucker                                         dump_u8xu8((u8 *) decode_matrix, m, k);
56700c1efc1SGreg Tucker 
56800c1efc1SGreg Tucker                                         printf("recov %d:", src_err_list[i]);
56900c1efc1SGreg Tucker                                         dump(temp_buffs[k + i], align);
57000c1efc1SGreg Tucker                                         printf("orig   :");
57100c1efc1SGreg Tucker                                         dump(efence_buffs[src_err_list[i]], align);
572a3e26043SPablo de Lara                                         re = -1;
573a3e26043SPablo de Lara                                         goto exit;
57400c1efc1SGreg Tucker                                 }
57500c1efc1SGreg Tucker                         }
57600c1efc1SGreg Tucker                 }
57700c1efc1SGreg Tucker         }
57800c1efc1SGreg Tucker 
57900c1efc1SGreg Tucker         // Test rand ptr alignment if available
58000c1efc1SGreg Tucker 
58100c1efc1SGreg Tucker         for (rtest = 0; rtest < RANDOMS; rtest++) {
582*300260a4SMarcel Cornu                 while ((m = (rand() % MMAX)) < 2)
583*300260a4SMarcel Cornu                         ;
584*300260a4SMarcel Cornu                 while ((k = (rand() % KMAX)) >= m || k < 1)
585*300260a4SMarcel Cornu                         ;
58600c1efc1SGreg Tucker 
58700c1efc1SGreg Tucker                 if (m > MMAX || k > KMAX)
58800c1efc1SGreg Tucker                         continue;
58900c1efc1SGreg Tucker 
59000c1efc1SGreg Tucker                 size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~15;
59100c1efc1SGreg Tucker 
59200c1efc1SGreg Tucker                 offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
59300c1efc1SGreg Tucker                 // Add random offsets
59400c1efc1SGreg Tucker                 for (i = 0; i < m; i++) {
59500c1efc1SGreg Tucker                         memset(buffs[i], 0, TEST_LEN);      // zero pad to check write-over
59600c1efc1SGreg Tucker                         memset(temp_buffs[i], 0, TEST_LEN); // zero pad to check write-over
59700c1efc1SGreg Tucker                         ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
59800c1efc1SGreg Tucker                         temp_ubuffs[i] = temp_buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
59900c1efc1SGreg Tucker                 }
60000c1efc1SGreg Tucker 
60100c1efc1SGreg Tucker                 for (i = 0; i < k; i++)
60200c1efc1SGreg Tucker                         for (j = 0; j < size; j++)
60300c1efc1SGreg Tucker                                 ubuffs[i][j] = rand();
60400c1efc1SGreg Tucker 
60500c1efc1SGreg Tucker                 // The matrix generated by gf_gen_cauchy1_matrix
60600c1efc1SGreg Tucker                 // is always invertable.
60700c1efc1SGreg Tucker                 gf_gen_cauchy1_matrix(encode_matrix, m, k);
60800c1efc1SGreg Tucker 
60900c1efc1SGreg Tucker                 // Make parity vects
61000c1efc1SGreg Tucker                 // Generate g_tbls from encode matrix a
61100c1efc1SGreg Tucker                 ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
61200c1efc1SGreg Tucker                 // Perform matrix dot_prod for EC encoding
61300c1efc1SGreg Tucker                 // using g_tbls from encode matrix a
61400c1efc1SGreg Tucker                 ec_encode_data(size, k, m - k, g_tbls, ubuffs, &ubuffs[k]);
61500c1efc1SGreg Tucker 
61600c1efc1SGreg Tucker                 // Random errors
61700c1efc1SGreg Tucker                 memset(src_in_err, 0, TEST_SOURCES);
61800c1efc1SGreg Tucker                 gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
61900c1efc1SGreg Tucker 
62000c1efc1SGreg Tucker                 // Generate decode matrix
621*300260a4SMarcel Cornu                 re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index,
622*300260a4SMarcel Cornu                                           src_err_list, src_in_err, nerrs, nsrcerrs, k, m);
62300c1efc1SGreg Tucker                 if (re != 0) {
62400c1efc1SGreg Tucker                         printf("Fail to gf_gen_decode_matrix\n");
625a3e26043SPablo de Lara                         goto exit;
62600c1efc1SGreg Tucker                 }
62700c1efc1SGreg Tucker                 // Pack recovery array as list of valid sources
62800c1efc1SGreg Tucker                 // Its order must be the same as the order
62900c1efc1SGreg Tucker                 // to generate matrix b in gf_gen_decode_matrix
63000c1efc1SGreg Tucker                 for (i = 0; i < k; i++) {
63100c1efc1SGreg Tucker                         recov[i] = ubuffs[decode_index[i]];
63200c1efc1SGreg Tucker                 }
63300c1efc1SGreg Tucker 
63400c1efc1SGreg Tucker                 // Recover data
63500c1efc1SGreg Tucker                 ec_init_tables(k, nerrs, decode_matrix, g_tbls);
63600c1efc1SGreg Tucker                 ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_ubuffs[k]);
63700c1efc1SGreg Tucker 
63800c1efc1SGreg Tucker                 for (i = 0; i < nerrs; i++) {
63900c1efc1SGreg Tucker 
64000c1efc1SGreg Tucker                         if (0 != memcmp(temp_ubuffs[k + i], ubuffs[src_err_list[i]], size)) {
64100c1efc1SGreg Tucker                                 printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs);
64200c1efc1SGreg Tucker                                 printf(" - erase list = ");
64300c1efc1SGreg Tucker                                 for (j = 0; j < nerrs; j++)
64400c1efc1SGreg Tucker                                         printf(" %d", src_err_list[j]);
64500c1efc1SGreg Tucker                                 printf(" - Index = ");
64600c1efc1SGreg Tucker                                 for (p = 0; p < k; p++)
64700c1efc1SGreg Tucker                                         printf(" %d", decode_index[p]);
64800c1efc1SGreg Tucker                                 printf("\nencode_matrix:\n");
64900c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) encode_matrix, m, k);
65000c1efc1SGreg Tucker                                 printf("inv b:\n");
65100c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) invert_matrix, k, k);
65200c1efc1SGreg Tucker                                 printf("\ndecode_matrix:\n");
65300c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) decode_matrix, m, k);
65400c1efc1SGreg Tucker                                 printf("orig data:\n");
65500c1efc1SGreg Tucker                                 dump_matrix(ubuffs, m, 25);
65600c1efc1SGreg Tucker                                 printf("orig   :");
65700c1efc1SGreg Tucker                                 dump(ubuffs[src_err_list[i]], 25);
65800c1efc1SGreg Tucker                                 printf("recov %d:", src_err_list[i]);
65900c1efc1SGreg Tucker                                 dump(temp_ubuffs[k + i], 25);
660a3e26043SPablo de Lara                                 re = -1;
661a3e26043SPablo de Lara                                 goto exit;
66200c1efc1SGreg Tucker                         }
66300c1efc1SGreg Tucker                 }
66400c1efc1SGreg Tucker 
66500c1efc1SGreg Tucker                 // Confirm that padding around dests is unchanged
66600c1efc1SGreg Tucker                 memset(temp_buffs[0], 0, PTR_ALIGN_CHK_B); // Make reference zero buff
66700c1efc1SGreg Tucker 
66800c1efc1SGreg Tucker                 for (i = 0; i < m; i++) {
66900c1efc1SGreg Tucker 
67000c1efc1SGreg Tucker                         offset = ubuffs[i] - buffs[i];
67100c1efc1SGreg Tucker 
67200c1efc1SGreg Tucker                         if (memcmp(buffs[i], temp_buffs[0], offset)) {
67300c1efc1SGreg Tucker                                 printf("Fail rand ualign encode pad start\n");
674a3e26043SPablo de Lara                                 re = -1;
675a3e26043SPablo de Lara                                 goto exit;
67600c1efc1SGreg Tucker                         }
677*300260a4SMarcel Cornu                         if (memcmp(buffs[i] + offset + size, temp_buffs[0],
67800c1efc1SGreg Tucker                                    PTR_ALIGN_CHK_B - offset)) {
67900c1efc1SGreg Tucker                                 printf("Fail rand ualign encode pad end\n");
680a3e26043SPablo de Lara                                 re = -1;
681a3e26043SPablo de Lara                                 goto exit;
68200c1efc1SGreg Tucker                         }
68300c1efc1SGreg Tucker                 }
68400c1efc1SGreg Tucker 
68500c1efc1SGreg Tucker                 for (i = 0; i < nerrs; i++) {
68600c1efc1SGreg Tucker 
68700c1efc1SGreg Tucker                         offset = temp_ubuffs[k + i] - temp_buffs[k + i];
68800c1efc1SGreg Tucker                         if (memcmp(temp_buffs[k + i], temp_buffs[0], offset)) {
68900c1efc1SGreg Tucker                                 printf("Fail rand ualign decode pad start\n");
690a3e26043SPablo de Lara                                 re = -1;
691a3e26043SPablo de Lara                                 goto exit;
69200c1efc1SGreg Tucker                         }
693*300260a4SMarcel Cornu                         if (memcmp(temp_buffs[k + i] + offset + size, temp_buffs[0],
69400c1efc1SGreg Tucker                                    PTR_ALIGN_CHK_B - offset)) {
69500c1efc1SGreg Tucker                                 printf("Fail rand ualign decode pad end\n");
696a3e26043SPablo de Lara                                 re = -1;
697a3e26043SPablo de Lara                                 goto exit;
69800c1efc1SGreg Tucker                         }
69900c1efc1SGreg Tucker                 }
70000c1efc1SGreg Tucker 
7012ca781dfSPablo de Lara #ifdef TEST_VERBOSE
70200c1efc1SGreg Tucker                 putchar('.');
7032ca781dfSPablo de Lara #endif
70400c1efc1SGreg Tucker         }
70500c1efc1SGreg Tucker 
70600c1efc1SGreg Tucker         // Test size alignment
70700c1efc1SGreg Tucker 
70800c1efc1SGreg Tucker         align = (LEN_ALIGN_CHK_B != 0) ? 13 : 16;
70900c1efc1SGreg Tucker 
71000c1efc1SGreg Tucker         for (size = TEST_LEN; size > 0; size -= align) {
711*300260a4SMarcel Cornu                 while ((m = (rand() % MMAX)) < 2)
712*300260a4SMarcel Cornu                         ;
713*300260a4SMarcel Cornu                 while ((k = (rand() % KMAX)) >= m || k < 1)
714*300260a4SMarcel Cornu                         ;
71500c1efc1SGreg Tucker 
71600c1efc1SGreg Tucker                 if (m > MMAX || k > KMAX)
71700c1efc1SGreg Tucker                         continue;
71800c1efc1SGreg Tucker 
71900c1efc1SGreg Tucker                 for (i = 0; i < k; i++)
72000c1efc1SGreg Tucker                         for (j = 0; j < size; j++)
72100c1efc1SGreg Tucker                                 buffs[i][j] = rand();
72200c1efc1SGreg Tucker 
72300c1efc1SGreg Tucker                 // The matrix generated by gf_gen_cauchy1_matrix
72400c1efc1SGreg Tucker                 // is always invertable.
72500c1efc1SGreg Tucker                 gf_gen_cauchy1_matrix(encode_matrix, m, k);
72600c1efc1SGreg Tucker 
72700c1efc1SGreg Tucker                 // Make parity vects
72800c1efc1SGreg Tucker                 // Generate g_tbls from encode matrix a
72900c1efc1SGreg Tucker                 ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
73000c1efc1SGreg Tucker                 // Perform matrix dot_prod for EC encoding
73100c1efc1SGreg Tucker                 // using g_tbls from encode matrix a
73200c1efc1SGreg Tucker                 ec_encode_data(size, k, m - k, g_tbls, buffs, &buffs[k]);
73300c1efc1SGreg Tucker 
73400c1efc1SGreg Tucker                 // Random errors
73500c1efc1SGreg Tucker                 memset(src_in_err, 0, TEST_SOURCES);
73600c1efc1SGreg Tucker                 gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m);
73700c1efc1SGreg Tucker                 // Generate decode matrix
738*300260a4SMarcel Cornu                 re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index,
739*300260a4SMarcel Cornu                                           src_err_list, src_in_err, nerrs, nsrcerrs, k, m);
74000c1efc1SGreg Tucker                 if (re != 0) {
74100c1efc1SGreg Tucker                         printf("Fail to gf_gen_decode_matrix\n");
742a3e26043SPablo de Lara                         goto exit;
74300c1efc1SGreg Tucker                 }
74400c1efc1SGreg Tucker                 // Pack recovery array as list of valid sources
74500c1efc1SGreg Tucker                 // Its order must be the same as the order
74600c1efc1SGreg Tucker                 // to generate matrix b in gf_gen_decode_matrix
74700c1efc1SGreg Tucker                 for (i = 0; i < k; i++) {
74800c1efc1SGreg Tucker                         recov[i] = buffs[decode_index[i]];
74900c1efc1SGreg Tucker                 }
75000c1efc1SGreg Tucker 
75100c1efc1SGreg Tucker                 // Recover data
75200c1efc1SGreg Tucker                 ec_init_tables(k, nerrs, decode_matrix, g_tbls);
75300c1efc1SGreg Tucker                 ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]);
75400c1efc1SGreg Tucker 
75500c1efc1SGreg Tucker                 for (i = 0; i < nerrs; i++) {
75600c1efc1SGreg Tucker 
75700c1efc1SGreg Tucker                         if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], size)) {
75800c1efc1SGreg Tucker                                 printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs);
75900c1efc1SGreg Tucker                                 printf(" - erase list = ");
76000c1efc1SGreg Tucker                                 for (j = 0; j < nerrs; j++)
76100c1efc1SGreg Tucker                                         printf(" %d", src_err_list[j]);
76200c1efc1SGreg Tucker                                 printf(" - Index = ");
76300c1efc1SGreg Tucker                                 for (p = 0; p < k; p++)
76400c1efc1SGreg Tucker                                         printf(" %d", decode_index[p]);
76500c1efc1SGreg Tucker                                 printf("\nencode_matrix:\n");
76600c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) encode_matrix, m, k);
76700c1efc1SGreg Tucker                                 printf("inv b:\n");
76800c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) invert_matrix, k, k);
76900c1efc1SGreg Tucker                                 printf("\ndecode_matrix:\n");
77000c1efc1SGreg Tucker                                 dump_u8xu8((unsigned char *) decode_matrix, m, k);
77100c1efc1SGreg Tucker                                 printf("orig data:\n");
77200c1efc1SGreg Tucker                                 dump_matrix(buffs, m, 25);
77300c1efc1SGreg Tucker                                 printf("orig   :");
77400c1efc1SGreg Tucker                                 dump(buffs[src_err_list[i]], 25);
77500c1efc1SGreg Tucker                                 printf("recov %d:", src_err_list[i]);
77600c1efc1SGreg Tucker                                 dump(temp_buffs[k + i], 25);
777a3e26043SPablo de Lara                                 re = -1;
778a3e26043SPablo de Lara                                 goto exit;
77900c1efc1SGreg Tucker                         }
78000c1efc1SGreg Tucker                 }
78100c1efc1SGreg Tucker         }
78200c1efc1SGreg Tucker 
78300c1efc1SGreg Tucker         printf("done EC tests: Pass\n");
784a3e26043SPablo de Lara         re = 0;
785a3e26043SPablo de Lara 
786a3e26043SPablo de Lara exit:
787a3e26043SPablo de Lara         for (i = 0; i < TEST_SOURCES; i++) {
788a3e26043SPablo de Lara                 if (buffs[i])
789a3e26043SPablo de Lara                         aligned_free(buffs[i]);
790a3e26043SPablo de Lara                 if (temp_buffs[i])
791a3e26043SPablo de Lara                         aligned_free(temp_buffs[i]);
792a3e26043SPablo de Lara         }
793a3e26043SPablo de Lara         free(encode_matrix);
794a3e26043SPablo de Lara         free(decode_matrix);
795a3e26043SPablo de Lara         free(invert_matrix);
796a3e26043SPablo de Lara         free(g_tbls);
797a3e26043SPablo de Lara 
798a3e26043SPablo de Lara         return re;
79900c1efc1SGreg Tucker }
800