/* * Polynomial Evaluator, used to determine the Syndrome Vector. This is * relatively straightforward, and there are faster algorithms. */ static uint8_t evalpoly(uint8_t p[ECC_CAPACITY], uint8_t x) { uint8_t y = 0; for (int i = 0; i < ECC_CAPACITY; i++) y = GF_ADD(y, GF_MUL(p[i], GF_EXP(x, i))); return y; }
/* * Reed - Solomon Encoder. The Encoder uses a shift register algorithm, * as detailed in _Applied Modern Algebra_ by Dornhoff and Hohn (p.446). * Note that the message is reversed in the code array; this was done to * allow for (emergency) recovery of the message directly from the * data stream. */ extern void ecc_encode(uint8_t m[ECC_PAYLOAD], uint8_t c[ECC_CAPACITY]) { uint8_t r[ECC_OFFSET] = { 0x0 }; for (int i = 0; i < ECC_PAYLOAD; i++) { c[(ECC_CAPACITY - 1) - i] = m[i]; uint8_t rtmp = GF_ADD(m[i], r[5]); for (int j = ECC_OFFSET - 1; j > 0; j--) r[j] = GF_ADD(GF_MUL(rtmp, g[j]), r[j - 1]); r[0] = GF_MUL(rtmp, g[0]); } for (int i = 0; i < ECC_OFFSET; i++) c[i] = r[i]; REVERSE(c, ECC_CAPACITY); }
/* * Polynomial Solver. Simple exhaustive search, as solving polynomials is * generally NP - Complete anyway. */ static void polysolve(uint8_t polynom[4], uint8_t roots[3], int *numsol) { *numsol = 0; for (int i = 0; i < ECC_CAPACITY; i++) { uint8_t y = 0; for (int j = 0; j < 4; j++) y = GF_ADD(y, GF_MUL(polynom[j], GF_EXP(e2v[i], j))); if (y == 0) roots[(*numsol)++] = e2v[i]; } }
/* * Determine the number of errors in a block. Since we have to find the * determinant of the S[] matrix in order to determine singularity, we * also return the determinant to be used by the Cramer's Rule correction * algorithm. */ static void errnum(uint8_t s[ECC_OFFSET + 1], uint8_t *det, int *errs) { *det = GF_MUL(s[2], GF_MUL(s[4], s[6])); *det = GF_ADD(*det, GF_MUL(s[2], GF_MUL(s[5], s[5]))); *det = GF_ADD(*det, GF_MUL(s[6], GF_MUL(s[3], s[3]))); *det = GF_ADD(*det, GF_MUL(s[4], GF_MUL(s[4], s[4]))); *errs = 3; if (*det != 0) return; *det = GF_ADD(GF_MUL(s[2], s[4]), GF_EXP(s[3], 2)); *errs = 2; if (*det != 0) return; *det = s[1]; *errs = 1; if (*det != 0) return; *errs = 4; }
/* * Full implementation of the three error correcting Peterson decoder. For * t<6, it is faster than Massey - Berlekamp. It is also somewhat more * intuitive. */ extern void ecc_decode(uint8_t code[ECC_CAPACITY], uint8_t mesg[ECC_CAPACITY], int *errcode) { REVERSE(code, ECC_CAPACITY); uint8_t syn[ECC_OFFSET + 1], deter, z[4], e0, e1, e2, n0, n1, n2, w0, w1, w2, x0, x[3]; int sols; *errcode = 0; /* * First, get the message out of the code, so that even if we can't correct * it, we return an estimate. */ for (int i = 0; i < ECC_PAYLOAD; i++) mesg[i] = code[(ECC_CAPACITY - 1) - i]; syndrome(code, syn); if (syn[0] == 0) return; /* * We now know we have at least one error. If there are no errors detected, * we assume that something funny is going on, and so return with errcode 4, * else pass the number of errors back via errcode. */ errnum(syn, &deter, errcode); if (*errcode == 4) return; /* Having obtained the syndrome, the number of errors, and the determinant, * we now proceed to correct the block. If we do not find exactly the * number of solutions equal to the number of errors, we have exceeded our * error capacity, and return with the block uncorrected, and errcode 4. */ switch (*errcode) { case 1: x0 = GF_MUL(syn[2], GF_INV(syn[1])); w0 = GF_MUL(GF_EXP(syn[1], 2), GF_INV(syn[2])); if (v2e[x0] > 5) mesg[(ECC_CAPACITY - 1) - v2e[x0]] = GF_ADD(mesg[(ECC_CAPACITY - 1) - v2e[x0]], w0); return; case 2: z[0] = GF_MUL(GF_ADD(GF_MUL(syn[1], syn[3]), GF_EXP(syn[2], 2)), GF_INV(deter)); z[1] = GF_MUL(GF_ADD(GF_MUL(syn[2], syn[3]), GF_MUL(syn[1], syn[4])), GF_INV(deter)); z[2] = 1; z[3] = 0; polysolve(z, x, &sols); if (sols != 2) { *errcode = 4; return; } w0 = GF_MUL(z[0], syn[1]); w1 = GF_ADD(GF_MUL(z[0], syn[2]), GF_MUL(z[1], syn[1])); n0 = (ECC_CAPACITY - 1) - v2e[GF_INV(x[0])]; n1 = (ECC_CAPACITY - 1) - v2e[GF_INV(x[1])]; e0 = GF_MUL(GF_ADD(w0, GF_MUL(w1, x[0])), GF_INV(z[1])); e1 = GF_MUL(GF_ADD(w0, GF_MUL(w1, x[1])), GF_INV(z[1])); if (n0 < ECC_PAYLOAD) mesg[n0] = GF_ADD(mesg[n0], e0); if (n1 < ECC_PAYLOAD) mesg[n1] = GF_ADD(mesg[n1], e1); return; case 3: z[3] = 1; z[2] = GF_MUL(syn[1], GF_MUL(syn[4], syn[6])); z[2] = GF_ADD(z[2], GF_MUL(syn[1], GF_MUL(syn[5], syn[5]))); z[2] = GF_ADD(z[2], GF_MUL(syn[5], GF_MUL(syn[3], syn[3]))); z[2] = GF_ADD(z[2], GF_MUL(syn[3], GF_MUL(syn[4], syn[4]))); z[2] = GF_ADD(z[2], GF_MUL(syn[2], GF_MUL(syn[5], syn[4]))); z[2] = GF_ADD(z[2], GF_MUL(syn[2], GF_MUL(syn[3], syn[6]))); z[2] = GF_MUL(z[2], GF_INV(deter)); z[1] = GF_MUL(syn[1], GF_MUL(syn[3], syn[6])); z[1] = GF_ADD(z[1], GF_MUL(syn[1], GF_MUL(syn[5], syn[4]))); z[1] = GF_ADD(z[1], GF_MUL(syn[4], GF_MUL(syn[3], syn[3]))); z[1] = GF_ADD(z[1], GF_MUL(syn[2], GF_MUL(syn[4], syn[4]))); z[1] = GF_ADD(z[1], GF_MUL(syn[2], GF_MUL(syn[3], syn[5]))); z[1] = GF_ADD(z[1], GF_MUL(syn[2], GF_MUL(syn[2], syn[6]))); z[1] = GF_MUL(z[1], GF_INV(deter)); z[0] = GF_MUL(syn[2], GF_MUL(syn[3], syn[4])); z[0] = GF_ADD(z[0], GF_MUL(syn[3], GF_MUL(syn[2], syn[4]))); z[0] = GF_ADD(z[0], GF_MUL(syn[3], GF_MUL(syn[5], syn[1]))); z[0] = GF_ADD(z[0], GF_MUL(syn[4], GF_MUL(syn[4], syn[1]))); z[0] = GF_ADD(z[0], GF_MUL(syn[3], GF_MUL(syn[3], syn[3]))); z[0] = GF_ADD(z[0], GF_MUL(syn[2], GF_MUL(syn[2], syn[5]))); z[0] = GF_MUL(z[0], GF_INV(deter)); polysolve (z, x, &sols); if (sols != 3) { *errcode = 4; return; } w0 = GF_MUL(z[0], syn[1]); w1 = GF_ADD(GF_MUL(z[0], syn[2]), GF_MUL(z[1], syn[1])); w2 = GF_ADD(GF_MUL(z[0], syn[3]), GF_ADD(GF_MUL(z[1], syn[2]), GF_MUL(z[2], syn[1]))); n0 = (ECC_CAPACITY - 1) - v2e[GF_INV(x[0])]; n1 = (ECC_CAPACITY - 1) - v2e[GF_INV(x[1])]; n2 = (ECC_CAPACITY - 1) - v2e[GF_INV(x[2])]; e0 = GF_ADD(w0, GF_ADD(GF_MUL(w1, x[0]), GF_MUL(w2, GF_EXP(x[0], 2)))); e0 = GF_MUL(e0, GF_INV(GF_ADD(z[1], GF_EXP(x[0], 2)))); e1 = GF_ADD(w0, GF_ADD(GF_MUL(w1, x[1]), GF_MUL(w2, GF_EXP(x[1], 2)))); e1 = GF_MUL(e1, GF_INV(GF_ADD(z[1], GF_EXP(x[1], 2)))); e2 = GF_ADD(w0, GF_ADD(GF_MUL(w1, x[2]), GF_MUL(w2, GF_EXP(x[2], 2)))); e2 = GF_MUL(e2, GF_INV(GF_ADD(z[1], GF_EXP(x[2], 2)))); if (n0 < ECC_PAYLOAD) mesg[n0] = GF_ADD(mesg[n0], e0); if (n1 < ECC_PAYLOAD) mesg[n1] = GF_ADD(mesg[n1], e1); if (n2 < ECC_PAYLOAD) mesg[n2] = GF_ADD(mesg[n2], e2); return; } }
int main(void) { gf a, b, c; gf_init(); a = 1; b = 37; c = 78; testit("1 * ( 37 + 78 ) = 1 * 37 + 1 * 78", GF_MUL(a, GF_ADD(b, c)), GF_ADD(GF_MUL(a, b), GF_MUL(a, c))); testit("(1 * 37) * 78 = 1 * (37 * 78)", GF_MUL(GF_MUL(a, b), c), GF_MUL(a, GF_MUL(b, c))); testit("(37 * 78) * 37 = (37 * 37) * 78", GF_MUL(GF_MUL(b, c), b), GF_MUL(GF_MUL(b, b), c)); testit("b * b^-1 = 1", GF_MUL(b, GF_INV(b)), 1); return 0; }
/*M \emph{Computes addition of a row multiplied by a constant.} Computes $a = a + c * b$, $a, b \in \gf{2^8}^k, c \in \gf{2^8}$. **/ void gf_add_mul(gf *a, gf *b, gf c, int k) { int i; for (i = 0; i < k; i++) a[i] = GF_ADD(a[i], GF_MUL(c, b[i])); }