[
  {
    "path": ".gitexcludes",
    "content": "./src/libRS.pro.user\n./tests/tests.pro.user\n./Reed-Solomon.pro.user\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [master]\n  schedule:\n    - cron: '0 12 * * 2'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        # Override automatic language detection by changing the below list\n        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']\n        language: ['cpp']\n        # Learn more...\n        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n      with:\n        # We must fetch at least the immediate parents so that if this is\n        # a pull request then we can checkout the head.\n        fetch-depth: 2\n\n    # If this run was triggered by a pull request event, then checkout\n    # the head of the pull request instead of the merge commit.\n    - run: git checkout HEAD^2\n      if: ${{ github.event_name == 'pull_request' }}\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file. \n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".gitignore",
    "content": "*.so\n*.a\n*.o\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"tests/mtest\"]\n\tpath = tests/mtest\n\turl = git@github.com:mersinvald/mtest.git\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(Reed-Solomon)\n\n# You can tweak some common (for all subprojects) stuff here. For example:\n\nset(CMAKE_DISABLE_IN_SOURCE_BUILD ON)\nset(CMAKE_DISABLE_SOURCE_CHANGES  ON)\n\nif (\"${CMAKE_SOURCE_DIR}\" STREQUAL \"${CMAKE_BINARY_DIR}\")\n  message(SEND_ERROR \"In-source builds are not allowed.\")\nendif ()\n\nset(CMAKE_VERBOSE_MAKEFILE ON)\nset(CMAKE_COLOR_MAKEFILE   ON)\n\n# Remove 'lib' prefix for shared libraries on Windows\nif (WIN32)\n  set(CMAKE_SHARED_LIBRARY_PREFIX \"\")\nendif ()\n\nset(CMAKE_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG} -O0\")\nset(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -O3\")\n\nset(RS_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include)\n\n# When done tweaking common stuff, configure the components (subprojects).\n# NOTE: The order matters! The most independent ones should go first.\nadd_subdirectory(examples)\nadd_subdirectory(tests)\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright © 2015 Mike Lubinets, github.com/mersinvald\n\nPermission is hereby granted, free of charge, to any person \nobtaining a copy of this software and associated documentation files \n(the “Software”), to deal in the Software without restriction, \nincluding without limitation the rights to use, copy, modify, merge, \npublish, distribute, sublicense, and/or sell copies of the Software, \nand to permit persons to whom the Software is furnished to do so, \nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be \nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, \nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF \nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS \nBE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN \nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "all:\n\tmkdir -p build && cd build && cmake ../ && make\n\nx32:\n\tmkdir -p build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=../x32.cmake_toolchain ../ && make\n\nclean:\n\tcd build && make clean && cd .. && rm -rf build\n\n"
  },
  {
    "path": "README.md",
    "content": "# Reed-Solomon\nReed Solomon BCH encoder and decoder library\n\n## Overview\n\nThis RS implementation was designed for embedded purposes, so all the memory allocations performed on the stack.<br>\nIf somebody wants to reimplement memory management with heap usage, pull requests are welcome\n\n## Getting the source\n\nIf you want only Reed-Solomon code, just clone repository.<br>\nIf you want to get tests and examples also, do \n```\ngit clone --recursive git@github.com:mersinvald/Reed-Solomon.git\n```\n\n## Build\n\nThere is no need in building RS library, cause all the implementation is in headers.<br>\nTo build tests and examples simply run <b>make</b> in the folder with cloned repo and executables will emerge in the \n./build folder\n\n## Usage\n\nAll the Reed-Solomon code is in folder **include**, you just need to include header <b>rs.hpp</b>\n\nTemplate class ReedSolomon accepts two template arguments: message length and ecc length. <br>\nSimple example: <br>\n```\n    char message[] = \"Some very important message ought to be delivered\";\n    const int msglen = sizeof(message);\n    const int ecclen = 8;\n    \n    char repaired[msglen];\n    char encoded[msglen + ecclen];\n\n\n    RS::ReedSolomon<msglen, ecclen> rs;\n\n    rs.Encode(message, encoded);\n\n    // Corrupting first 8 bytes of message (any 4 bytes can be repaired, no more)\n    for(uint i = 0; i < ecclen / 2; i++) {\n        encoded[i] = 'E';\n    }\n\n    rs.Decode(encoded, repaired);\n\n    std::cout << \"Original:  \" << message  << std::endl;\n    std::cout << \"Corrupted: \" << encoded  << std::endl;\n    std::cout << \"Repaired:  \" << repaired << std::endl;\n\n    std::cout << ((memcmp(message, repaired, msglen) == 0) ? \"SUCCESS\" : \"FAILURE\") << std::endl;\n```\n\n## Regards\n\nHuge thanks to authors of [wikiversity page about Reed-Solomon BCH](https://en.wikiversity.org/wiki/Reed–Solomon_codes_for_coders)\n## Related projects\n\n[Arduino Reed-Solomon Forward Error Correction library](https://github.com/simonyipeter/Arduino-FEC)\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(examples CXX)\n\ninclude(CheckCXXCompilerFlag)\nCHECK_CXX_COMPILER_FLAG(\"-std=c++11\" COMPILER_SUPPORTS_CXX11)\nCHECK_CXX_COMPILER_FLAG(\"-std=c++0x\" COMPILER_SUPPORTS_CXX0X)\n\nif(COMPILER_SUPPORTS_CXX11)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\nelseif(COMPILER_SUPPORTS_CXX0X)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++0x\")\nelse()\n    message(STATUS \"The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.\")\nendif()\n\n\ninclude_directories(${RS_INCLUDE_DIRS})\n\nadd_executable(example1 example1.cpp)\n"
  },
  {
    "path": "examples/example1.cpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include <iostream>\n#include \"rs.hpp\"\nusing namespace std;\n\n#define ECC_LENGTH 8\n\nint main() {\n\n    char message[] = \"Some very important message ought to be delivered\";\n    const int msglen = sizeof(message);\n\n    char repaired[msglen];\n    char encoded[msglen + ECC_LENGTH];\n\n\n    RS::ReedSolomon<msglen, ECC_LENGTH> rs;\n\n    rs.Encode(message, encoded);\n\n    // Corrupting first 8 bytes of message (any 8 bytes can be repaired)\n    for(uint i = 0; i < ECC_LENGTH / 2; i++) {\n        encoded[i] = 'E';\n    }\n\n    rs.Decode(encoded, repaired);\n\n    std::cout << \"Original:  \" << message  << std::endl;\n    std::cout << \"Corrupted: \" << encoded  << std::endl;\n    std::cout << \"Repaired:  \" << repaired << std::endl;\n\n    std::cout << ((memcmp(message, repaired, msglen) == 0) ? \"SUCCESS\" : \"FAILURE\") << std::endl;\n    return 0;\n}\n\n"
  },
  {
    "path": "include/gf.hpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\r\n * Date: 29.12.15\r\n *\r\n * See LICENSE */\r\n\r\n#ifndef GF_H\r\n#define GF_H\r\n#include <stdint.h>\r\n#include <string.h>\r\n#include \"poly.hpp\"\r\n\r\n#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT\r\n#include <assert.h>\r\n#else\r\n#define assert(dummy)\r\n#endif\r\n\r\n\r\nnamespace RS {\r\n\r\nnamespace gf {\r\n\r\n\r\n/* GF tables pre-calculated for 0x11d primitive polynomial */\r\n\r\nconst uint8_t exp[255] = {\r\n    0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c,\r\n    0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x3, 0x6, 0xc, 0x18, 0x30, 0x60, 0xc0, 0x9d,\r\n    0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 0x46,\r\n    0x8c, 0x5, 0xa, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 0x5f,\r\n    0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0xf, 0x1e, 0x3c, 0x78, 0xf0, 0xfd,\r\n    0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 0xd9,\r\n    0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0xd, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 0x81,\r\n    0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 0x85,\r\n    0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 0xa8,\r\n    0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 0xe6,\r\n    0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 0xe3,\r\n    0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 0x82,\r\n    0x19, 0x32, 0x64, 0xc8, 0x8d, 0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 0x51,\r\n    0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x9, 0x12,\r\n    0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0xb, 0x16, 0x2c,\r\n    0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e\r\n};\r\n\r\nconst uint8_t log[256] = {\r\n    0x0, 0x0, 0x1, 0x19, 0x2, 0x32, 0x1a, 0xc6, 0x3, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x4,\r\n    0x64, 0xe0, 0xe, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x8, 0x4c, 0x71, 0x5,\r\n    0x8a, 0x65, 0x2f, 0xe1, 0x24, 0xf, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 0x1d,\r\n    0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x9, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 0x6,\r\n    0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 0x36,\r\n    0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 0x1e,\r\n    0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 0xca,\r\n    0x5e, 0x9b, 0x9f, 0xa, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 0x7,\r\n    0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0xd, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 0xe3,\r\n    0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 0x37,\r\n    0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 0xf2,\r\n    0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 0x1f,\r\n    0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0xc, 0x6f, 0xf6, 0x6c,\r\n    0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 0xcb,\r\n    0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0xb, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 0x4f,\r\n    0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf\r\n};\r\n\r\n\r\n\r\n/* ################################\r\n * # OPERATIONS OVER GALOIS FIELDS #\r\n * ################################ */\r\n\r\n/* @brief Addition in Galois Fields\r\n * @param x - left operand\r\n * @param y - right operand\r\n * @return x + y */\r\ninline uint8_t add(uint8_t x, uint8_t y) {\r\n    return x^y;\r\n}\r\n\r\n/* ##### GF subtraction ###### */\r\n/* @brief Subtraction in Galois Fields\r\n * @param x - left operand\r\n * @param y - right operand\r\n * @return x - y */\r\ninline uint8_t sub(uint8_t x, uint8_t y) {\r\n    return x^y;\r\n}\r\n\r\n/* @brief Multiplication in Galois Fields\r\n * @param x - left operand\r\n * @param y - right operand\r\n * @return x * y */\r\ninline uint8_t mul(uint16_t x, uint16_t y){\r\n    if (x == 0 || y == 0)\r\n        return 0;\r\n    return exp[(log[x] + log[y]) % 255];\r\n}\r\n\r\n/* @brief Division in Galois Fields\r\n * @param x - dividend\r\n * @param y - divisor\r\n * @return x / y */\r\ninline uint8_t div(uint8_t x, uint8_t y){\r\n    assert(y != 0);\r\n    if(x == 0) return 0;\r\n    return exp[(log[x] + 255 - log[y]) % 255];\r\n}\r\n\r\n/* @brief X in power Y w\r\n * @param x     - operand\r\n * @param power - power\r\n * @return x^power */\r\ninline uint8_t pow(uint8_t x, intmax_t power){\r\n    intmax_t i = log[x];\r\n    i *= power;\r\n    i %= 255;\r\n    if(i < 0) i = i + 255;\r\n    return exp[i % 255];\r\n}\r\n\r\n/* @brief Inversion in Galois Fields\r\n * @param x - number\r\n * @return inversion of x */\r\ninline uint8_t inverse(uint8_t x){\r\n    return exp[(255 - log[x]) % 255]; /* == div(1, x); */\r\n}\r\n\r\n/* ##########################\r\n * # POLYNOMIALS OPERATIONS #\r\n * ########################## */\r\n\r\n/* @brief Multiplication polynomial by scalar\r\n * @param &p    - source polynomial\r\n * @param &newp - destination polynomial\r\n * @param x     - scalar */\r\ninline void\r\npoly_scale(const Poly *p, Poly *newp, uint16_t x) {\r\n    newp->length = p->length;\r\n    for(uint16_t i = 0; i < p->length; i++){\r\n        newp->at(i) = mul(p->at(i), x);\r\n    }\r\n}\r\n\r\n/* @brief Addition of two polynomials\r\n * @param &p    - right operand polynomial\r\n * @param &q    - left operand polynomial\r\n * @param &newp - destination polynomial */\r\ninline void\r\npoly_add(const Poly *p, const Poly *q, Poly *newp) {\r\n    newp->length = poly_max(p->length, q->length);\r\n    memset(newp->ptr(), 0, newp->length * sizeof(uint8_t));\r\n\r\n    for(uint8_t i = 0; i < p->length; i++){\r\n        newp->at(i + newp->length - p->length) = p->at(i);\r\n    }\r\n\r\n    for(uint8_t i = 0; i < q->length; i++){\r\n        newp->at(i + newp->length - q->length) ^= q->at(i);\r\n    }\r\n}\r\n\r\n\r\n/* @brief Multiplication of two polynomials\r\n * @param &p    - right operand polynomial\r\n * @param &q    - left operand polynomial\r\n * @param &newp - destination polynomial */\r\ninline void\r\npoly_mul(const Poly *p, const Poly *q, Poly *newp) {\r\n    newp->length = p->length + q->length - 1;\r\n    memset(newp->ptr(), 0, newp->length * sizeof(uint8_t));\r\n    /* Compute the polynomial multiplication (just like the outer product of two vectors,\r\n     * we multiply each coefficients of p with all coefficients of q) */\r\n    for(uint8_t j = 0; j < q->length; j++){\r\n        for(uint8_t i = 0; i < p->length; i++){\r\n            newp->at(i+j) ^= mul(p->at(i), q->at(j)); /* == r[i + j] = gf_add(r[i+j], gf_mul(p[i], q[j])) */\r\n        }\r\n    }\r\n}\r\n\r\n/* @brief Division of two polynomials\r\n * @param &p    - right operand polynomial\r\n * @param &q    - left operand polynomial\r\n * @param &newp - destination polynomial */\r\ninline void\r\npoly_div(const Poly *p, const Poly *q, Poly *newp) {\r\n    if(p->ptr() != newp->ptr()) {\r\n        memcpy(newp->ptr(), p->ptr(), p->length*sizeof(uint8_t));\r\n    }\r\n\r\n    newp->length = p->length;\r\n\r\n    uint8_t coef;\r\n\r\n    for(int i = 0; i < (p->length-(q->length-1)); i++){\r\n        coef = newp->at(i);\r\n        if(coef != 0){\r\n            for(uint8_t j = 1; j < q->length; j++){\r\n                if(q->at(j) != 0)\r\n                    newp->at(i+j) ^= mul(q->at(j), coef);\r\n            }\r\n        }\r\n    }\r\n\r\n    size_t sep = p->length-(q->length-1);\r\n    memmove(newp->ptr(), newp->ptr()+sep, (newp->length-sep) * sizeof(uint8_t));\r\n    newp->length = newp->length-sep;\r\n}\r\n\r\n/* @brief Evaluation of polynomial in x\r\n * @param &p - polynomial to evaluate\r\n * @param x  - evaluation point */\r\ninline int8_t\r\npoly_eval(const Poly *p, uint16_t x) {\r\n    uint8_t y = p->at(0);\r\n    for(uint8_t i = 1; i < p->length; i++){\r\n        y = mul(y, x) ^ p->at(i);\r\n    }\r\n    return y;\r\n}\r\n\r\n} /* end of gf namespace */\r\n\r\n}\r\n#endif // GF_H\r\n\r\n"
  },
  {
    "path": "include/poly.hpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\r\n * Date: 29.12.15\r\n *\r\n * See LICENSE */\r\n\r\n#ifndef POLY_H\r\n#define POLY_H\r\n#include <stdint.h>\r\n#include <string.h>\r\n\r\n#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT\r\n#include <assert.h>\r\n#else\r\n#define assert(dummy)\r\n#endif\r\n\r\nnamespace RS {\r\n\r\nstruct Poly {\r\n    Poly()\r\n        : length(0), _memory(NULL) {}\r\n\r\n    Poly(uint8_t id, uint16_t offset, uint8_t size) \\\r\n        : length(0), _id(id), _size(size), _offset(offset), _memory(NULL) {}\r\n\r\n    /* @brief Append number at the end of polynomial\r\n     * @param num - number to append\r\n     * @return false if polynomial can't be stretched */\r\n    inline bool Append(uint8_t num) {\r\n        assert(length+1 < _size);\r\n        ptr()[length++] = num;\r\n        return true;\r\n    }\r\n\r\n    /* @brief Polynomial initialization */\r\n    inline void Init(uint8_t id, uint16_t offset, uint8_t size, uint8_t** memory_ptr) {\r\n        this->_id     = id;\r\n        this->_offset = offset;\r\n        this->_size   = size;\r\n        this->length  = 0;\r\n        this->_memory = memory_ptr;\r\n    }\r\n\r\n    /* @brief Polynomial memory zeroing */\r\n    inline void Reset() {\r\n        memset((void*)ptr(), 0, this->_size);\r\n    }\r\n\r\n    /* @brief Copy polynomial to memory\r\n     * @param src    - source byte-sequence\r\n     * @param size   - size of polynomial\r\n     * @param offset - write offset */\r\n    inline void Set(const uint8_t* src, uint8_t len, uint8_t offset = 0) {\r\n        assert(src && len <= this->_size-offset);\r\n        memcpy(ptr()+offset, src, len * sizeof(uint8_t));\r\n        length = len + offset;\r\n    }\r\n\r\n    #define poly_max(a, b) ((a > b) ? (a) : (b))\r\n\r\n    inline void Copy(const Poly* src) {\r\n        length = poly_max(length, src->length);\r\n        Set(src->ptr(), length);\r\n    }\r\n\r\n    inline uint8_t& at(uint8_t i) const {\r\n        assert(i < _size);\r\n        return ptr()[i];\r\n    }\r\n\r\n    inline uint8_t id() const {\r\n        return _id;\r\n    }\r\n\r\n    inline uint8_t size() const {\r\n        return _size;\r\n    }\r\n\r\n    // Returns pointer to memory of this polynomial\r\n    inline uint8_t* ptr() const {\r\n        assert(_memory && *_memory);\r\n        return (*_memory) + _offset;\r\n    }\r\n\r\n    uint8_t length;\r\n\r\nprotected:\r\n\r\n    uint8_t   _id;\r\n    uint8_t   _size;    // Size of reserved memory for this polynomial\r\n    uint16_t  _offset;  // Offset in memory\r\n    uint8_t** _memory;  // Pointer to pointer to memory\r\n};\r\n\r\n\r\n}\r\n\r\n#endif // POLY_H\r\n"
  },
  {
    "path": "include/rs.hpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\r\n * Date: 29.12.15\r\n *\r\n * See LICENSE */\r\n\r\n#ifndef RS_HPP\r\n#define RS_HPP\r\n#include <string.h>\r\n#include <stdint.h>\r\n#include \"poly.hpp\"\r\n#include \"gf.hpp\"\r\n\r\n#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT\r\n#include <assert.h>\r\n#else\r\n#define assert(dummy)\r\n#endif\r\n\r\nnamespace RS {\r\n\r\n#define MSG_CNT 3   // message-length polynomials count\r\n#define POLY_CNT 14 // (ecc_length*2)-length polynomials count\r\n\r\ntemplate <const uint8_t msg_length,  // Message length without correction code\r\n          const uint8_t ecc_length>  // Length of correction code\r\n\r\nclass ReedSolomon {\r\npublic:\r\n    ReedSolomon() {\r\n        const uint8_t   enc_len  = msg_length + ecc_length;\r\n        const uint8_t   poly_len = ecc_length * 2;\r\n        uint8_t** memptr   = &memory;\r\n        uint16_t  offset   = 0;\r\n\r\n        /* Initialize first six polys manually cause their amount depends on template parameters */\r\n\r\n        polynoms[0].Init(ID_MSG_IN, offset, enc_len, memptr);\r\n        offset += enc_len;\r\n\r\n        polynoms[1].Init(ID_MSG_OUT, offset, enc_len, memptr);\r\n        offset += enc_len;\r\n\r\n        for(uint8_t i = ID_GENERATOR; i < ID_MSG_E; i++) {\r\n            polynoms[i].Init(i, offset, poly_len, memptr);\r\n            offset += poly_len;\r\n        }\r\n\r\n        polynoms[5].Init(ID_MSG_E, offset, enc_len, memptr);\r\n        offset += enc_len;\r\n\r\n        for(uint8_t i = ID_TPOLY3; i < ID_ERR_EVAL+2; i++) {\r\n            polynoms[i].Init(i, offset, poly_len, memptr);\r\n            offset += poly_len;\r\n        }\r\n    }\r\n\r\n    ~ReedSolomon() {\r\n        // Dummy destructor, gcc-generated one crashes program\r\n        memory = NULL;\r\n    }\r\n\r\n    /* @brief Message block encoding\r\n     * @param *src - input message buffer      (msg_length size)\r\n     * @param *dst - output buffer for ecc     (ecc_length size at least) */\r\n     void EncodeBlock(const void* src, void* dst) {\r\n        assert(msg_length + ecc_length < 256);\r\n\r\n        /* Generator cache, it dosn't change for one template parameters */\r\n        static uint8_t generator_cache[ecc_length+1] = {0};\r\n        static bool    generator_cached = false;\r\n\r\n        /* Allocating memory on stack for polynomials storage */\r\n        uint8_t stack_memory[MSG_CNT * msg_length + POLY_CNT * ecc_length * 2];\r\n        this->memory = stack_memory;\r\n\r\n        const uint8_t* src_ptr = (const uint8_t*) src;\r\n        uint8_t* dst_ptr = (uint8_t*) dst;\r\n\r\n        Poly *msg_in  = &polynoms[ID_MSG_IN];\r\n        Poly *msg_out = &polynoms[ID_MSG_OUT];\r\n        Poly *gen     = &polynoms[ID_GENERATOR];\r\n\r\n        // Weird shit, but without resetting msg_in it simply doesn't work\r\n        msg_in->Reset();\r\n        msg_out->Reset();\r\n\r\n        // Using cached generator or generating new one\r\n        if(generator_cached) {\r\n            gen->Set(generator_cache, sizeof(generator_cache));\r\n        } else {\r\n            GeneratorPoly();\r\n            memcpy(generator_cache, gen->ptr(), gen->length);\r\n            generator_cached = true;\r\n        }\r\n\r\n        // Copying input message to internal polynomial\r\n        msg_in->Set(src_ptr, msg_length);\r\n        msg_out->Set(src_ptr, msg_length);\r\n        msg_out->length = msg_in->length + ecc_length;\r\n\r\n        // Here all the magic happens\r\n        uint8_t coef = 0; // cache\r\n        for(uint8_t i = 0; i < msg_length; i++){\r\n            coef = msg_out->at(i);\r\n            if(coef != 0){\r\n                for(uint32_t j = 1; j < gen->length; j++){\r\n                    msg_out->at(i+j) ^= gf::mul(gen->at(j), coef);\r\n                }\r\n            }\r\n        }\r\n\r\n        // Copying ECC to the output buffer\r\n        memcpy(dst_ptr, msg_out->ptr()+msg_length, ecc_length * sizeof(uint8_t));\r\n    }\r\n\r\n    /* @brief Message encoding\r\n     * @param *src - input message buffer      (msg_length size)\r\n     * @param *dst - output buffer             (msg_length + ecc_length size at least) */\r\n    void Encode(const void* src, void* dst) {\r\n        uint8_t* dst_ptr = (uint8_t*) dst;\r\n\r\n        // Copying message to the output buffer\r\n        memcpy(dst_ptr, src, msg_length * sizeof(uint8_t));\r\n\r\n        // Calling EncodeBlock to write ecc to out[ut buffer\r\n        EncodeBlock(src, dst_ptr+msg_length);\r\n    }\r\n\r\n    /* @brief Message block decoding\r\n     * @param *src         - encoded message buffer   (msg_length size)\r\n     * @param *ecc         - ecc buffer               (ecc_length size)\r\n     * @param *msg_out     - output buffer            (msg_length size at least)\r\n     * @param *erase_pos   - known errors positions\r\n     * @param erase_count  - count of known errors\r\n     * @return RESULT_SUCCESS if successful, error code otherwise */\r\n     int DecodeBlock(const void* src, const void* ecc, void* dst, uint8_t* erase_pos = NULL, size_t erase_count = 0) {\r\n        assert(msg_length + ecc_length < 256);\r\n\r\n        const uint8_t *src_ptr = (const uint8_t*) src;\r\n        const uint8_t *ecc_ptr = (const uint8_t*) ecc;\r\n        uint8_t *dst_ptr = (uint8_t*) dst;\r\n\r\n        const uint8_t src_len = msg_length + ecc_length;\r\n        const uint8_t dst_len = msg_length;\r\n\r\n        bool ok;\r\n\r\n        /* Allocation memory on stack */\r\n        uint8_t stack_memory[MSG_CNT * msg_length + POLY_CNT * ecc_length * 2];\r\n        this->memory = stack_memory;\r\n\r\n        Poly *msg_in  = &polynoms[ID_MSG_IN];\r\n        Poly *msg_out = &polynoms[ID_MSG_OUT];\r\n        Poly *epos    = &polynoms[ID_ERASURES];\r\n\r\n        // Copying message to polynomials memory\r\n        msg_in->Set(src_ptr, msg_length);\r\n        msg_in->Set(ecc_ptr, ecc_length, msg_length);\r\n        msg_out->Copy(msg_in);\r\n\r\n        // Copying known errors to polynomial\r\n        if(erase_pos == NULL) {\r\n            epos->length = 0;\r\n        } else {\r\n            epos->Set(erase_pos, erase_count);\r\n            for(uint8_t i = 0; i < epos->length; i++){\r\n                msg_in->at(epos->at(i)) = 0;\r\n            }\r\n        }\r\n\r\n        // Too many errors\r\n        if(epos->length > ecc_length) return 1;\r\n\r\n        Poly *synd   = &polynoms[ID_SYNDROMES];\r\n        Poly *eloc   = &polynoms[ID_ERRORS_LOC];\r\n        Poly *reloc  = &polynoms[ID_TPOLY1];\r\n        Poly *err    = &polynoms[ID_ERRORS];\r\n        Poly *forney = &polynoms[ID_FORNEY];\r\n\r\n        // Calculating syndrome\r\n        CalcSyndromes(msg_in);\r\n\r\n        // Checking for errors\r\n        bool has_errors = false;\r\n        for(uint8_t i = 0; i < synd->length; i++) {\r\n            if(synd->at(i) != 0) {\r\n                has_errors = true;\r\n                break;\r\n            }\r\n        }\r\n\r\n        // Going to exit if no errors\r\n        if(!has_errors) goto return_corrected_msg;\r\n\r\n        CalcForneySyndromes(synd, epos, src_len);\r\n        FindErrorLocator(forney, NULL, epos->length);\r\n\r\n        // Reversing syndrome\r\n        // TODO optimize through special Poly flag\r\n        reloc->length = eloc->length;\r\n        for(int8_t i = eloc->length-1, j = 0; i >= 0; i--, j++){\r\n            reloc->at(j) = eloc->at(i);\r\n        }\r\n\r\n        // Find errors\r\n        ok = FindErrors(reloc, src_len);\r\n        if(!ok) return 1;\r\n\r\n        // Error happened while finding errors (so helpful :D)\r\n        if(err->length == 0) return 1;\r\n\r\n        /* Adding found errors with known */\r\n        for(uint8_t i = 0; i < err->length; i++) {\r\n            epos->Append(err->at(i));\r\n        }\r\n\r\n        // Correcting errors\r\n        CorrectErrata(synd, epos, msg_in);\r\n\r\n    return_corrected_msg:\r\n        // Writing corrected message to output buffer\r\n        msg_out->length = dst_len;\r\n        memcpy(dst_ptr, msg_out->ptr(), msg_out->length * sizeof(uint8_t));\r\n        return 0;\r\n    }\r\n\r\n    /* @brief Message block decoding\r\n     * @param *src         - encoded message buffer   (msg_length + ecc_length size)\r\n     * @param *msg_out     - output buffer            (msg_length size at least)\r\n     * @param *erase_pos   - known errors positions\r\n     * @param erase_count  - count of known errors\r\n     * @return RESULT_SUCCESS if successful, error code otherwise */\r\n     int Decode(const void* src, void* dst, uint8_t* erase_pos = NULL, size_t erase_count = 0) {\r\n         const uint8_t *src_ptr = (const uint8_t*) src;\r\n         const uint8_t *ecc_ptr = src_ptr + msg_length;\r\n\r\n         return DecodeBlock(src, ecc_ptr, dst, erase_pos, erase_count);\r\n     }\r\n\r\n#ifndef RS_DEBUG\r\nprivate:\r\n#endif\r\n\r\n    enum POLY_ID {\r\n        ID_MSG_IN = 0,\r\n        ID_MSG_OUT,\r\n        ID_GENERATOR,   // 3\r\n        ID_TPOLY1,      // T for Temporary\r\n        ID_TPOLY2,\r\n\r\n        ID_MSG_E,       // 5\r\n\r\n        ID_TPOLY3,     // 6\r\n        ID_TPOLY4,\r\n\r\n        ID_SYNDROMES,\r\n        ID_FORNEY,\r\n\r\n        ID_ERASURES_LOC,\r\n        ID_ERRORS_LOC,\r\n\r\n        ID_ERASURES,\r\n        ID_ERRORS,\r\n\r\n        ID_COEF_POS,\r\n        ID_ERR_EVAL\r\n    };\r\n\r\n    // Pointer for polynomials memory on stack\r\n    uint8_t* memory;\r\n    Poly polynoms[MSG_CNT + POLY_CNT];\r\n\r\n    void GeneratorPoly() {\r\n        Poly *gen = polynoms + ID_GENERATOR;\r\n        gen->at(0) = 1;\r\n        gen->length = 1;\r\n\r\n        Poly *mulp = polynoms + ID_TPOLY1;\r\n        Poly *temp = polynoms + ID_TPOLY2;\r\n        mulp->length = 2;\r\n\r\n        for(int8_t i = 0; i < ecc_length; i++){\r\n            mulp->at(0) = 1;\r\n            mulp->at(1) = gf::pow(2, i);\r\n\r\n            gf::poly_mul(gen, mulp, temp);\r\n\r\n            gen->Copy(temp);\r\n        }\r\n    }\r\n\r\n    void CalcSyndromes(const Poly *msg) {\r\n        Poly *synd = &polynoms[ID_SYNDROMES];\r\n        synd->length = ecc_length+1;\r\n        synd->at(0) = 0;\r\n        for(uint8_t i = 1; i < ecc_length+1; i++){\r\n            synd->at(i) = gf::poly_eval(msg, gf::pow(2, i-1));\r\n        }\r\n    }\r\n\r\n    void FindErrataLocator(const Poly *epos) {\r\n        Poly *errata_loc = &polynoms[ID_ERASURES_LOC];\r\n        Poly *mulp = &polynoms[ID_TPOLY1];\r\n        Poly *addp = &polynoms[ID_TPOLY2];\r\n        Poly *apol = &polynoms[ID_TPOLY3];\r\n        Poly *temp = &polynoms[ID_TPOLY4];\r\n\r\n        errata_loc->length = 1;\r\n        errata_loc->at(0)  = 1;\r\n\r\n        mulp->length = 1;\r\n        addp->length = 2;\r\n\r\n        for(uint8_t i = 0; i < epos->length; i++){\r\n            mulp->at(0) = 1;\r\n            addp->at(0) = gf::pow(2, epos->at(i));\r\n            addp->at(1) = 0;\r\n\r\n            gf::poly_add(mulp, addp, apol);\r\n            gf::poly_mul(errata_loc, apol, temp);\r\n\r\n            errata_loc->Copy(temp);\r\n        }\r\n    }\r\n\r\n    void FindErrorEvaluator(const Poly *synd, const Poly *errata_loc, Poly *dst, uint8_t ecclen) {\r\n        Poly *mulp = &polynoms[ID_TPOLY1];\r\n        gf::poly_mul(synd, errata_loc, mulp);\r\n\r\n        Poly *divisor = &polynoms[ID_TPOLY2];\r\n        divisor->length = ecclen+2;\r\n\r\n        divisor->Reset();\r\n        divisor->at(0) = 1;\r\n\r\n        gf::poly_div(mulp, divisor, dst);\r\n    }\r\n\r\n    void CorrectErrata(const Poly *synd, const Poly *err_pos, const Poly *msg_in) {\r\n        Poly *c_pos     = &polynoms[ID_COEF_POS];\r\n        Poly *corrected = &polynoms[ID_MSG_OUT];\r\n        c_pos->length = err_pos->length;\r\n\r\n        for(uint8_t i = 0; i < err_pos->length; i++)\r\n            c_pos->at(i) = msg_in->length - 1 - err_pos->at(i);\r\n\r\n        /* uses t_poly 1, 2, 3, 4 */\r\n        FindErrataLocator(c_pos);\r\n        Poly *errata_loc = &polynoms[ID_ERASURES_LOC];\r\n\r\n        /* reversing syndromes */\r\n        Poly *rsynd = &polynoms[ID_TPOLY3];\r\n        rsynd->length = synd->length;\r\n\r\n        for(int8_t i = synd->length-1, j = 0; i >= 0; i--, j++) {\r\n            rsynd->at(j) = synd->at(i);\r\n        }\r\n\r\n        /* getting reversed error evaluator polynomial */\r\n        Poly *re_eval = &polynoms[ID_TPOLY4];\r\n\r\n        /* uses T_POLY 1, 2 */\r\n        FindErrorEvaluator(rsynd, errata_loc, re_eval, errata_loc->length-1);\r\n\r\n        /* reversing it back */\r\n        Poly *e_eval = &polynoms[ID_ERR_EVAL];\r\n        e_eval->length = re_eval->length;\r\n        for(int8_t i = re_eval->length-1, j = 0; i >= 0; i--, j++) {\r\n            e_eval->at(j) = re_eval->at(i);\r\n        }\r\n\r\n        Poly *X = &polynoms[ID_TPOLY1]; /* this will store errors positions */\r\n        X->length = 0;\r\n\r\n        int16_t l;\r\n        for(uint8_t i = 0; i < c_pos->length; i++){\r\n            l = 255 - c_pos->at(i);\r\n            X->Append(gf::pow(2, -l));\r\n        }\r\n\r\n        /* Magnitude polynomial\r\n           Shit just got real */\r\n        Poly *E = &polynoms[ID_MSG_E];\r\n        E->Reset();\r\n        E->length = msg_in->length;\r\n\r\n        uint8_t Xi_inv;\r\n\r\n        Poly *err_loc_prime_temp = &polynoms[ID_TPOLY2];\r\n\r\n        uint8_t err_loc_prime;\r\n        uint8_t y;\r\n\r\n        for(uint8_t i = 0; i < X->length; i++){\r\n            Xi_inv = gf::inverse(X->at(i));\r\n\r\n            err_loc_prime_temp->length = 0;\r\n            for(uint8_t j = 0; j < X->length; j++){\r\n                if(j != i){\r\n                    err_loc_prime_temp->Append(gf::sub(1, gf::mul(Xi_inv, X->at(j))));\r\n                }\r\n            }\r\n\r\n            err_loc_prime = 1;\r\n            for(uint8_t j = 0; j < err_loc_prime_temp->length; j++){\r\n                err_loc_prime = gf::mul(err_loc_prime, err_loc_prime_temp->at(j));\r\n            }\r\n\r\n            y = gf::poly_eval(re_eval, Xi_inv);\r\n            y = gf::mul(gf::pow(X->at(i), 1), y);\r\n\r\n            E->at(err_pos->at(i)) = gf::div(y, err_loc_prime);\r\n        }\r\n\r\n        gf::poly_add(msg_in, E, corrected);\r\n    }\r\n\r\n    bool FindErrorLocator(const Poly *synd, Poly *erase_loc = NULL, size_t erase_count = 0) {\r\n        Poly *error_loc = &polynoms[ID_ERRORS_LOC];\r\n        Poly *err_loc   = &polynoms[ID_TPOLY1];\r\n        Poly *old_loc   = &polynoms[ID_TPOLY2];\r\n        Poly *temp      = &polynoms[ID_TPOLY3];\r\n        Poly *temp2     = &polynoms[ID_TPOLY4];\r\n\r\n        if(erase_loc != NULL) {\r\n            err_loc->Copy(erase_loc);\r\n            old_loc->Copy(erase_loc);\r\n        } else {\r\n            err_loc->length = 1;\r\n            old_loc->length = 1;\r\n            err_loc->at(0)  = 1;\r\n            old_loc->at(0)  = 1;\r\n        }\r\n\r\n        uint8_t synd_shift = 0;\r\n        if(synd->length > ecc_length) {\r\n            synd_shift = synd->length - ecc_length;\r\n        }\r\n\r\n        uint8_t K = 0;\r\n        uint8_t delta = 0;\r\n        uint8_t index;\r\n\r\n        for(uint8_t i = 0; i < ecc_length - erase_count; i++){\r\n            if(erase_loc != NULL)\r\n                K = erase_count + i + synd_shift;\r\n            else\r\n                K = i + synd_shift;\r\n\r\n            delta = synd->at(K);\r\n            for(uint8_t j = 1; j < err_loc->length; j++) {\r\n                index = err_loc->length - j - 1;\r\n                delta ^= gf::mul(err_loc->at(index), synd->at(K-j));\r\n            }\r\n\r\n            old_loc->Append(0);\r\n\r\n            if(delta != 0) {\r\n                if(old_loc->length > err_loc->length) {\r\n                    gf::poly_scale(old_loc, temp, delta);\r\n                    gf::poly_scale(err_loc, old_loc, gf::inverse(delta));\r\n                    err_loc->Copy(temp);\r\n                }\r\n                gf::poly_scale(old_loc, temp, delta);\r\n                gf::poly_add(err_loc, temp, temp2);\r\n                err_loc->Copy(temp2);\r\n            }\r\n        }\r\n\r\n        uint32_t shift = 0;\r\n        while(err_loc->length && err_loc->at(shift) == 0) shift++;\r\n\r\n        uint32_t errs = err_loc->length - shift - 1;\r\n        if(((errs - erase_count) * 2 + erase_count) > ecc_length){\r\n            return false; /* Error count is greater than we can fix! */\r\n        }\r\n\r\n        memcpy(error_loc->ptr(), err_loc->ptr() + shift, (err_loc->length - shift) * sizeof(uint8_t));\r\n        error_loc->length = (err_loc->length - shift);\r\n        return true;\r\n    }\r\n\r\n    bool FindErrors(const Poly *error_loc, size_t msg_in_size) {\r\n        Poly *err = &polynoms[ID_ERRORS];\r\n\r\n        uint8_t errs = error_loc->length - 1;\r\n        err->length = 0;\r\n\r\n        for(uint8_t i = 0; i < msg_in_size; i++) {\r\n            if(gf::poly_eval(error_loc, gf::pow(2, i)) == 0) {\r\n                err->Append(msg_in_size - 1 - i);\r\n            }\r\n        }\r\n\r\n        /* Sanity check:\r\n         * the number of err/errata positions found\r\n         * should be exactly the same as the length of the errata locator polynomial */\r\n        if(err->length != errs)\r\n            /* couldn't find error locations */\r\n            return false;\r\n        return true;\r\n    }\r\n\r\n    void CalcForneySyndromes(const Poly *synd, const Poly *erasures_pos, size_t msg_in_size) {\r\n        Poly *erase_pos_reversed = &polynoms[ID_TPOLY1];\r\n        Poly *forney_synd = &polynoms[ID_FORNEY];\r\n        erase_pos_reversed->length = 0;\r\n\r\n        for(uint8_t i = 0; i < erasures_pos->length; i++){\r\n            erase_pos_reversed->Append(msg_in_size - 1 - erasures_pos->at(i));\r\n        }\r\n\r\n        forney_synd->Reset();\r\n        forney_synd->Set(synd->ptr()+1, synd->length-1);\r\n\r\n        uint8_t x;\r\n        for(uint8_t i = 0; i < erasures_pos->length; i++) {\r\n            x = gf::pow(2, erase_pos_reversed->at(i));\r\n            for(int8_t j = 0; j < forney_synd->length - 1; j++){\r\n                forney_synd->at(j) = gf::mul(forney_synd->at(j), x) ^ forney_synd->at(j+1);\r\n            }\r\n        }\r\n    }\r\n};\r\n\r\n}\r\n\r\n#endif // RS_HPP\r\n\r\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(RStest C CXX)\n\ninclude(CheckCXXCompilerFlag)\nCHECK_CXX_COMPILER_FLAG(\"-std=c++11\" COMPILER_SUPPORTS_CXX11)\nCHECK_CXX_COMPILER_FLAG(\"-std=c++0x\" COMPILER_SUPPORTS_CXX0X)\n\nif(COMPILER_SUPPORTS_CXX11)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\nelseif(COMPILER_SUPPORTS_CXX0X)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++0x\")\nelse()\n    message(STATUS \"The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.\")\nendif()\n\ninclude_directories(${RS_INCLUDE_DIRS})\n\nfile(GLOB CPP_FILES *.cpp)\nadd_executable(${PROJECT_NAME} ${CPP_FILES})\n\n\n"
  },
  {
    "path": "tests/gftest.cpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include \"gftest.hpp\"\n\nReport\nGFtest::run_tests() {\n    bool (*tests[])(std::string&) = {\n        test_add,\n        test_mul,\n        test_div,\n        test_pow,\n        test_inverse,\n        test_poly_scale,\n        test_poly_add,\n        test_poly_mul,\n        test_poly_div,\n        test_poly_eval\n    };\n\n    Report rep = {10, 0};\n\n    for(uint i = 0; i < rep.overall; i++) {\n        if(test(tests[i])) rep.passed++;\n    }\n\n    std::cout << \"GFTest: \" << rep.passed << \"/\" << rep.overall << \" tests passed.\\n\\n\";\n\n    return rep;\n}\n\nbool\nGFtest::test_add(std::string &name) {\n    INIT_TESTCASE;\n\n    const uint testcount = 256;\n    uint8_t* leftops  = (uint8_t*) RS::gf::log;\n    uint8_t* rightops = (uint8_t*) RS::gf::exp;\n\n    uint8_t answers[testcount] = {\n        1, 2, 5, 17, 18, 18, 90, 70, 30, 229, 71, 6, 214, 239, 212, 109, 72, 252, 205, 84, 128, 248, 5, 72, 147, 194, 111, 244, 208, 56,\n        44, 177, 152, 173, 43, 179, 196, 110, 155, 20, 95, 71, 59, 173, 30, 211, 29, 102, 91, 57, 199, 119, 126, 15, 169, 25, 148, 32,\n        96, 170, 244, 139, 172, 7, 89, 1, 234, 160, 255, 242, 110, 65, 135, 82, 172, 188, 14, 173, 90, 120, 203, 55, 71, 117, 228, 64,\n        106, 194, 15, 51, 204, 255, 216, 142, 55, 162, 199, 237, 245, 37, 210, 106, 58, 230, 102, 32, 28, 60, 42, 56, 221, 243, 75, 65, 165,\n        227, 242, 248, 190, 184, 117, 162, 9, 105, 228, 192, 193, 155, 130, 103, 238, 171, 52, 237, 185, 164, 40, 212, 255, 175, 181, 208, 212,\n        76, 75, 232, 3, 94, 116, 28, 225, 214, 88, 214, 171, 171, 199, 245, 62, 93, 209, 238, 110, 56, 83, 45, 240, 179, 108, 98, 64, 1, 167,\n        10, 79, 158, 17, 141, 120, 224, 130, 27, 63, 90, 17, 11, 87, 143, 226, 58, 239, 227, 157, 52, 113, 188, 127, 246, 163, 120, 216, 47,\n        57, 12, 162, 171, 60, 80, 61, 3, 98, 224, 80, 111, 172, 69, 56, 251, 173, 231, 23, 137, 180, 83, 217, 125, 23, 32, 161, 211, 84, 164, 252,\n        6, 237, 0, 177, 254, 39, 193, 99, 246, 101, 148, 28, 14, 98, 107, 111, 224, 152, 50, 5, 23, 214, 174\n    };\n\n    for(uint i = 0; i < testcount; i++) {\n        SUBTEST(compare(RS::gf::add(leftops[i], rightops[i]), answers[i]));\n    }\n\n    RETURN;\n}\n\n// TODO Implement other tests\n\nbool\nGFtest::test_mul(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_div(std::string &name) {\n    INIT_TESTCASE;\n\n\tSUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_pow(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_inverse(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_poly_scale(std::string &name) {    \n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_poly_add(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_poly_mul(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_poly_div(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\nbool\nGFtest::test_poly_eval(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n"
  },
  {
    "path": "tests/gftest.hpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#ifndef GFTEST_H\n#define GFTEST_H\n#include \"testsuite.hpp\"\n#include <gf.hpp>\n\nclass GFtest : public TestSuite {\npublic:\n    static Report run_tests();\n\n    static bool test_add(std::string& name);\n    static bool test_sub(std::string& name);\n    static bool test_mul(std::string& name);\n    static bool test_div(std::string& name);\n    static bool test_pow(std::string& name);\n    static bool test_inverse(std::string& name);\n\n    static bool test_poly_scale(std::string& name);\n    static bool test_poly_add  (std::string& name);\n    static bool test_poly_mul  (std::string& name);\n    static bool test_poly_div  (std::string& name);\n    static bool test_poly_eval (std::string& name);\n};\n\n#endif // GFTEST_H\n"
  },
  {
    "path": "tests/performancetest.cpp",
    "content": "#include \"performancetest.hpp\"\n#include <chrono>\n\nusing namespace std::chrono;\n\nPerformanceTest::Data_t PerformanceTest::data = {};\nRS::ReedSolomon<TEST_DATA_SIZE, TEST_ECC_SIZE> PerformanceTest::rs;\n\nPReport\nPerformanceTest::run_tests(uint32_t laps_cnt, uint32_t cnt_per_lap) {\n    assert(laps_cnt < 64 && cnt_per_lap < 64);\n    std::cout << \"Starting performance tests\\n\";\n    PReport enc_rep;\n    PReport dec_rep;\n\n    /// Init data\n    for(uint32_t i = 0; i < TEST_DATA_SIZE; i++) {\n        data.msg[i] = i;\n        data.err_msg[i] = i;\n    }\n\n    /// Prepare corrupted message\n    for(uint32_t i = 0; i < TEST_ECC_SIZE / 2; i++) {\n        data.err_msg[i+1] = 0;\n    }\n\n    auto lap_time = []() -> uint32_t {\n        static milliseconds last_time = duration_cast<milliseconds>(\n            system_clock::now().time_since_epoch()\n        );\n\n        milliseconds time = duration_cast<milliseconds>(\n            system_clock::now().time_since_epoch()\n        );\n\n        milliseconds diff = time - last_time;\n        last_time = time;\n\n        return diff.count();\n    };\n\n    /// Run 3 times\n    for(uint32_t i = 0; i < laps_cnt; i++) {\n        lap_time(); /// init static counter\n        for(uint32_t i = 0; i < cnt_per_lap; i++) {\n            encoder_atom();\n        }\n        enc_rep.laps[i] = lap_time();\n\n        lap_time(); /// init static counter\n        for(uint32_t i = 0; i < cnt_per_lap; i++) {\n            decoder_atom();\n        }\n        dec_rep.laps[i] = lap_time();\n    }\n\n    /// Calculate average\n    enc_rep.average[0] = 0;\n    dec_rep.average[0] = 0;\n    for(uint32_t i = 0; i < laps_cnt; i++) {\n        enc_rep.average[0] += enc_rep.laps[i];\n        dec_rep.average[0] += dec_rep.laps[i];\n    }\n    enc_rep.average[0] /= laps_cnt;\n    dec_rep.average[0] /= laps_cnt;\n\n    return PReport {\n        .overall = enc_rep.average[0] + dec_rep.average[0],\n        .average = {enc_rep.average[0], dec_rep.average[0]},\n        .count = 2\n    };\n}\n\nvoid\nPerformanceTest::encoder_atom() {\n    rs.EncodeBlock(data.msg, data.ecc);\n}\n\nvoid\nPerformanceTest::decoder_atom() {\n    rs.DecodeBlock(data.err_msg, data.ecc, data.rep_msg);\n}\n"
  },
  {
    "path": "tests/performancetest.hpp",
    "content": "#ifndef PERFORMANCETEST_HPP\n#define PERFORMANCETEST_HPP\n#include \"testsuite.hpp\"\n#include \"string.h\"\n#include \"rs.hpp\"\n\n#define TEST_DATA_SIZE 200\n#define TEST_ECC_SIZE  40\n\nclass PerformanceTest : public TestSuite\n{\npublic:\n    static PReport run_tests(uint32_t laps_cnt, uint32_t cnt_per_lap);\n\n    static void encoder_atom();\n    static void decoder_atom();\n\nprivate:\n    static struct Data_t {\n        uint8_t msg    [TEST_DATA_SIZE];\n        uint8_t err_msg[TEST_DATA_SIZE];\n        uint8_t rep_msg[TEST_DATA_SIZE];\n        uint8_t ecc[TEST_ECC_SIZE];\n    } data;\n\n    static RS::ReedSolomon<TEST_DATA_SIZE, TEST_ECC_SIZE> rs;\n};\n\n#endif // PERFORMANCETEST_H\n"
  },
  {
    "path": "tests/rstest.cpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include \"rstest.hpp\"\n#include <rs.hpp>\n\nReport\nRStest::run_tests() {\n    bool (*tests[])(std::string&) = {\n        test_encode,\n        test_decode,\n        test_stress\n    };\n\n    Report rep = {3, 0};\n\n    for(uint i = 0; i < rep.overall; i++) {\n        if(test(tests[i])) rep.passed++;\n    }\n\n    std::cout << \"RSTest: \" << rep.passed << \"/\" << rep.overall << \" tests passed.\\n\\n\";\n\n    return rep;\n}\n\nbool\nRStest::test_encode(std::string &name) {\n    INIT_TESTCASE;\n    RS::ReedSolomon<30, 8> rs;\n\n    char message[30];\n    char encoded[38];\n\n    uint8_t right[38] = {\n        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n        99, 26, 219, 193, 9, 94, 186, 143\n    };\n\n    memcpy(message, right, 30);\n\n    rs.Encode(message, encoded);\n\n    SUBTEST(compare((uint8_t*)encoded, (uint8_t*)right, 38));\n    RETURN;\n}\n\nbool\nRStest::test_decode(std::string &name) {\n    INIT_TESTCASE;\n    RS::ReedSolomon<30, 8> rs;\n\n    char message[30];\n    char right[30] = {\n        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29\n    };\n\n    // Test clean message\n    uint8_t clean[38] = {\n        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n        99, 26, 219, 193, 9, 94, 186, 143\n    };\n    SUBTEST(rs.Decode(clean, message) == 0);\n    SUBTEST(compare(message, right, 30));\n\n    // Test corrupted message\n    uint8_t corrupted[38] = {\n        0, 1, 2, 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, 13, 14, 0, 16, 17, 18, 19, 0, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n        99, 26, 219, 193, 9, 94, 0, 143\n    };\n\n    SUBTEST(rs.Decode(corrupted, message) == 0);\n    SUBTEST(compare(message, right, 30));\n\n    RETURN\n}\n\n// TODO make complex encoder-decder test\n\nbool\nRStest::test_stress(std::string &name) {\n    INIT_TESTCASE;\n\n    SUBTEST(true);\n\n    RETURN;\n}\n\n"
  },
  {
    "path": "tests/rstest.hpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#ifndef RSTEST_H\n#define RSTEST_H\n#include \"testsuite.hpp\"\n#include <rs.hpp>\n\nclass RStest : public TestSuite\n{\npublic:\n    static Report run_tests();\n\n    static bool test_encode(std::string& name);\n    static bool test_decode(std::string& name);\n    static bool test_stress(std::string& name);\n};\n\n#endif // RSTEST_H\n"
  },
  {
    "path": "tests/tests.cpp",
    "content": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include <iostream>\n#include \"gftest.hpp\"\n#include \"rstest.hpp\"\n#include \"performancetest.hpp\"\n\nusing namespace std;\n\n#define COUNT_PER_PTEST_LAP 63\n#define COUNT_OF_LAPS       22\n\nint main() {\n    GFtest::run_tests();\n    RStest::run_tests();\n\n    PReport performance = PerformanceTest::run_tests(COUNT_OF_LAPS, COUNT_PER_PTEST_LAP);\n    std::cout << \"Average of \" << COUNT_OF_LAPS << \"x\" << COUNT_PER_PTEST_LAP << \" for encoder: \" << performance.average[0] << \"ms\\n\";\n    std::cout << \"Average of \" << COUNT_OF_LAPS << \"x\" << COUNT_PER_PTEST_LAP << \" for decoder: \" << performance.average[1] << \"ms\\n\";\n}\n\n"
  },
  {
    "path": "x32.cmake_toolchain",
    "content": "set(CMAKE_SYSTEM_VERSION 1) \nset(CMAKE_CXX_COMPILER_ARG1 \"-m32\")\nset(CMAKE_C_COMPILER_ARG1 \"-m32\")\n\n"
  }
]