Repository: mersinvald/Reed-Solomon
Branch: master
Commit: 96b9a08d245b
Files: 22
Total size: 45.8 KB
Directory structure:
gitextract_c0tv96n1/
├── .gitexcludes
├── .github/
│ └── workflows/
│ └── codeql-analysis.yml
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
├── examples/
│ ├── CMakeLists.txt
│ └── example1.cpp
├── include/
│ ├── gf.hpp
│ ├── poly.hpp
│ └── rs.hpp
├── tests/
│ ├── CMakeLists.txt
│ ├── gftest.cpp
│ ├── gftest.hpp
│ ├── performancetest.cpp
│ ├── performancetest.hpp
│ ├── rstest.cpp
│ ├── rstest.hpp
│ └── tests.cpp
└── x32.cmake_toolchain
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitexcludes
================================================
./src/libRS.pro.user
./tests/tests.pro.user
./Reed-Solomon.pro.user
================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 12 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['cpp']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
================================================
FILE: .gitignore
================================================
*.so
*.a
*.o
================================================
FILE: .gitmodules
================================================
[submodule "tests/mtest"]
path = tests/mtest
url = git@github.com:mersinvald/mtest.git
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 2.8.10)
project(Reed-Solomon)
# You can tweak some common (for all subprojects) stuff here. For example:
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif ()
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_COLOR_MAKEFILE ON)
# Remove 'lib' prefix for shared libraries on Windows
if (WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif ()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(RS_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include)
# When done tweaking common stuff, configure the components (subprojects).
# NOTE: The order matters! The most independent ones should go first.
add_subdirectory(examples)
add_subdirectory(tests)
================================================
FILE: LICENSE
================================================
Copyright © 2015 Mike Lubinets, github.com/mersinvald
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.
================================================
FILE: Makefile
================================================
all:
mkdir -p build && cd build && cmake ../ && make
x32:
mkdir -p build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=../x32.cmake_toolchain ../ && make
clean:
cd build && make clean && cd .. && rm -rf build
================================================
FILE: README.md
================================================
# Reed-Solomon
Reed Solomon BCH encoder and decoder library
## Overview
This RS implementation was designed for embedded purposes, so all the memory allocations performed on the stack.<br>
If somebody wants to reimplement memory management with heap usage, pull requests are welcome
## Getting the source
If you want only Reed-Solomon code, just clone repository.<br>
If you want to get tests and examples also, do
```
git clone --recursive git@github.com:mersinvald/Reed-Solomon.git
```
## Build
There is no need in building RS library, cause all the implementation is in headers.<br>
To build tests and examples simply run <b>make</b> in the folder with cloned repo and executables will emerge in the
./build folder
## Usage
All the Reed-Solomon code is in folder **include**, you just need to include header <b>rs.hpp</b>
Template class ReedSolomon accepts two template arguments: message length and ecc length. <br>
Simple example: <br>
```
char message[] = "Some very important message ought to be delivered";
const int msglen = sizeof(message);
const int ecclen = 8;
char repaired[msglen];
char encoded[msglen + ecclen];
RS::ReedSolomon<msglen, ecclen> rs;
rs.Encode(message, encoded);
// Corrupting first 8 bytes of message (any 4 bytes can be repaired, no more)
for(uint i = 0; i < ecclen / 2; i++) {
encoded[i] = 'E';
}
rs.Decode(encoded, repaired);
std::cout << "Original: " << message << std::endl;
std::cout << "Corrupted: " << encoded << std::endl;
std::cout << "Repaired: " << repaired << std::endl;
std::cout << ((memcmp(message, repaired, msglen) == 0) ? "SUCCESS" : "FAILURE") << std::endl;
```
## Regards
Huge thanks to authors of [wikiversity page about Reed-Solomon BCH](https://en.wikiversity.org/wiki/Reed–Solomon_codes_for_coders)
## Related projects
[Arduino Reed-Solomon Forward Error Correction library](https://github.com/simonyipeter/Arduino-FEC)
================================================
FILE: examples/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 2.8.10)
project(examples CXX)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
include_directories(${RS_INCLUDE_DIRS})
add_executable(example1 example1.cpp)
================================================
FILE: examples/example1.cpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#include <iostream>
#include "rs.hpp"
using namespace std;
#define ECC_LENGTH 8
int main() {
char message[] = "Some very important message ought to be delivered";
const int msglen = sizeof(message);
char repaired[msglen];
char encoded[msglen + ECC_LENGTH];
RS::ReedSolomon<msglen, ECC_LENGTH> rs;
rs.Encode(message, encoded);
// Corrupting first 8 bytes of message (any 8 bytes can be repaired)
for(uint i = 0; i < ECC_LENGTH / 2; i++) {
encoded[i] = 'E';
}
rs.Decode(encoded, repaired);
std::cout << "Original: " << message << std::endl;
std::cout << "Corrupted: " << encoded << std::endl;
std::cout << "Repaired: " << repaired << std::endl;
std::cout << ((memcmp(message, repaired, msglen) == 0) ? "SUCCESS" : "FAILURE") << std::endl;
return 0;
}
================================================
FILE: include/gf.hpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#ifndef GF_H
#define GF_H
#include <stdint.h>
#include <string.h>
#include "poly.hpp"
#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT
#include <assert.h>
#else
#define assert(dummy)
#endif
namespace RS {
namespace gf {
/* GF tables pre-calculated for 0x11d primitive polynomial */
const uint8_t exp[255] = {
0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c,
0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x3, 0x6, 0xc, 0x18, 0x30, 0x60, 0xc0, 0x9d,
0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 0x46,
0x8c, 0x5, 0xa, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 0x5f,
0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0xf, 0x1e, 0x3c, 0x78, 0xf0, 0xfd,
0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 0xd9,
0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0xd, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 0x81,
0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 0x85,
0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 0xa8,
0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 0xe6,
0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 0xe3,
0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 0x82,
0x19, 0x32, 0x64, 0xc8, 0x8d, 0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 0x51,
0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x9, 0x12,
0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0xb, 0x16, 0x2c,
0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e
};
const uint8_t log[256] = {
0x0, 0x0, 0x1, 0x19, 0x2, 0x32, 0x1a, 0xc6, 0x3, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x4,
0x64, 0xe0, 0xe, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x8, 0x4c, 0x71, 0x5,
0x8a, 0x65, 0x2f, 0xe1, 0x24, 0xf, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 0x1d,
0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x9, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 0x6,
0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 0x36,
0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 0x1e,
0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 0xca,
0x5e, 0x9b, 0x9f, 0xa, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 0x7,
0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0xd, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 0xe3,
0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 0x37,
0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 0xf2,
0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 0x1f,
0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0xc, 0x6f, 0xf6, 0x6c,
0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 0xcb,
0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0xb, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 0x4f,
0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
};
/* ################################
* # OPERATIONS OVER GALOIS FIELDS #
* ################################ */
/* @brief Addition in Galois Fields
* @param x - left operand
* @param y - right operand
* @return x + y */
inline uint8_t add(uint8_t x, uint8_t y) {
return x^y;
}
/* ##### GF subtraction ###### */
/* @brief Subtraction in Galois Fields
* @param x - left operand
* @param y - right operand
* @return x - y */
inline uint8_t sub(uint8_t x, uint8_t y) {
return x^y;
}
/* @brief Multiplication in Galois Fields
* @param x - left operand
* @param y - right operand
* @return x * y */
inline uint8_t mul(uint16_t x, uint16_t y){
if (x == 0 || y == 0)
return 0;
return exp[(log[x] + log[y]) % 255];
}
/* @brief Division in Galois Fields
* @param x - dividend
* @param y - divisor
* @return x / y */
inline uint8_t div(uint8_t x, uint8_t y){
assert(y != 0);
if(x == 0) return 0;
return exp[(log[x] + 255 - log[y]) % 255];
}
/* @brief X in power Y w
* @param x - operand
* @param power - power
* @return x^power */
inline uint8_t pow(uint8_t x, intmax_t power){
intmax_t i = log[x];
i *= power;
i %= 255;
if(i < 0) i = i + 255;
return exp[i % 255];
}
/* @brief Inversion in Galois Fields
* @param x - number
* @return inversion of x */
inline uint8_t inverse(uint8_t x){
return exp[(255 - log[x]) % 255]; /* == div(1, x); */
}
/* ##########################
* # POLYNOMIALS OPERATIONS #
* ########################## */
/* @brief Multiplication polynomial by scalar
* @param &p - source polynomial
* @param &newp - destination polynomial
* @param x - scalar */
inline void
poly_scale(const Poly *p, Poly *newp, uint16_t x) {
newp->length = p->length;
for(uint16_t i = 0; i < p->length; i++){
newp->at(i) = mul(p->at(i), x);
}
}
/* @brief Addition of two polynomials
* @param &p - right operand polynomial
* @param &q - left operand polynomial
* @param &newp - destination polynomial */
inline void
poly_add(const Poly *p, const Poly *q, Poly *newp) {
newp->length = poly_max(p->length, q->length);
memset(newp->ptr(), 0, newp->length * sizeof(uint8_t));
for(uint8_t i = 0; i < p->length; i++){
newp->at(i + newp->length - p->length) = p->at(i);
}
for(uint8_t i = 0; i < q->length; i++){
newp->at(i + newp->length - q->length) ^= q->at(i);
}
}
/* @brief Multiplication of two polynomials
* @param &p - right operand polynomial
* @param &q - left operand polynomial
* @param &newp - destination polynomial */
inline void
poly_mul(const Poly *p, const Poly *q, Poly *newp) {
newp->length = p->length + q->length - 1;
memset(newp->ptr(), 0, newp->length * sizeof(uint8_t));
/* Compute the polynomial multiplication (just like the outer product of two vectors,
* we multiply each coefficients of p with all coefficients of q) */
for(uint8_t j = 0; j < q->length; j++){
for(uint8_t i = 0; i < p->length; i++){
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])) */
}
}
}
/* @brief Division of two polynomials
* @param &p - right operand polynomial
* @param &q - left operand polynomial
* @param &newp - destination polynomial */
inline void
poly_div(const Poly *p, const Poly *q, Poly *newp) {
if(p->ptr() != newp->ptr()) {
memcpy(newp->ptr(), p->ptr(), p->length*sizeof(uint8_t));
}
newp->length = p->length;
uint8_t coef;
for(int i = 0; i < (p->length-(q->length-1)); i++){
coef = newp->at(i);
if(coef != 0){
for(uint8_t j = 1; j < q->length; j++){
if(q->at(j) != 0)
newp->at(i+j) ^= mul(q->at(j), coef);
}
}
}
size_t sep = p->length-(q->length-1);
memmove(newp->ptr(), newp->ptr()+sep, (newp->length-sep) * sizeof(uint8_t));
newp->length = newp->length-sep;
}
/* @brief Evaluation of polynomial in x
* @param &p - polynomial to evaluate
* @param x - evaluation point */
inline int8_t
poly_eval(const Poly *p, uint16_t x) {
uint8_t y = p->at(0);
for(uint8_t i = 1; i < p->length; i++){
y = mul(y, x) ^ p->at(i);
}
return y;
}
} /* end of gf namespace */
}
#endif // GF_H
================================================
FILE: include/poly.hpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#ifndef POLY_H
#define POLY_H
#include <stdint.h>
#include <string.h>
#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT
#include <assert.h>
#else
#define assert(dummy)
#endif
namespace RS {
struct Poly {
Poly()
: length(0), _memory(NULL) {}
Poly(uint8_t id, uint16_t offset, uint8_t size) \
: length(0), _id(id), _size(size), _offset(offset), _memory(NULL) {}
/* @brief Append number at the end of polynomial
* @param num - number to append
* @return false if polynomial can't be stretched */
inline bool Append(uint8_t num) {
assert(length+1 < _size);
ptr()[length++] = num;
return true;
}
/* @brief Polynomial initialization */
inline void Init(uint8_t id, uint16_t offset, uint8_t size, uint8_t** memory_ptr) {
this->_id = id;
this->_offset = offset;
this->_size = size;
this->length = 0;
this->_memory = memory_ptr;
}
/* @brief Polynomial memory zeroing */
inline void Reset() {
memset((void*)ptr(), 0, this->_size);
}
/* @brief Copy polynomial to memory
* @param src - source byte-sequence
* @param size - size of polynomial
* @param offset - write offset */
inline void Set(const uint8_t* src, uint8_t len, uint8_t offset = 0) {
assert(src && len <= this->_size-offset);
memcpy(ptr()+offset, src, len * sizeof(uint8_t));
length = len + offset;
}
#define poly_max(a, b) ((a > b) ? (a) : (b))
inline void Copy(const Poly* src) {
length = poly_max(length, src->length);
Set(src->ptr(), length);
}
inline uint8_t& at(uint8_t i) const {
assert(i < _size);
return ptr()[i];
}
inline uint8_t id() const {
return _id;
}
inline uint8_t size() const {
return _size;
}
// Returns pointer to memory of this polynomial
inline uint8_t* ptr() const {
assert(_memory && *_memory);
return (*_memory) + _offset;
}
uint8_t length;
protected:
uint8_t _id;
uint8_t _size; // Size of reserved memory for this polynomial
uint16_t _offset; // Offset in memory
uint8_t** _memory; // Pointer to pointer to memory
};
}
#endif // POLY_H
================================================
FILE: include/rs.hpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#ifndef RS_HPP
#define RS_HPP
#include <string.h>
#include <stdint.h>
#include "poly.hpp"
#include "gf.hpp"
#if !defined RS_DEBUG && !defined __CC_ARM && !defined RS_NO_ASSERT
#include <assert.h>
#else
#define assert(dummy)
#endif
namespace RS {
#define MSG_CNT 3 // message-length polynomials count
#define POLY_CNT 14 // (ecc_length*2)-length polynomials count
template <const uint8_t msg_length, // Message length without correction code
const uint8_t ecc_length> // Length of correction code
class ReedSolomon {
public:
ReedSolomon() {
const uint8_t enc_len = msg_length + ecc_length;
const uint8_t poly_len = ecc_length * 2;
uint8_t** memptr = &memory;
uint16_t offset = 0;
/* Initialize first six polys manually cause their amount depends on template parameters */
polynoms[0].Init(ID_MSG_IN, offset, enc_len, memptr);
offset += enc_len;
polynoms[1].Init(ID_MSG_OUT, offset, enc_len, memptr);
offset += enc_len;
for(uint8_t i = ID_GENERATOR; i < ID_MSG_E; i++) {
polynoms[i].Init(i, offset, poly_len, memptr);
offset += poly_len;
}
polynoms[5].Init(ID_MSG_E, offset, enc_len, memptr);
offset += enc_len;
for(uint8_t i = ID_TPOLY3; i < ID_ERR_EVAL+2; i++) {
polynoms[i].Init(i, offset, poly_len, memptr);
offset += poly_len;
}
}
~ReedSolomon() {
// Dummy destructor, gcc-generated one crashes program
memory = NULL;
}
/* @brief Message block encoding
* @param *src - input message buffer (msg_length size)
* @param *dst - output buffer for ecc (ecc_length size at least) */
void EncodeBlock(const void* src, void* dst) {
assert(msg_length + ecc_length < 256);
/* Generator cache, it dosn't change for one template parameters */
static uint8_t generator_cache[ecc_length+1] = {0};
static bool generator_cached = false;
/* Allocating memory on stack for polynomials storage */
uint8_t stack_memory[MSG_CNT * msg_length + POLY_CNT * ecc_length * 2];
this->memory = stack_memory;
const uint8_t* src_ptr = (const uint8_t*) src;
uint8_t* dst_ptr = (uint8_t*) dst;
Poly *msg_in = &polynoms[ID_MSG_IN];
Poly *msg_out = &polynoms[ID_MSG_OUT];
Poly *gen = &polynoms[ID_GENERATOR];
// Weird shit, but without resetting msg_in it simply doesn't work
msg_in->Reset();
msg_out->Reset();
// Using cached generator or generating new one
if(generator_cached) {
gen->Set(generator_cache, sizeof(generator_cache));
} else {
GeneratorPoly();
memcpy(generator_cache, gen->ptr(), gen->length);
generator_cached = true;
}
// Copying input message to internal polynomial
msg_in->Set(src_ptr, msg_length);
msg_out->Set(src_ptr, msg_length);
msg_out->length = msg_in->length + ecc_length;
// Here all the magic happens
uint8_t coef = 0; // cache
for(uint8_t i = 0; i < msg_length; i++){
coef = msg_out->at(i);
if(coef != 0){
for(uint32_t j = 1; j < gen->length; j++){
msg_out->at(i+j) ^= gf::mul(gen->at(j), coef);
}
}
}
// Copying ECC to the output buffer
memcpy(dst_ptr, msg_out->ptr()+msg_length, ecc_length * sizeof(uint8_t));
}
/* @brief Message encoding
* @param *src - input message buffer (msg_length size)
* @param *dst - output buffer (msg_length + ecc_length size at least) */
void Encode(const void* src, void* dst) {
uint8_t* dst_ptr = (uint8_t*) dst;
// Copying message to the output buffer
memcpy(dst_ptr, src, msg_length * sizeof(uint8_t));
// Calling EncodeBlock to write ecc to out[ut buffer
EncodeBlock(src, dst_ptr+msg_length);
}
/* @brief Message block decoding
* @param *src - encoded message buffer (msg_length size)
* @param *ecc - ecc buffer (ecc_length size)
* @param *msg_out - output buffer (msg_length size at least)
* @param *erase_pos - known errors positions
* @param erase_count - count of known errors
* @return RESULT_SUCCESS if successful, error code otherwise */
int DecodeBlock(const void* src, const void* ecc, void* dst, uint8_t* erase_pos = NULL, size_t erase_count = 0) {
assert(msg_length + ecc_length < 256);
const uint8_t *src_ptr = (const uint8_t*) src;
const uint8_t *ecc_ptr = (const uint8_t*) ecc;
uint8_t *dst_ptr = (uint8_t*) dst;
const uint8_t src_len = msg_length + ecc_length;
const uint8_t dst_len = msg_length;
bool ok;
/* Allocation memory on stack */
uint8_t stack_memory[MSG_CNT * msg_length + POLY_CNT * ecc_length * 2];
this->memory = stack_memory;
Poly *msg_in = &polynoms[ID_MSG_IN];
Poly *msg_out = &polynoms[ID_MSG_OUT];
Poly *epos = &polynoms[ID_ERASURES];
// Copying message to polynomials memory
msg_in->Set(src_ptr, msg_length);
msg_in->Set(ecc_ptr, ecc_length, msg_length);
msg_out->Copy(msg_in);
// Copying known errors to polynomial
if(erase_pos == NULL) {
epos->length = 0;
} else {
epos->Set(erase_pos, erase_count);
for(uint8_t i = 0; i < epos->length; i++){
msg_in->at(epos->at(i)) = 0;
}
}
// Too many errors
if(epos->length > ecc_length) return 1;
Poly *synd = &polynoms[ID_SYNDROMES];
Poly *eloc = &polynoms[ID_ERRORS_LOC];
Poly *reloc = &polynoms[ID_TPOLY1];
Poly *err = &polynoms[ID_ERRORS];
Poly *forney = &polynoms[ID_FORNEY];
// Calculating syndrome
CalcSyndromes(msg_in);
// Checking for errors
bool has_errors = false;
for(uint8_t i = 0; i < synd->length; i++) {
if(synd->at(i) != 0) {
has_errors = true;
break;
}
}
// Going to exit if no errors
if(!has_errors) goto return_corrected_msg;
CalcForneySyndromes(synd, epos, src_len);
FindErrorLocator(forney, NULL, epos->length);
// Reversing syndrome
// TODO optimize through special Poly flag
reloc->length = eloc->length;
for(int8_t i = eloc->length-1, j = 0; i >= 0; i--, j++){
reloc->at(j) = eloc->at(i);
}
// Find errors
ok = FindErrors(reloc, src_len);
if(!ok) return 1;
// Error happened while finding errors (so helpful :D)
if(err->length == 0) return 1;
/* Adding found errors with known */
for(uint8_t i = 0; i < err->length; i++) {
epos->Append(err->at(i));
}
// Correcting errors
CorrectErrata(synd, epos, msg_in);
return_corrected_msg:
// Writing corrected message to output buffer
msg_out->length = dst_len;
memcpy(dst_ptr, msg_out->ptr(), msg_out->length * sizeof(uint8_t));
return 0;
}
/* @brief Message block decoding
* @param *src - encoded message buffer (msg_length + ecc_length size)
* @param *msg_out - output buffer (msg_length size at least)
* @param *erase_pos - known errors positions
* @param erase_count - count of known errors
* @return RESULT_SUCCESS if successful, error code otherwise */
int Decode(const void* src, void* dst, uint8_t* erase_pos = NULL, size_t erase_count = 0) {
const uint8_t *src_ptr = (const uint8_t*) src;
const uint8_t *ecc_ptr = src_ptr + msg_length;
return DecodeBlock(src, ecc_ptr, dst, erase_pos, erase_count);
}
#ifndef RS_DEBUG
private:
#endif
enum POLY_ID {
ID_MSG_IN = 0,
ID_MSG_OUT,
ID_GENERATOR, // 3
ID_TPOLY1, // T for Temporary
ID_TPOLY2,
ID_MSG_E, // 5
ID_TPOLY3, // 6
ID_TPOLY4,
ID_SYNDROMES,
ID_FORNEY,
ID_ERASURES_LOC,
ID_ERRORS_LOC,
ID_ERASURES,
ID_ERRORS,
ID_COEF_POS,
ID_ERR_EVAL
};
// Pointer for polynomials memory on stack
uint8_t* memory;
Poly polynoms[MSG_CNT + POLY_CNT];
void GeneratorPoly() {
Poly *gen = polynoms + ID_GENERATOR;
gen->at(0) = 1;
gen->length = 1;
Poly *mulp = polynoms + ID_TPOLY1;
Poly *temp = polynoms + ID_TPOLY2;
mulp->length = 2;
for(int8_t i = 0; i < ecc_length; i++){
mulp->at(0) = 1;
mulp->at(1) = gf::pow(2, i);
gf::poly_mul(gen, mulp, temp);
gen->Copy(temp);
}
}
void CalcSyndromes(const Poly *msg) {
Poly *synd = &polynoms[ID_SYNDROMES];
synd->length = ecc_length+1;
synd->at(0) = 0;
for(uint8_t i = 1; i < ecc_length+1; i++){
synd->at(i) = gf::poly_eval(msg, gf::pow(2, i-1));
}
}
void FindErrataLocator(const Poly *epos) {
Poly *errata_loc = &polynoms[ID_ERASURES_LOC];
Poly *mulp = &polynoms[ID_TPOLY1];
Poly *addp = &polynoms[ID_TPOLY2];
Poly *apol = &polynoms[ID_TPOLY3];
Poly *temp = &polynoms[ID_TPOLY4];
errata_loc->length = 1;
errata_loc->at(0) = 1;
mulp->length = 1;
addp->length = 2;
for(uint8_t i = 0; i < epos->length; i++){
mulp->at(0) = 1;
addp->at(0) = gf::pow(2, epos->at(i));
addp->at(1) = 0;
gf::poly_add(mulp, addp, apol);
gf::poly_mul(errata_loc, apol, temp);
errata_loc->Copy(temp);
}
}
void FindErrorEvaluator(const Poly *synd, const Poly *errata_loc, Poly *dst, uint8_t ecclen) {
Poly *mulp = &polynoms[ID_TPOLY1];
gf::poly_mul(synd, errata_loc, mulp);
Poly *divisor = &polynoms[ID_TPOLY2];
divisor->length = ecclen+2;
divisor->Reset();
divisor->at(0) = 1;
gf::poly_div(mulp, divisor, dst);
}
void CorrectErrata(const Poly *synd, const Poly *err_pos, const Poly *msg_in) {
Poly *c_pos = &polynoms[ID_COEF_POS];
Poly *corrected = &polynoms[ID_MSG_OUT];
c_pos->length = err_pos->length;
for(uint8_t i = 0; i < err_pos->length; i++)
c_pos->at(i) = msg_in->length - 1 - err_pos->at(i);
/* uses t_poly 1, 2, 3, 4 */
FindErrataLocator(c_pos);
Poly *errata_loc = &polynoms[ID_ERASURES_LOC];
/* reversing syndromes */
Poly *rsynd = &polynoms[ID_TPOLY3];
rsynd->length = synd->length;
for(int8_t i = synd->length-1, j = 0; i >= 0; i--, j++) {
rsynd->at(j) = synd->at(i);
}
/* getting reversed error evaluator polynomial */
Poly *re_eval = &polynoms[ID_TPOLY4];
/* uses T_POLY 1, 2 */
FindErrorEvaluator(rsynd, errata_loc, re_eval, errata_loc->length-1);
/* reversing it back */
Poly *e_eval = &polynoms[ID_ERR_EVAL];
e_eval->length = re_eval->length;
for(int8_t i = re_eval->length-1, j = 0; i >= 0; i--, j++) {
e_eval->at(j) = re_eval->at(i);
}
Poly *X = &polynoms[ID_TPOLY1]; /* this will store errors positions */
X->length = 0;
int16_t l;
for(uint8_t i = 0; i < c_pos->length; i++){
l = 255 - c_pos->at(i);
X->Append(gf::pow(2, -l));
}
/* Magnitude polynomial
Shit just got real */
Poly *E = &polynoms[ID_MSG_E];
E->Reset();
E->length = msg_in->length;
uint8_t Xi_inv;
Poly *err_loc_prime_temp = &polynoms[ID_TPOLY2];
uint8_t err_loc_prime;
uint8_t y;
for(uint8_t i = 0; i < X->length; i++){
Xi_inv = gf::inverse(X->at(i));
err_loc_prime_temp->length = 0;
for(uint8_t j = 0; j < X->length; j++){
if(j != i){
err_loc_prime_temp->Append(gf::sub(1, gf::mul(Xi_inv, X->at(j))));
}
}
err_loc_prime = 1;
for(uint8_t j = 0; j < err_loc_prime_temp->length; j++){
err_loc_prime = gf::mul(err_loc_prime, err_loc_prime_temp->at(j));
}
y = gf::poly_eval(re_eval, Xi_inv);
y = gf::mul(gf::pow(X->at(i), 1), y);
E->at(err_pos->at(i)) = gf::div(y, err_loc_prime);
}
gf::poly_add(msg_in, E, corrected);
}
bool FindErrorLocator(const Poly *synd, Poly *erase_loc = NULL, size_t erase_count = 0) {
Poly *error_loc = &polynoms[ID_ERRORS_LOC];
Poly *err_loc = &polynoms[ID_TPOLY1];
Poly *old_loc = &polynoms[ID_TPOLY2];
Poly *temp = &polynoms[ID_TPOLY3];
Poly *temp2 = &polynoms[ID_TPOLY4];
if(erase_loc != NULL) {
err_loc->Copy(erase_loc);
old_loc->Copy(erase_loc);
} else {
err_loc->length = 1;
old_loc->length = 1;
err_loc->at(0) = 1;
old_loc->at(0) = 1;
}
uint8_t synd_shift = 0;
if(synd->length > ecc_length) {
synd_shift = synd->length - ecc_length;
}
uint8_t K = 0;
uint8_t delta = 0;
uint8_t index;
for(uint8_t i = 0; i < ecc_length - erase_count; i++){
if(erase_loc != NULL)
K = erase_count + i + synd_shift;
else
K = i + synd_shift;
delta = synd->at(K);
for(uint8_t j = 1; j < err_loc->length; j++) {
index = err_loc->length - j - 1;
delta ^= gf::mul(err_loc->at(index), synd->at(K-j));
}
old_loc->Append(0);
if(delta != 0) {
if(old_loc->length > err_loc->length) {
gf::poly_scale(old_loc, temp, delta);
gf::poly_scale(err_loc, old_loc, gf::inverse(delta));
err_loc->Copy(temp);
}
gf::poly_scale(old_loc, temp, delta);
gf::poly_add(err_loc, temp, temp2);
err_loc->Copy(temp2);
}
}
uint32_t shift = 0;
while(err_loc->length && err_loc->at(shift) == 0) shift++;
uint32_t errs = err_loc->length - shift - 1;
if(((errs - erase_count) * 2 + erase_count) > ecc_length){
return false; /* Error count is greater than we can fix! */
}
memcpy(error_loc->ptr(), err_loc->ptr() + shift, (err_loc->length - shift) * sizeof(uint8_t));
error_loc->length = (err_loc->length - shift);
return true;
}
bool FindErrors(const Poly *error_loc, size_t msg_in_size) {
Poly *err = &polynoms[ID_ERRORS];
uint8_t errs = error_loc->length - 1;
err->length = 0;
for(uint8_t i = 0; i < msg_in_size; i++) {
if(gf::poly_eval(error_loc, gf::pow(2, i)) == 0) {
err->Append(msg_in_size - 1 - i);
}
}
/* Sanity check:
* the number of err/errata positions found
* should be exactly the same as the length of the errata locator polynomial */
if(err->length != errs)
/* couldn't find error locations */
return false;
return true;
}
void CalcForneySyndromes(const Poly *synd, const Poly *erasures_pos, size_t msg_in_size) {
Poly *erase_pos_reversed = &polynoms[ID_TPOLY1];
Poly *forney_synd = &polynoms[ID_FORNEY];
erase_pos_reversed->length = 0;
for(uint8_t i = 0; i < erasures_pos->length; i++){
erase_pos_reversed->Append(msg_in_size - 1 - erasures_pos->at(i));
}
forney_synd->Reset();
forney_synd->Set(synd->ptr()+1, synd->length-1);
uint8_t x;
for(uint8_t i = 0; i < erasures_pos->length; i++) {
x = gf::pow(2, erase_pos_reversed->at(i));
for(int8_t j = 0; j < forney_synd->length - 1; j++){
forney_synd->at(j) = gf::mul(forney_synd->at(j), x) ^ forney_synd->at(j+1);
}
}
}
};
}
#endif // RS_HPP
================================================
FILE: tests/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 2.8.10)
project(RStest C CXX)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
include_directories(${RS_INCLUDE_DIRS})
file(GLOB CPP_FILES *.cpp)
add_executable(${PROJECT_NAME} ${CPP_FILES})
================================================
FILE: tests/gftest.cpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#include "gftest.hpp"
Report
GFtest::run_tests() {
bool (*tests[])(std::string&) = {
test_add,
test_mul,
test_div,
test_pow,
test_inverse,
test_poly_scale,
test_poly_add,
test_poly_mul,
test_poly_div,
test_poly_eval
};
Report rep = {10, 0};
for(uint i = 0; i < rep.overall; i++) {
if(test(tests[i])) rep.passed++;
}
std::cout << "GFTest: " << rep.passed << "/" << rep.overall << " tests passed.\n\n";
return rep;
}
bool
GFtest::test_add(std::string &name) {
INIT_TESTCASE;
const uint testcount = 256;
uint8_t* leftops = (uint8_t*) RS::gf::log;
uint8_t* rightops = (uint8_t*) RS::gf::exp;
uint8_t answers[testcount] = {
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,
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,
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,
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,
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,
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,
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,
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,
6, 237, 0, 177, 254, 39, 193, 99, 246, 101, 148, 28, 14, 98, 107, 111, 224, 152, 50, 5, 23, 214, 174
};
for(uint i = 0; i < testcount; i++) {
SUBTEST(compare(RS::gf::add(leftops[i], rightops[i]), answers[i]));
}
RETURN;
}
// TODO Implement other tests
bool
GFtest::test_mul(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_div(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_pow(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_inverse(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_poly_scale(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_poly_add(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_poly_mul(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_poly_div(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
bool
GFtest::test_poly_eval(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
================================================
FILE: tests/gftest.hpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#ifndef GFTEST_H
#define GFTEST_H
#include "testsuite.hpp"
#include <gf.hpp>
class GFtest : public TestSuite {
public:
static Report run_tests();
static bool test_add(std::string& name);
static bool test_sub(std::string& name);
static bool test_mul(std::string& name);
static bool test_div(std::string& name);
static bool test_pow(std::string& name);
static bool test_inverse(std::string& name);
static bool test_poly_scale(std::string& name);
static bool test_poly_add (std::string& name);
static bool test_poly_mul (std::string& name);
static bool test_poly_div (std::string& name);
static bool test_poly_eval (std::string& name);
};
#endif // GFTEST_H
================================================
FILE: tests/performancetest.cpp
================================================
#include "performancetest.hpp"
#include <chrono>
using namespace std::chrono;
PerformanceTest::Data_t PerformanceTest::data = {};
RS::ReedSolomon<TEST_DATA_SIZE, TEST_ECC_SIZE> PerformanceTest::rs;
PReport
PerformanceTest::run_tests(uint32_t laps_cnt, uint32_t cnt_per_lap) {
assert(laps_cnt < 64 && cnt_per_lap < 64);
std::cout << "Starting performance tests\n";
PReport enc_rep;
PReport dec_rep;
/// Init data
for(uint32_t i = 0; i < TEST_DATA_SIZE; i++) {
data.msg[i] = i;
data.err_msg[i] = i;
}
/// Prepare corrupted message
for(uint32_t i = 0; i < TEST_ECC_SIZE / 2; i++) {
data.err_msg[i+1] = 0;
}
auto lap_time = []() -> uint32_t {
static milliseconds last_time = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
);
milliseconds time = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
);
milliseconds diff = time - last_time;
last_time = time;
return diff.count();
};
/// Run 3 times
for(uint32_t i = 0; i < laps_cnt; i++) {
lap_time(); /// init static counter
for(uint32_t i = 0; i < cnt_per_lap; i++) {
encoder_atom();
}
enc_rep.laps[i] = lap_time();
lap_time(); /// init static counter
for(uint32_t i = 0; i < cnt_per_lap; i++) {
decoder_atom();
}
dec_rep.laps[i] = lap_time();
}
/// Calculate average
enc_rep.average[0] = 0;
dec_rep.average[0] = 0;
for(uint32_t i = 0; i < laps_cnt; i++) {
enc_rep.average[0] += enc_rep.laps[i];
dec_rep.average[0] += dec_rep.laps[i];
}
enc_rep.average[0] /= laps_cnt;
dec_rep.average[0] /= laps_cnt;
return PReport {
.overall = enc_rep.average[0] + dec_rep.average[0],
.average = {enc_rep.average[0], dec_rep.average[0]},
.count = 2
};
}
void
PerformanceTest::encoder_atom() {
rs.EncodeBlock(data.msg, data.ecc);
}
void
PerformanceTest::decoder_atom() {
rs.DecodeBlock(data.err_msg, data.ecc, data.rep_msg);
}
================================================
FILE: tests/performancetest.hpp
================================================
#ifndef PERFORMANCETEST_HPP
#define PERFORMANCETEST_HPP
#include "testsuite.hpp"
#include "string.h"
#include "rs.hpp"
#define TEST_DATA_SIZE 200
#define TEST_ECC_SIZE 40
class PerformanceTest : public TestSuite
{
public:
static PReport run_tests(uint32_t laps_cnt, uint32_t cnt_per_lap);
static void encoder_atom();
static void decoder_atom();
private:
static struct Data_t {
uint8_t msg [TEST_DATA_SIZE];
uint8_t err_msg[TEST_DATA_SIZE];
uint8_t rep_msg[TEST_DATA_SIZE];
uint8_t ecc[TEST_ECC_SIZE];
} data;
static RS::ReedSolomon<TEST_DATA_SIZE, TEST_ECC_SIZE> rs;
};
#endif // PERFORMANCETEST_H
================================================
FILE: tests/rstest.cpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#include "rstest.hpp"
#include <rs.hpp>
Report
RStest::run_tests() {
bool (*tests[])(std::string&) = {
test_encode,
test_decode,
test_stress
};
Report rep = {3, 0};
for(uint i = 0; i < rep.overall; i++) {
if(test(tests[i])) rep.passed++;
}
std::cout << "RSTest: " << rep.passed << "/" << rep.overall << " tests passed.\n\n";
return rep;
}
bool
RStest::test_encode(std::string &name) {
INIT_TESTCASE;
RS::ReedSolomon<30, 8> rs;
char message[30];
char encoded[38];
uint8_t right[38] = {
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,
99, 26, 219, 193, 9, 94, 186, 143
};
memcpy(message, right, 30);
rs.Encode(message, encoded);
SUBTEST(compare((uint8_t*)encoded, (uint8_t*)right, 38));
RETURN;
}
bool
RStest::test_decode(std::string &name) {
INIT_TESTCASE;
RS::ReedSolomon<30, 8> rs;
char message[30];
char right[30] = {
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
};
// Test clean message
uint8_t clean[38] = {
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,
99, 26, 219, 193, 9, 94, 186, 143
};
SUBTEST(rs.Decode(clean, message) == 0);
SUBTEST(compare(message, right, 30));
// Test corrupted message
uint8_t corrupted[38] = {
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,
99, 26, 219, 193, 9, 94, 0, 143
};
SUBTEST(rs.Decode(corrupted, message) == 0);
SUBTEST(compare(message, right, 30));
RETURN
}
// TODO make complex encoder-decder test
bool
RStest::test_stress(std::string &name) {
INIT_TESTCASE;
SUBTEST(true);
RETURN;
}
================================================
FILE: tests/rstest.hpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#ifndef RSTEST_H
#define RSTEST_H
#include "testsuite.hpp"
#include <rs.hpp>
class RStest : public TestSuite
{
public:
static Report run_tests();
static bool test_encode(std::string& name);
static bool test_decode(std::string& name);
static bool test_stress(std::string& name);
};
#endif // RSTEST_H
================================================
FILE: tests/tests.cpp
================================================
/* Author: Mike Lubinets (aka mersinvald)
* Date: 29.12.15
*
* See LICENSE */
#include <iostream>
#include "gftest.hpp"
#include "rstest.hpp"
#include "performancetest.hpp"
using namespace std;
#define COUNT_PER_PTEST_LAP 63
#define COUNT_OF_LAPS 22
int main() {
GFtest::run_tests();
RStest::run_tests();
PReport performance = PerformanceTest::run_tests(COUNT_OF_LAPS, COUNT_PER_PTEST_LAP);
std::cout << "Average of " << COUNT_OF_LAPS << "x" << COUNT_PER_PTEST_LAP << " for encoder: " << performance.average[0] << "ms\n";
std::cout << "Average of " << COUNT_OF_LAPS << "x" << COUNT_PER_PTEST_LAP << " for decoder: " << performance.average[1] << "ms\n";
}
================================================
FILE: x32.cmake_toolchain
================================================
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_CXX_COMPILER_ARG1 "-m32")
set(CMAKE_C_COMPILER_ARG1 "-m32")
gitextract_c0tv96n1/ ├── .gitexcludes ├── .github/ │ └── workflows/ │ └── codeql-analysis.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── examples/ │ ├── CMakeLists.txt │ └── example1.cpp ├── include/ │ ├── gf.hpp │ ├── poly.hpp │ └── rs.hpp ├── tests/ │ ├── CMakeLists.txt │ ├── gftest.cpp │ ├── gftest.hpp │ ├── performancetest.cpp │ ├── performancetest.hpp │ ├── rstest.cpp │ ├── rstest.hpp │ └── tests.cpp └── x32.cmake_toolchain
SYMBOL INDEX (49 symbols across 11 files)
FILE: examples/example1.cpp
function main (line 12) | int main() {
FILE: include/gf.hpp
type RS (line 19) | namespace RS {
type gf (line 21) | namespace gf {
function add (line 74) | inline uint8_t add(uint8_t x, uint8_t y) {
function sub (line 83) | inline uint8_t sub(uint8_t x, uint8_t y) {
function mul (line 91) | inline uint8_t mul(uint16_t x, uint16_t y){
function div (line 101) | inline uint8_t div(uint8_t x, uint8_t y){
function pow (line 111) | inline uint8_t pow(uint8_t x, intmax_t power){
function inverse (line 122) | inline uint8_t inverse(uint8_t x){
function poly_scale (line 134) | inline void
function poly_add (line 146) | inline void
function poly_mul (line 165) | inline void
function poly_div (line 182) | inline void
function poly_eval (line 210) | inline int8_t
FILE: include/poly.hpp
type RS (line 17) | namespace RS {
type Poly (line 19) | struct Poly {
method Poly (line 20) | Poly()
method Poly (line 23) | Poly(uint8_t id, uint16_t offset, uint8_t size) \
method Append (line 29) | inline bool Append(uint8_t num) {
method Init (line 36) | inline void Init(uint8_t id, uint16_t offset, uint8_t size, uint8_t*...
method Reset (line 45) | inline void Reset() {
method Set (line 53) | inline void Set(const uint8_t* src, uint8_t len, uint8_t offset = 0) {
method Copy (line 61) | inline void Copy(const Poly* src) {
method id (line 71) | inline uint8_t id() const {
method size (line 75) | inline uint8_t size() const {
FILE: include/rs.hpp
type RS (line 19) | namespace RS {
class ReedSolomon (line 27) | class ReedSolomon {
method ReedSolomon (line 29) | ReedSolomon() {
method EncodeBlock (line 65) | void EncodeBlock(const void* src, void* dst) {
method Encode (line 119) | void Encode(const void* src, void* dst) {
method DecodeBlock (line 136) | int DecodeBlock(const void* src, const void* ecc, void* dst, uint8_t...
method Decode (line 233) | int Decode(const void* src, void* dst, uint8_t* erase_pos = NULL, si...
type POLY_ID (line 244) | enum POLY_ID {
method GeneratorPoly (line 273) | void GeneratorPoly() {
method CalcSyndromes (line 292) | void CalcSyndromes(const Poly *msg) {
method FindErrataLocator (line 301) | void FindErrataLocator(const Poly *epos) {
method FindErrorEvaluator (line 326) | void FindErrorEvaluator(const Poly *synd, const Poly *errata_loc, Po...
method CorrectErrata (line 339) | void CorrectErrata(const Poly *synd, const Poly *err_pos, const Poly...
method FindErrorLocator (line 418) | bool FindErrorLocator(const Poly *synd, Poly *erase_loc = NULL, size...
method FindErrors (line 483) | bool FindErrors(const Poly *error_loc, size_t msg_in_size) {
method CalcForneySyndromes (line 504) | void CalcForneySyndromes(const Poly *synd, const Poly *erasures_pos,...
FILE: tests/gftest.cpp
function Report (line 8) | Report
FILE: tests/gftest.hpp
class GFtest (line 11) | class GFtest : public TestSuite {
FILE: tests/performancetest.cpp
function PReport (line 9) | PReport
FILE: tests/performancetest.hpp
class PerformanceTest (line 10) | class PerformanceTest : public TestSuite
type Data_t (line 19) | struct Data_t {
FILE: tests/rstest.cpp
function Report (line 9) | Report
FILE: tests/rstest.hpp
class RStest (line 11) | class RStest : public TestSuite
FILE: tests/tests.cpp
function main (line 16) | int main() {
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
{
"path": ".gitexcludes",
"chars": 68,
"preview": "./src/libRS.pro.user\n./tests/tests.pro.user\n./Reed-Solomon.pro.user\n"
},
{
"path": ".github/workflows/codeql-analysis.yml",
"chars": 2572,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".gitignore",
"chars": 13,
"preview": "*.so\n*.a\n*.o\n"
},
{
"path": ".gitmodules",
"chars": 89,
"preview": "[submodule \"tests/mtest\"]\n\tpath = tests/mtest\n\turl = git@github.com:mersinvald/mtest.git\n"
},
{
"path": "CMakeLists.txt",
"chars": 887,
"preview": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(Reed-Solomon)\n\n# You can tweak some common (for all subprojects) stuff h"
},
{
"path": "LICENSE",
"chars": 1092,
"preview": "Copyright © 2015 Mike Lubinets, github.com/mersinvald\n\nPermission is hereby granted, free of charge, to any person \nobta"
},
{
"path": "Makefile",
"chars": 213,
"preview": "all:\n\tmkdir -p build && cd build && cmake ../ && make\n\nx32:\n\tmkdir -p build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE="
},
{
"path": "README.md",
"chars": 1973,
"preview": "# Reed-Solomon\nReed Solomon BCH encoder and decoder library\n\n## Overview\n\nThis RS implementation was designed for embedd"
},
{
"path": "examples/CMakeLists.txt",
"chars": 604,
"preview": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(examples CXX)\n\ninclude(CheckCXXCompilerFlag)\nCHECK_CXX_COMPILER_FLAG(\"-s"
},
{
"path": "examples/example1.cpp",
"chars": 915,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include <iostream>\n#include \"rs.hpp\"\n"
},
{
"path": "include/gf.hpp",
"chars": 8159,
"preview": "/* 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#incl"
},
{
"path": "include/poly.hpp",
"chars": 2480,
"preview": "/* 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#"
},
{
"path": "include/rs.hpp",
"chars": 17192,
"preview": "/* 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#"
},
{
"path": "tests/CMakeLists.txt",
"chars": 639,
"preview": "cmake_minimum_required(VERSION 2.8.10)\n\nproject(RStest C CXX)\n\ninclude(CheckCXXCompilerFlag)\nCHECK_CXX_COMPILER_FLAG(\"-s"
},
{
"path": "tests/gftest.cpp",
"chars": 3170,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include \"gftest.hpp\"\n\nReport\nGFtest::"
},
{
"path": "tests/gftest.hpp",
"chars": 792,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#ifndef GFTEST_H\n#define GFTEST_H\n#inc"
},
{
"path": "tests/performancetest.cpp",
"chars": 2144,
"preview": "#include \"performancetest.hpp\"\n#include <chrono>\n\nusing namespace std::chrono;\n\nPerformanceTest::Data_t PerformanceTest:"
},
{
"path": "tests/performancetest.hpp",
"chars": 664,
"preview": "#ifndef PERFORMANCETEST_HPP\n#define PERFORMANCETEST_HPP\n#include \"testsuite.hpp\"\n#include \"string.h\"\n#include \"rs.hpp\"\n\n"
},
{
"path": "tests/rstest.cpp",
"chars": 2014,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include \"rstest.hpp\"\n#include <rs.hpp"
},
{
"path": "tests/rstest.hpp",
"chars": 401,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#ifndef RSTEST_H\n#define RSTEST_H\n#inc"
},
{
"path": "tests/tests.cpp",
"chars": 690,
"preview": "/* Author: Mike Lubinets (aka mersinvald)\n * Date: 29.12.15\n *\n * See LICENSE */\n\n#include <iostream>\n#include \"gftest.h"
},
{
"path": "x32.cmake_toolchain",
"chars": 100,
"preview": "set(CMAKE_SYSTEM_VERSION 1) \nset(CMAKE_CXX_COMPILER_ARG1 \"-m32\")\nset(CMAKE_C_COMPILER_ARG1 \"-m32\")\n\n"
}
]
About this extraction
This page contains the full source code of the mersinvald/Reed-Solomon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (45.8 KB), approximately 15.8k tokens, and a symbol index with 49 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.