/* * Copyright (c) 2014 Kaprica Security, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ /* * --- (127, 99, 4) implementation * Messages are stored LSB */ #include "cgc_stdlib.h" #include "cgc_stdint.h" #include "cgc_string.h" #include "cgc_ecc.h" #define M 7 #define N 127 // number of bits #define K 99 // number of message bits #define T 4 // number of correctable bits const static unsigned int G = 0x1c9c26b9; // generator polynomial const static unsigned int prim = 0x89; // primitive polynomial static uint8_t field[N]; static uint8_t gf_index[N+1]; #define FMUL(x, y) (field[(gf_index[x] + gf_index[y]) % N]) #define FINV(x) (field[(N - gf_index[x]) % N]) void cgc_ecc_init() { int i; for (i = 0; i < M; i++) field[i] = 1 << i; field[M] = prim ^ (1 << M); for (i = M+1; i < N; i++) { field[i] = field[i-1] << 1; if (field[i] & (1 << M)) { // hard case, outside of the field field[i] = field[M] ^ (field[i] ^ (1 << M)); } } // fill in gf_index table for (i = 0; i < N; i++) gf_index[field[i]] = i; } int cgc_ecc_encode(uint8_t *bits) { int i, j; // clear the parity bits for (i = 0; i < N-K; i++) bits[i] = 0; // treat the parity bits as an LFSR in order to do polynomial division // the input is the message bits, configuration of the LFSR is hard-coded // to the generator polynomial: 11100100111000010011010111001 // "input" into the LFSR is the XOR of the feedback and the input bit // afterwards, the parity bits will contain the remainder of the division for (i = N-1; i >= N-K; i--) { uint8_t input = bits[N-K-1] ^ bits[i]; // shift the register for (j = N-K-1; j > 0; j--) bits[j] = bits[j-1]; // apply polynomial bits[0] = 0; if (input) for (j = 0; j < N-K; j++) bits[j] ^= (G >> j) & 1; } return 0; } int cgc_ecc_decode(uint8_t *bits) { int i, j, L, m, b, corrections; uint8_t s[2*T], C[T+1], B[T+1]; // calculate syndromes for (i = 0; i < 2*T; i++) s[i] = 0; for (i = 0; i < N; i++) { if (bits[i]) for (j = 0; j < 2*T; j++) s[j] ^= field[(i * (j + 1)) % N]; } // Berlekamp-Massey algorithm cgc_memset(B, 0, sizeof(B)); cgc_memset(C, 0, sizeof(C)); B[0] = 1; C[0] = 1; L = 0; m = 1; b = 1; for (i = 0; i < 2*T; i++, m++) { uint8_t d = s[i]; for (j = 1; j <= L; j++) d ^= FMUL(C[j], s[i - j]); if (d != 0) { uint8_t tmp[T+1]; cgc_memcpy(tmp, C, sizeof(C)); for (j = 0; j < T; j++) if (B[j]) C[m + j] ^= FMUL(d, FMUL(FINV(b), B[j])); if (2 * L <= i) { L = i + 1 - L; b = d; m = 0; cgc_memcpy(B, tmp, sizeof(B)); } } } // Find the roots in C using Chien search corrections = 0; for (i = 0; i < N; i++) { uint8_t sum = 0; for (j = 0; j <= L; j++) sum ^= FMUL(C[j], field[(i * j) % N]); if (sum == 0) { // found a root, error location is inverse of i corrections++; bits[(N - i) % N] ^= 1; } } if (L > 2) cgc_fdprintf(STDERR, "\nFOUND ERRORS: %d %d\n", corrections, L); return corrections == L; }