This commit is contained in:
Kurt Moraw
2020-10-27 16:41:16 +01:00
parent 647db711c4
commit 3deb0a09fd
514 changed files with 242695 additions and 2 deletions
+172
View File
@@ -0,0 +1,172 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_CRC_HPP
#define INCLUDE_SCHIFRA_CRC_HPP
#include <iostream>
#include <string>
namespace schifra
{
class crc32
{
public:
typedef std::size_t crc32_t;
crc32(const crc32_t& _key, const crc32_t& _state = 0x00)
: key(_key),
state(_state),
initial_state(_state)
{
initialize_crc32_table();
}
void reset()
{
state = initial_state;
}
void update_1byte(const unsigned char data)
{
state = (state >> 8) ^ table[data];
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
crc32_t crc()
{
return state;
}
private:
crc32& operator=(const crc32&);
void initialize_crc32_table()
{
for (std::size_t i = 0; i < 0xFF; ++i)
{
crc32_t reg = i;
for (int j = 0; j < 0x08; ++j)
{
reg = ((reg & 1) ? (reg >> 1) ^ key : reg >> 1);
}
table[i] = reg;
}
}
protected:
crc32_t key;
crc32_t state;
const crc32_t initial_state;
crc32_t table[256];
};
class schifra_crc : public crc32
{
public:
schifra_crc(const crc32_t _key)
: crc32(_key,0xAAAAAAAA)
{}
void update(const unsigned char& data)
{
state = ((state >> 8) ^ table[data]) ^ ((state << 8) ^ table[~data]);
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(const char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
};
} // namespace schifra
#endif
+109
View File
@@ -0,0 +1,109 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ECC_TRAITS_HPP
#define INCLUDE_SCHIFRA_ECC_TRAITS_HPP
namespace schifra
{
namespace traits
{
template <std::size_t code_length> struct symbol;
/* bits per symbol */
template <> struct symbol< 3> { enum {size = 2}; };
template <> struct symbol< 7> { enum {size = 3}; };
template <> struct symbol< 15> { enum {size = 4}; };
template <> struct symbol< 31> { enum {size = 5}; };
template <> struct symbol< 63> { enum {size = 6}; };
template <> struct symbol< 127> { enum {size = 7}; };
template <> struct symbol< 255> { enum {size = 8}; };
template <> struct symbol< 511> { enum {size = 9}; };
template <> struct symbol< 1023> { enum {size = 10}; };
template <> struct symbol< 2047> { enum {size = 11}; };
template <> struct symbol< 4195> { enum {size = 12}; };
template <> struct symbol< 8191> { enum {size = 13}; };
template <> struct symbol<16383> { enum {size = 14}; };
template <> struct symbol<32768> { enum {size = 15}; };
template <> struct symbol<65535> { enum {size = 16}; };
/* Credits: Modern C++ Design - Andrei Alexandrescu */
template <bool> class __static_assert__
{
public:
__static_assert__(...) {}
};
template <> class __static_assert__<true> {};
template <> class __static_assert__<false>;
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_code_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_block_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <typename Encoder, typename Decoder>
struct equivalent_encoder_decoder
{
private:
__static_assert__<(Encoder::trait::code_length == Decoder::trait::code_length)> assertion1;
__static_assert__<(Encoder::trait::fec_length == Decoder::trait::fec_length) > assertion2;
__static_assert__<(Encoder::trait::data_length == Decoder::trait::data_length)> assertion3;
};
template <std::size_t code_length_, std::size_t fec_length_, std::size_t data_length_ = code_length_ - fec_length_>
class reed_solomon_triat
{
public:
typedef validate_reed_solomon_code_parameters<code_length_,fec_length_,data_length_> vrscp;
enum { code_length = code_length_ };
enum { fec_length = fec_length_ };
enum { data_length = data_length_ };
};
}
} // namespace schifra
#endif
+256
View File
@@ -0,0 +1,256 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#define INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t fec_length>
inline void interleaved_stack_erasure_mapper(const std::vector<std::size_t>& missing_row_index,
std::vector<erasure_locations_t>& erasure_row_list)
{
erasure_row_list.resize(block_length);
for (std::size_t i = 0; i < block_length; ++i)
{
erasure_row_list[i].reserve(fec_length);
}
for (std::size_t i = 0; i < missing_row_index.size(); ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
erasure_row_list[j].push_back(missing_row_index[i]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_encode(const encoder<code_length,fec_length>& encoder,
block<code_length,fec_length> (&output)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
if (!encoder.encode(output[i]))
{
std::cout << "erasure_channel_stack_encode() - Error: Failed to encode block[" << i <<"]" << std::endl;
return false;
}
}
interleave<code_length,fec_length>(output);
return true;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class erasure_code_decoder : public decoder<code_length,fec_length,data_length>
{
public:
typedef decoder<code_length,fec_length,data_length> decoder_type;
typedef typename decoder_type::block_type block_type;
typedef std::vector<galois::field_polynomial> polynomial_list_type;
erasure_code_decoder(const galois::field& gfield,
const unsigned int& gen_initial_index)
: decoder<code_length,fec_length,data_length>(gfield, gen_initial_index)
{
for (std::size_t i = 0; i < code_length; ++i)
{
received_.push_back(galois::field_polynomial(decoder_type::field_, code_length - 1));
syndrome_.push_back(galois::field_polynomial(decoder_type::field_));
}
};
bool decode(block_type rsblock[code_length], const erasure_locations_t& erasure_list) const
{
if (
(!decoder_type::decoder_valid_) ||
(erasure_list.size() != fec_length)
)
{
return false;
}
for (std::size_t i = 0; i < code_length; ++i)
{
decoder_type::load_message (received_[i], rsblock [i]);
decoder_type::compute_syndrome(received_[i], syndrome_[i]);
}
erasure_locations_t erasure_locations;
decoder_type::prepare_erasure_list(erasure_locations,erasure_list);
galois::field_polynomial gamma(galois::field_element(decoder_type::field_, 1));
decoder_type::compute_gamma(gamma,erasure_locations);
std::vector<int> gamma_roots;
find_roots_in_data(gamma,gamma_roots);
polynomial_list_type omega;
for (std::size_t i = 0; i < code_length; ++i)
{
omega.push_back((gamma * syndrome_[i]) % fec_length);
}
galois::field_polynomial gamma_derivative = gamma.derivative();
for (std::size_t i = 0; i < gamma_roots.size(); ++i)
{
int error_location = static_cast<int>(gamma_roots[i]);
galois::field_symbol alpha_inverse = decoder_type::field_.alpha(error_location);
galois::field_element denominator = gamma_derivative(alpha_inverse);
if (denominator == 0)
{
return false;
}
for (std::size_t j = 0; j < code_length; ++j)
{
galois::field_element numerator = (omega[j](alpha_inverse) * decoder_type::root_exponent_table_[error_location]);
/*
A minor optimization can be made in the event the
numerator is equal to zero by not executing the
following line.
*/
rsblock[j][error_location - 1] ^= decoder_type::field_.div(numerator.poly(),denominator.poly());
}
}
return true;
}
private:
void find_roots_in_data(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search, as described in parent, but only
for locations within the data range of the message.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
std::size_t polynomial_degree = poly.deg();
std::size_t root_list_size = 0;
for (int i = 1; i <= static_cast<int>(data_length); ++i)
{
if (0 == poly(decoder_type::field_.alpha(i)).poly())
{
root_list.push_back(i);
root_list_size++;
if (root_list_size == polynomial_degree)
{
break;
}
}
}
}
mutable polynomial_list_type received_;
mutable polynomial_list_type syndrome_;
};
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const decoder<code_length,fec_length>& general_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
if (missing_row_index.empty())
{
return true;
}
interleave<code_length,fec_length>(output);
for (std::size_t i = 0; i < code_length; ++i)
{
if (!general_decoder.decode(output[i],missing_row_index))
{
std::cout << "[2] erasure_channel_stack_decode() - Error: Failed to decode block[" << i <<"]" << std::endl;
return false;
}
}
return true;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const erasure_code_decoder<code_length,fec_length>& erasure_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
/*
Note: 1. Missing row indicies must be unique.
2. Missing row indicies must exist within
the stack's size.
3. There will be NO errors in the rows (aka output)
4. The information members of the blocks will
not be utilized.
There are NO exceptions to these rules!
*/
if (missing_row_index.empty())
{
return true;
}
else if (missing_row_index.size() == fec_length)
{
interleave<code_length,fec_length>(output);
return erasure_decoder.decode(output,missing_row_index);
}
else
return erasure_channel_stack_decode<code_length,fec_length>(
static_cast<const decoder<code_length,fec_length>&>(erasure_decoder),
missing_row_index,
output);
}
} // namespace reed_solomon
} // namepsace schifra
#endif
+602
View File
@@ -0,0 +1,602 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#define INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <deque>
#include <vector>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
template <std::size_t code_length, std::size_t fec_length>
inline void add_erasure_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF; // Or one can simply equate to zero
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF;
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error_4bit_symbol(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0x0F;
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors00(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_wth_mask(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const int& mask,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
std::size_t position = (start_position + scale * i) % code_length;
rsblock[position] = (~rsblock[position]) & mask;
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < error_count; ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures00(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < fec_length; ++i)
{
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t erasure_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < erasure_count; ++i)
{
/* Note: Must make sure duplicate erasures are not added */
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
namespace error_mode
{
enum type
{
errors_erasures, // Errors first then erasures
erasures_errors // Erasures first then errors
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const error_mode::type& mode,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t between_space = 0)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_errors_erasures() - ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t error_position = 0;
switch (mode)
{
case error_mode::erasures_errors : {
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + erasure_count + between_space + i) % code_length;
add_error(error_position,rsblock);
}
}
break;
case error_mode::errors_erasures : {
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + i) % code_length;
add_error(error_position,rsblock);
}
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + error_count + between_space + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
}
break;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_interleaved_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [1] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t e = 0;
std::size_t s = 0;
std::size_t i = 0;
while ((e < error_count) || (s < erasure_count) || (i < (error_count + erasure_count)))
{
std::size_t error_position = (start_position + i) % code_length;
if (((i & 0x01) == 0) && (s < erasure_count))
{
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
s++;
}
else if (((i & 0x01) == 1) && (e < error_count))
{
e++;
add_error(error_position,rsblock);
}
++i;
}
for (std::size_t j = 0; j < code_length; ++j)
{
if (erasures[j] == 1) erasure_list.push_back(j);
}
if ((2 * e) + erasure_list.size() > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [2] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
}
namespace details
{
template <std::size_t code_length, std::size_t fec_length, bool t>
struct corrupt_message_all_errors_segmented_impl
{
static void process(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
std::size_t block_1_error_count = (fec_length >> 2);
std::size_t block_2_error_count = (fec_length >> 1) - block_1_error_count;
for (std::size_t i = 0; i < block_1_error_count; ++i)
{
add_error((start_position + i) % code_length,rsblock);
}
std::size_t new_start_position = (start_position + (block_1_error_count)) + distance_between_blocks;
for (std::size_t i = 0; i < block_2_error_count; ++i)
{
add_error((new_start_position + i) % code_length,rsblock);
}
}
};
template <std::size_t code_length, std::size_t fec_length>
struct corrupt_message_all_errors_segmented_impl<code_length,fec_length,false>
{
static void process(reed_solomon::block<code_length,fec_length>&,
const std::size_t&, const std::size_t&)
{}
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_segmented(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
details::corrupt_message_all_errors_segmented_impl<code_length,fec_length,(fec_length > 2)>::
process(rsblock,start_position,distance_between_blocks);
}
inline bool check_for_duplicate_erasures(const std::vector<int>& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
for (std::size_t j = i + 1; j < erasure_list.size(); ++j)
{
if (erasure_list[i] == erasure_list[j])
{
return false;
}
}
}
return true;
}
inline void dump_erasure_list(const schifra::reed_solomon::erasure_locations_t& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
std::cout << "[" << i << "," << erasure_list[i] << "] ";
}
std::cout << std::endl;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool is_block_equivelent(const reed_solomon::block<code_length,fec_length>& rsblock,
const std::string& data,
const bool display = false,
const bool all_errors = false)
{
std::string::const_iterator it = data.begin();
bool error_found = false;
for (std::size_t i = 0; i < code_length - fec_length; ++i, ++it)
{
if (static_cast<char>(rsblock.data[i] & 0xFF) != (*it))
{
error_found = true;
if (display)
{
printf("is_block_equivelent() - Error at loc : %02d\td1: %02X\td2: %02X\n",
static_cast<unsigned int>(i),
rsblock.data[i],
static_cast<unsigned char>(*it));
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool are_blocks_equivelent(const reed_solomon::block<code_length,fec_length>& block1,
const reed_solomon::block<code_length,fec_length>& block2,
const std::size_t span = code_length,
const bool display = false,
const bool all_errors = false)
{
bool error_found = false;
for (std::size_t i = 0; i < span; ++i)
{
if (block1[i] != block2[i])
{
error_found = true;
if (display)
{
printf("are_blocks_equivelent() - Error at loc : %02d\td1: %04X\td2: %04X\n",
static_cast<unsigned int>(i),
block1[i],
block2[i]);
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::block<code_length,fec_length> block_stack1[stack_size],
const reed_solomon::block<code_length,fec_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
if (!are_blocks_equivelent(block_stack1[i],block_stack2[i]))
{
return false;
}
}
return true;
}
template <std::size_t block_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::data_block<std::size_t,block_length> block_stack1[stack_size],
const reed_solomon::data_block<std::size_t,block_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
if (block_stack1[i][j] != block_stack2[i][j])
{
return false;
}
}
}
return true;
}
inline void corrupt_file_with_burst_errors(const std::string& file_name,
const long& start_position,
const long& burst_length)
{
if (!schifra::fileio::file_exists(file_name))
{
std::cout << "corrupt_file() - Error: " << file_name << " does not exist!" << std::endl;
return;
}
if (static_cast<std::size_t>(start_position + burst_length) >= schifra::fileio::file_size(file_name))
{
std::cout << "corrupt_file() - Error: Burst error out of bounds." << std::endl;
return;
}
std::vector<char> data(burst_length);
std::ifstream ifile(file_name.c_str(), std::ios::in | std::ios::binary);
if (!ifile)
{
return;
}
ifile.seekg(start_position,std::ios_base::beg);
ifile.read(&data[0],burst_length);
ifile.close();
for (long i = 0; i < burst_length; ++i)
{
data[i] = ~data[i];
}
std::ofstream ofile(file_name.c_str(), std::ios::in | std::ios::out | std::ios::binary);
if (!ofile)
{
return;
}
ofile.seekp(start_position,std::ios_base::beg);
ofile.write(&data[0],burst_length);
ofile.close();
}
static const std::size_t global_random_error_index[] =
{
13, 170, 148, 66, 228, 208, 182, 92,
4, 137, 97, 99, 237, 151, 15, 0,
119, 243, 41, 222, 33, 211, 188, 5,
44, 30, 210, 111, 54, 79, 61, 223,
239, 149, 73, 115, 201, 234, 194, 62,
147, 70, 19, 49, 72, 52, 164, 29,
102, 225, 203, 153, 18, 205, 40, 217,
165, 177, 166, 134, 236, 68, 231, 154,
116, 136, 47, 240, 46, 89, 120, 183,
242, 28, 161, 226, 241, 230, 10, 131,
207, 132, 83, 171, 202, 195, 227, 206,
112, 88, 90, 146, 117, 180, 26, 78,
118, 254, 107, 110, 220, 7, 192, 187,
31, 175, 127, 209, 32, 12, 84, 128,
190, 156, 95, 105, 104, 246, 91, 215,
219, 142, 36, 186, 247, 233, 167, 133,
160, 16, 140, 169, 23, 96, 155, 235,
179, 76, 253, 103, 238, 67, 35, 121,
100, 27, 213, 58, 77, 248, 174, 39,
214, 56, 42, 200, 106, 21, 129, 114,
252, 113, 168, 53, 25, 216, 64, 232,
81, 75, 2, 224, 250, 60, 135, 204,
48, 196, 94, 63, 244, 191, 93, 126,
138, 159, 9, 85, 249, 34, 185, 163,
17, 65, 184, 82, 109, 172, 108, 69,
150, 3, 20, 221, 162, 212, 152, 59,
198, 74, 229, 55, 87, 178, 141, 199,
57, 130, 80, 173, 101, 122, 144, 51,
139, 11, 8, 125, 158, 124, 123, 37,
14, 24, 22, 43, 197, 50, 98, 6,
176, 251, 86, 218, 193, 71, 145, 1,
45, 38, 189, 143, 245, 157, 181
};
static const std::size_t error_index_size = sizeof(global_random_error_index) / sizeof(std::size_t);
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const bool display_positions = false)
{
schifra::reed_solomon::block<code_length,fec_length> tmp_rsblock = rsblock;
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (global_random_error_index[(error_index_start_position + i) % error_index_size]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const std::vector<std::size_t>& random_error_index,
const bool display_positions = false)
{
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (random_error_index[(error_index_start_position + i) % random_error_index.size()]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
inline void generate_error_index(const std::size_t index_size,
std::vector<std::size_t>& random_error_index,
std::size_t seed)
{
if (0 == seed)
{
seed = 0xA5A5A5A5;
}
::srand(static_cast<unsigned int>(seed));
std::deque<std::size_t> index_list;
for (std::size_t i = 0; i < index_size; ++i)
{
index_list.push_back(i);
}
random_error_index.reserve(index_size);
random_error_index.resize(0);
while (!index_list.empty())
{
// possibly the worst way of doing this.
std::size_t index = ::rand() % index_list.size();
random_error_index.push_back(index_list[index]);
index_list.erase(index_list.begin() + index);
}
}
} // namespace schifra
#endif
+227
View File
@@ -0,0 +1,227 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_FILEIO_HPP
#define INCLUDE_SCHIFRA_FILEIO_HPP
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include "schifra_crc.hpp"
namespace schifra
{
namespace fileio
{
inline void read_into_vector(const std::string& file_name, std::vector<std::string>& buffer)
{
std::ifstream file(file_name.c_str());
if (!file) return;
std::string line;
while (std::getline(file,line))
{
buffer.push_back(line);
}
file.close();
}
inline void write_from_vector(const std::string& file_name, const std::vector<std::string>& buffer)
{
std::ofstream file(file_name.c_str());
if (!file) return;
std::ostream_iterator <std::string> os(file,"\n");
std::copy(buffer.begin(),buffer.end(), os);
file.close();
}
inline bool file_exists(const std::string& file_name)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
return ((!file) ? false : true);
}
inline std::size_t file_size(const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
file.seekg (0, std::ios::end);
return static_cast<std::size_t>(file.tellg());
}
inline void load_file(const std::string& file_name, std::string& buffer)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
if (!file) return;
buffer.assign(std::istreambuf_iterator<char>(file),std::istreambuf_iterator<char>());
file.close();
}
inline void load_file(const std::string& file_name, char** buffer, std::size_t& buffer_size)
{
std::ifstream in_stream(file_name.c_str(),std::ios::binary);
if (!in_stream) return;
buffer_size = file_size(file_name);
*buffer = new char[buffer_size];
in_stream.read(*buffer,static_cast<std::streamsize>(buffer_size));
in_stream.close();
}
inline void write_file(const std::string& file_name, const std::string& buffer)
{
std::ofstream file(file_name.c_str(),std::ios::binary);
file << buffer;
file.close();
}
inline void write_file(const std::string& file_name, char* buffer, const std::size_t& buffer_size)
{
std::ofstream out_stream(file_name.c_str(),std::ios::binary);
if (!out_stream) return;
out_stream.write(buffer,static_cast<std::streamsize>(buffer_size));
out_stream.close();
}
inline bool copy_file(const std::string& src_file_name, const std::string& dest_file_name)
{
std::ifstream src_file(src_file_name.c_str(),std::ios::binary);
std::ofstream dest_file(dest_file_name.c_str(),std::ios::binary);
if (!src_file) return false;
if (!dest_file) return false;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(src_file_name);
while (remaining_bytes >= block_size)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(block_size));
dest_file.write(&buffer[0],static_cast<std::streamsize>(block_size));
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
dest_file.write(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
remaining_bytes = 0;
}
src_file.close();
dest_file.close();
return true;
}
inline bool files_identical(const std::string& file_name1, const std::string& file_name2)
{
std::ifstream file1(file_name1.c_str(),std::ios::binary);
std::ifstream file2(file_name2.c_str(),std::ios::binary);
if (!file1) return false;
if (!file2) return false;
if (file_size(file_name1) != file_size(file_name2)) return false;
const std::size_t block_size = 1024;
char buffer1[block_size];
char buffer2[block_size];
std::size_t remaining_bytes = file_size(file_name1);
while (remaining_bytes >= block_size)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(block_size));
file2.read(&buffer2[0],static_cast<std::streamsize>(block_size));
for (std::size_t i = 0; i < block_size; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(remaining_bytes));
file2.read(&buffer2[0],static_cast<std::streamsize>(remaining_bytes));
for (std::size_t i = 0; i < remaining_bytes; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes = 0;
}
file1.close();
file2.close();
return true;
}
inline std::size_t file_crc(crc32& crc_module, const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(file_name);
crc_module.reset();
while (remaining_bytes >= block_size)
{
file.read(&buffer[0],static_cast<std::streamsize>(block_size));
crc_module.update(buffer,block_size);
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
crc_module.update(buffer,remaining_bytes);
remaining_bytes = 0;
}
return crc_module.crc();
}
} // namespace fileio
} // namespace schifra
#endif
+518
View File
@@ -0,0 +1,518 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#include <algorithm>
#include <iostream>
#include <vector>
#include <limits>
#include <string>
namespace schifra
{
namespace galois
{
typedef int field_symbol;
const field_symbol GFERROR = -1;
class field
{
public:
field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly);
~field();
bool operator==(const field& gf) const;
bool operator!=(const field& gf) const;
inline field_symbol index(const field_symbol value) const
{
return index_of_[value];
}
inline field_symbol alpha(const field_symbol value) const
{
return alpha_to_[value];
}
inline unsigned int size() const
{
return field_size_;
}
inline unsigned int pwr() const
{
return power_;
}
inline unsigned int mask() const
{
return field_size_;
}
inline field_symbol add(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol sub(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol normalize(field_symbol x) const
{
while (x < 0)
{
x += static_cast<field_symbol>(field_size_);
}
while (x >= static_cast<field_symbol>(field_size_))
{
x -= static_cast<field_symbol>(field_size_);
x = (x >> power_) + (x & field_size_);
}
return x;
}
inline field_symbol mul(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return mul_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
#endif
}
inline field_symbol div(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return div_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
#endif
}
inline field_symbol exp(const field_symbol& a, int n) const
{
#if !defined(NO_GFLUT)
if (n >= 0)
return exp_table_[a][n & field_size_];
else
{
while (n < 0) n += field_size_;
return (n ? exp_table_[a][n] : 1);
}
#else
if (a != 0)
{
if (n < 0)
{
while (n < 0) n += field_size_;
return (n ? alpha_to_[normalize(index_of_[a] * n)] : 1);
}
else if (n)
return alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))];
else
return 1;
}
else
return 0;
#endif
}
#ifdef LINEAR_EXP_LUT
inline field_symbol* const linear_exp(const field_symbol& a) const
{
#if !defined(NO_GFLUT)
static const field_symbol upper_bound = 2 * field_size_;
if ((a >= 0) && (a <= upper_bound))
return linear_exp_table_[a];
else
return reinterpret_cast<field_symbol*>(0);
#else
return reinterpret_cast<field_symbol*>(0);
#endif
}
#endif
inline field_symbol inverse(const field_symbol& val) const
{
#if !defined(NO_GFLUT)
return mul_inverse_[val];
#else
return alpha_to_[normalize(field_size_ - index_of_[val])];
#endif
}
inline unsigned int prim_poly_term(const unsigned int index) const
{
return prim_poly_[index];
}
friend std::ostream& operator << (std::ostream& os, const field& gf);
private:
field();
field(const field& gfield);
field& operator=(const field& gfield);
void generate_field(const unsigned int* prim_poly_);
field_symbol gen_mul (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_div (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_exp (const field_symbol& a, const std::size_t& n) const;
field_symbol gen_inverse (const field_symbol& val) const;
std::size_t create_array(char buffer_[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array);
std::size_t create_2d_array(char buffer_[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array);
unsigned int power_;
std::size_t prim_poly_deg_;
unsigned int field_size_;
unsigned int prim_poly_hash_;
unsigned int* prim_poly_;
field_symbol* alpha_to_; // aka exponential or anti-log
field_symbol* index_of_; // aka log
field_symbol* mul_inverse_; // multiplicative inverse
field_symbol** mul_table_;
field_symbol** div_table_;
field_symbol** exp_table_;
field_symbol** linear_exp_table_;
char* buffer_;
};
inline field::field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly)
: power_(pwr),
prim_poly_deg_(primpoly_deg),
field_size_((1 << power_) - 1)
{
alpha_to_ = new field_symbol [field_size_ + 1];
index_of_ = new field_symbol [field_size_ + 1];
#if !defined(NO_GFLUT)
#ifdef LINEAR_EXP_LUT
static const std::size_t buffer_size = ((6 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#else
static const std::size_t buffer_size = ((4 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#endif
buffer_ = new char[buffer_size];
std::size_t offset = 0;
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&mul_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&div_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&exp_table_);
#ifdef LINEAR_EXP_LUT
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1) * 2,offset,&linear_exp_table_);
#else
linear_exp_table_ = 0;
#endif
offset = create_array(buffer_,(field_size_ + 1) * 2,offset,&mul_inverse_);
#else
buffer_ = 0;
mul_table_ = 0;
div_table_ = 0;
exp_table_ = 0;
mul_inverse_ = 0;
linear_exp_table_ = 0;
#endif
prim_poly_ = new unsigned int [prim_poly_deg_ + 1];
for (unsigned int i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_[i] = primitive_poly[i];
}
prim_poly_hash_ = 0xAAAAAAAA;
for (std::size_t i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_hash_ += ((i & 1) == 0) ? ( (prim_poly_hash_ << 7) ^ primitive_poly[i] * (prim_poly_hash_ >> 3)) :
(~((prim_poly_hash_ << 11) + (primitive_poly[i] ^ (prim_poly_hash_ >> 5))));
}
generate_field(primitive_poly);
}
inline field::~field()
{
if (0 != alpha_to_) { delete [] alpha_to_; alpha_to_ = 0; }
if (0 != index_of_) { delete [] index_of_; index_of_ = 0; }
if (0 != prim_poly_) { delete [] prim_poly_; prim_poly_ = 0; }
#if !defined(NO_GFLUT)
if (0 != mul_table_) { delete [] mul_table_; mul_table_ = 0; }
if (0 != div_table_) { delete [] div_table_; div_table_ = 0; }
if (0 != exp_table_) { delete [] exp_table_; exp_table_ = 0; }
#ifdef LINEAR_EXP_LUT
if (0 != linear_exp_table_) { delete [] linear_exp_table_; linear_exp_table_ = 0; }
#endif
if (0 != buffer_) { delete [] buffer_; buffer_ = 0; }
#endif
}
inline bool field::operator==(const field& gf) const
{
return (
(this->power_ == gf.power_) &&
(this->prim_poly_hash_ == gf.prim_poly_hash_)
);
}
inline bool field::operator!=(const field& gf) const
{
return !field::operator ==(gf);
}
inline void field::generate_field(const unsigned int* prim_poly)
{
/*
Note: It is assumed that the degree of the primitive
polynomial will be equivelent to the m value as
in GF(2^m)
*/
field_symbol mask = 1;
alpha_to_[power_] = 0;
for (field_symbol i = 0; i < static_cast<field_symbol>(power_); ++i)
{
alpha_to_[i] = mask;
index_of_[alpha_to_[i]] = i;
if (prim_poly[i] != 0)
{
alpha_to_[power_] ^= mask;
}
mask <<= 1;
}
index_of_[alpha_to_[power_]] = power_;
mask >>= 1;
for (field_symbol i = power_ + 1; i < static_cast<field_symbol>(field_size_); ++i)
{
if (alpha_to_[i - 1] >= mask)
alpha_to_[i] = alpha_to_[power_] ^ ((alpha_to_[i - 1] ^ mask) << 1);
else
alpha_to_[i] = alpha_to_[i - 1] << 1;
index_of_[alpha_to_[i]] = i;
}
index_of_[0] = GFERROR;
alpha_to_[field_size_] = 1;
#if !defined(NO_GFLUT)
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (field_symbol j = 0; j < static_cast<field_symbol>(field_size_ + 1); ++j)
{
mul_table_[i][j] = gen_mul(i,j);
div_table_[i][j] = gen_div(i,j);
exp_table_[i][j] = gen_exp(i,j);
}
}
#ifdef LINEAR_EXP_LUT
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (int j = 0; j < static_cast<field_symbol>(2 * field_size_); ++j)
{
linear_exp_table_[i][j] = gen_exp(i,j);
}
}
#endif
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
mul_inverse_[i] = gen_inverse(i);
mul_inverse_[i + (field_size_ + 1)] = mul_inverse_[i];
}
#endif
}
inline field_symbol field::gen_mul(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
}
inline field_symbol field::gen_div(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
}
inline field_symbol field::gen_exp(const field_symbol& a, const std::size_t& n) const
{
if (a != 0)
return ((n == 0) ? 1 : alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))]);
else
return 0;
}
inline field_symbol field::gen_inverse(const field_symbol& val) const
{
return alpha_to_[normalize(field_size_ - index_of_[val])];
}
inline std::size_t field::create_array(char buffer[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array)
{
const std::size_t row_size = length * sizeof(field_symbol);
(*array) = new(buffer + offset)field_symbol[length];
return row_size + offset;
}
inline std::size_t field::create_2d_array(char buffer[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array)
{
const std::size_t row_size = col_cnt * sizeof(field_symbol);
char* buffer__offset = buffer + offset;
(*array) = new field_symbol* [row_cnt];
for (std::size_t i = 0; i < row_cnt; ++i)
{
(*array)[i] = new(buffer__offset + (i * row_size))field_symbol[col_cnt];
}
return (row_cnt * row_size) + offset;
}
inline std::ostream& operator << (std::ostream& os, const field& gf)
{
for (std::size_t i = 0; i < (gf.field_size_ + 1); ++i)
{
os << i << "\t" << gf.alpha_to_[i] << "\t" << gf.index_of_[i] << std::endl;
}
return os;
}
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 */
const unsigned int primitive_polynomial00[] = {1, 1, 0, 1};
const unsigned int primitive_polynomial_size00 = 4;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4*/
const unsigned int primitive_polynomial01[] = {1, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size01 = 5;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 1x^5 */
const unsigned int primitive_polynomial02[] = {1, 0, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size02 = 6;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 */
const unsigned int primitive_polynomial03[] = {1, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size03 = 7;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 */
const unsigned int primitive_polynomial04[] = {1, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size04 = 8;
/* 1x^0 + 0x^1 + 1x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 1x^8 */
const unsigned int primitive_polynomial05[] = {1, 0, 1, 1, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size05 = 9;
/* 1x^0 + 1x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 + 1x^8 */
const unsigned int primitive_polynomial06[] = {1, 1, 1, 0, 0, 0, 0, 1, 1};
const unsigned int primitive_polynomial_size06 = 9;
/* 1x^0 + 0x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 1x^9 */
const unsigned int primitive_polynomial07[] = {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size07 = 10;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 */
const unsigned int primitive_polynomial08[] = {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size08 = 11;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 1x^11 */
const unsigned int primitive_polynomial09[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size09 = 12;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 */
const unsigned int primitive_polynomial10[] = {1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size10 = 13;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 1x^13 */
const unsigned int primitive_polynomial11[] = {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size11 = 14;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 + 0x^11 + 0x^12 + 0x^13 + 1x^14 */
const unsigned int primitive_polynomial12[] = {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size12 = 15;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 0x^13 + 0x^14 + 1x^15 */
const unsigned int primitive_polynomial13[] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size13 = 16;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 + 0x^13 + 0x^14 + 0x^15 + 1x^16 */
const unsigned int primitive_polynomial14[] = {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size14 = 17;
} // namespace galois
} // namespace schifra
#endif
+277
View File
@@ -0,0 +1,277 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
namespace schifra
{
namespace galois
{
class field_element
{
public:
field_element(const field& gfield)
: field_(gfield),
poly_value_(-1)
{}
field_element(const field& gfield,const field_symbol& v)
: field_(const_cast<field&>(gfield)),
poly_value_(v)
{}
field_element(const field_element& gfe)
: field_(const_cast<field&>(gfe.field_)),
poly_value_(gfe.poly_value_)
{}
~field_element()
{}
inline field_element& operator = (const field_element& gfe)
{
if ((this != &gfe) && (&field_ == &gfe.field_))
{
poly_value_ = gfe.poly_value_;
}
return *this;
}
inline field_element& operator = (const field_symbol& v)
{
poly_value_ = v & field_.size();
return *this;
}
inline field_element& operator += (const field_element& gfe)
{
poly_value_ ^= gfe.poly_value_;
return *this;
}
inline field_element& operator += (const field_symbol& v)
{
poly_value_ ^= v;
return *this;
}
inline field_element& operator -= (const field_element& gfe)
{
*this += gfe;
return *this;
}
inline field_element& operator -= (const field_symbol& v)
{
*this += v;
return *this;
}
inline field_element& operator *= (const field_element& gfe)
{
poly_value_ = field_.mul(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator *= (const field_symbol& v)
{
poly_value_ = field_.mul(poly_value_, v);
return *this;
}
inline field_element& operator /= (const field_element& gfe)
{
poly_value_ = field_.div(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator /= (const field_symbol& v)
{
poly_value_ = field_.div(poly_value_, v);
return *this;
}
inline field_element& operator ^= (const int& n)
{
poly_value_ = field_.exp(poly_value_,n);
return *this;
}
inline bool operator == (const field_element& gfe) const
{
return ((field_ == gfe.field_) && (poly_value_ == gfe.poly_value_));
}
inline bool operator == (const field_symbol& v) const
{
return (poly_value_ == v);
}
inline bool operator != (const field_element& gfe) const
{
return ((field_ != gfe.field_) || (poly_value_ != gfe.poly_value_));
}
inline bool operator != (const field_symbol& v) const
{
return (poly_value_ != v);
}
inline bool operator < (const field_element& gfe)
{
return (poly_value_ < gfe.poly_value_);
}
inline bool operator < (const field_symbol& v)
{
return (poly_value_ < v);
}
inline bool operator > (const field_element& gfe)
{
return (poly_value_ > gfe.poly_value_);
}
inline bool operator > (const field_symbol& v)
{
return (poly_value_ > v);
}
inline field_symbol index() const
{
return field_.index(poly_value_);
}
inline field_symbol poly() const
{
return poly_value_;
}
inline field_symbol& poly()
{
return poly_value_;
}
inline const field& galois_field() const
{
return field_;
}
inline field_symbol inverse() const
{
return field_.inverse(poly_value_);
}
inline void normalize()
{
poly_value_ &= field_.size();
}
friend std::ostream& operator << (std::ostream& os, const field_element& gfe);
private:
const field& field_;
field_symbol poly_value_;
};
inline field_element operator + (const field_element& a, const field_element& b);
inline field_element operator - (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_symbol& b);
inline field_element operator * (const field_symbol& a, const field_element& b);
inline field_element operator / (const field_element& a, const field_element& b);
inline field_element operator ^ (const field_element& a, const int& b);
inline std::ostream& operator << (std::ostream& os, const field_element& gfe)
{
os << gfe.poly_value_;
return os;
}
inline field_element operator + (const field_element& a, const field_element& b)
{
field_element result = a;
result += b;
return result;
}
inline field_element operator - (const field_element& a, const field_element& b)
{
field_element result = a;
result -= b;
return result;
}
inline field_element operator * (const field_element& a, const field_element& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_element& a, const field_symbol& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_symbol& a, const field_element& b)
{
field_element result = b;
result *= a;
return result;
}
inline field_element operator / (const field_element& a, const field_element& b)
{
field_element result = a;
result /= b;
return result;
}
inline field_element operator ^ (const field_element& a, const int& b)
{
field_element result = a;
result ^= b;
return result;
}
} // namespace galois
} // namespace schifra
#endif
@@ -0,0 +1,839 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#include <cassert>
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
namespace schifra
{
namespace galois
{
class field_polynomial
{
public:
field_polynomial(const field& gfield);
field_polynomial(const field& gfield, const unsigned int& degree);
field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[]);
field_polynomial(const field_polynomial& polynomial);
field_polynomial(const field_element& gfe);
~field_polynomial() {}
bool valid() const;
int deg() const;
const field& galois_field() const;
void set_degree(const unsigned int& x);
void simplify();
field_polynomial& operator = (const field_polynomial& polynomial);
field_polynomial& operator = (const field_element& element);
field_polynomial& operator += (const field_polynomial& element);
field_polynomial& operator += (const field_element& element);
field_polynomial& operator -= (const field_polynomial& element);
field_polynomial& operator -= (const field_element& element);
field_polynomial& operator *= (const field_polynomial& polynomial);
field_polynomial& operator *= (const field_element& element);
field_polynomial& operator /= (const field_polynomial& divisor);
field_polynomial& operator /= (const field_element& element);
field_polynomial& operator %= (const field_polynomial& divisor);
field_polynomial& operator %= (const unsigned int& power);
field_polynomial& operator ^= (const unsigned int& n);
field_polynomial& operator <<= (const unsigned int& n);
field_polynomial& operator >>= (const unsigned int& n);
field_element& operator[] (const std::size_t& term);
field_element operator() (const field_element& value);
field_element operator() (field_symbol value);
const field_element& operator[](const std::size_t& term) const;
const field_element operator()(const field_element& value) const;
const field_element operator()(field_symbol value) const;
bool operator==(const field_polynomial& polynomial) const;
bool operator!=(const field_polynomial& polynomial) const;
bool monic() const;
field_polynomial derivative() const;
friend std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial);
private:
typedef std::vector<field_element>::iterator poly_iter;
typedef std::vector<field_element>::const_iterator const_poly_iter;
void simplify(field_polynomial& polynomial) const;
field& field_;
std::vector<field_element> poly_;
};
field_polynomial operator + (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_element& b);
field_polynomial operator + (const field_element& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_symbol& b);
field_polynomial operator + (const field_symbol& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_element& b);
field_polynomial operator - (const field_element& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_symbol& b);
field_polynomial operator - (const field_symbol& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator * (const field_element& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_element& b);
field_polynomial operator / (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator / (const field_polynomial& a, const field_element& b);
field_polynomial operator % (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator % (const field_polynomial& a, const unsigned int& power);
field_polynomial operator ^ (const field_polynomial& a, const int& n);
field_polynomial operator <<(const field_polynomial& a, const unsigned int& n);
field_polynomial operator >>(const field_polynomial& a, const unsigned int& n);
field_polynomial gcd(const field_polynomial& a, const field_polynomial& b);
inline field_polynomial::field_polynomial(const field& gfield)
: field_(const_cast<field&>(gfield))
{
poly_.clear();
poly_.reserve(256);
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree)
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
poly_.resize(degree + 1,field_element(field_,0));
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[])
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
if (element != NULL)
{
/*
It is assumed that element is an array of field elements
with size/element count of degree + 1.
*/
for (unsigned int i = 0; i <= degree; ++i)
{
poly_.push_back(element[i]);
}
}
else
poly_.resize(degree + 1, field_element(field_, 0));
}
inline field_polynomial::field_polynomial(const field_polynomial& polynomial)
: field_(const_cast<field&>(polynomial.field_)),
poly_ (polynomial.poly_)
{}
inline field_polynomial::field_polynomial(const field_element& element)
: field_(const_cast<field&>(element.galois_field()))
{
poly_.resize(1,element);
}
inline bool field_polynomial::valid() const
{
return (poly_.size() > 0);
}
inline int field_polynomial::deg() const
{
return static_cast<int>(poly_.size()) - 1;
}
inline const field& field_polynomial::galois_field() const
{
return field_;
}
inline void field_polynomial::set_degree(const unsigned int& x)
{
poly_.resize(x - 1,field_element(field_,0));
}
inline field_polynomial& field_polynomial::operator = (const field_polynomial& polynomial)
{
if ((this != &polynomial) && (&field_ == &(polynomial.field_)))
{
poly_ = polynomial.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator = (const field_element& element)
{
if (&field_ == &(element.galois_field()))
{
poly_.resize(1,element);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
if (poly_.size() < polynomial.poly_.size())
{
const_poly_iter it0 = polynomial.poly_.begin();
for (poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
(*it1) += (*it0);
}
while (it0 != polynomial.poly_.end())
{
poly_.push_back(*it0);
++it0;
}
}
else
{
poly_iter it0 = poly_.begin();
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it0, ++it1)
{
(*it0) += (*it1);
}
}
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_element& element)
{
poly_[0] += element;
return *this;
}
inline field_polynomial& field_polynomial::operator -= (const field_polynomial& element)
{
return (*this += element);
}
inline field_polynomial& field_polynomial::operator -= (const field_element& element)
{
poly_[0] -= element;
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
field_polynomial product(field_,deg() + polynomial.deg() + 1);
poly_iter result_it = product.poly_.begin();
for (poly_iter it0 = poly_.begin(); it0 != poly_.end(); ++it0)
{
poly_iter current_result_it = result_it;
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it1)
{
(*current_result_it) += (*it0) * (*it1);
++current_result_it;
}
++result_it;
}
simplify(product);
poly_ = product.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) *= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_polynomial& divisor)
{
if (
(&field_ == &divisor.field_) &&
(deg() >= divisor.deg()) &&
(divisor.deg() >= 0)
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
simplify(quotient);
poly_ = quotient.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) /= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const field_polynomial& divisor)
{
if (
(field_ == divisor.field_) &&
(deg() >= divisor.deg() ) &&
(divisor.deg() >= 0 )
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
poly_ = remainder.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const unsigned int& power)
{
if (poly_.size() >= power)
{
poly_.resize(power,field_element(field_,0));
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator ^= (const unsigned int& n)
{
field_polynomial result = *this;
for (std::size_t i = 0; i < n; ++i)
{
result *= *this;
}
*this = result;
return *this;
}
inline field_polynomial& field_polynomial::operator <<= (const unsigned int& n)
{
if (poly_.size() > 0)
{
size_t initial_size = poly_.size();
poly_.resize(poly_.size() + n, field_element(field_,0));
for (size_t i = initial_size - 1; static_cast<int>(i) >= 0; --i)
{
poly_[i + n] = poly_[i];
}
for (unsigned int i = 0; i < n; ++i)
{
poly_[i] = 0;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator >>= (const unsigned int& n)
{
if (n <= poly_.size())
{
for (unsigned int i = 0; i <= deg() - n; ++i)
{
poly_[i] = poly_[i + n];
}
poly_.resize(poly_.size() - n,field_element(field_,0));
}
else if (static_cast<int>(n) >= (deg() + 1))
{
poly_.resize(0,field_element(field_,0));
}
return *this;
}
inline const field_element& field_polynomial::operator [] (const std::size_t& term) const
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element& field_polynomial::operator [] (const std::size_t& term)
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element field_polynomial::operator () (const field_element& value)
{
field_element result(field_,0);
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
result = total_sum;
}
return result;
}
inline const field_element field_polynomial::operator () (const field_element& value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline field_element field_polynomial::operator () (field_symbol value)
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline const field_element field_polynomial::operator () (field_symbol value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value, i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline bool field_polynomial::operator == (const field_polynomial& polynomial) const
{
if (field_ == polynomial.field_)
{
if (poly_.size() != polynomial.poly_.size())
return false;
else
{
const_poly_iter it0 = polynomial.poly_.begin();
for (const_poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
if ((*it0) != (*it1))
return false;
}
return true;
}
}
else
return false;
}
inline bool field_polynomial::operator != (const field_polynomial& polynomial) const
{
return !(*this == polynomial);
}
inline field_polynomial field_polynomial::derivative() const
{
if ((*this).poly_.size() > 1)
{
field_polynomial deriv(field_,deg());
const std::size_t upper_bound = poly_.size() - 1;
for (std::size_t i = 0; i < upper_bound; i += 2)
{
deriv.poly_[i] = poly_[i + 1];
}
simplify(deriv);
return deriv;
}
return field_polynomial(field_,0);
}
inline bool field_polynomial::monic() const
{
return (poly_[poly_.size() - 1] == static_cast<galois::field_symbol>(1));
}
inline void field_polynomial::simplify()
{
simplify(*this);
}
inline void field_polynomial::simplify(field_polynomial& polynomial) const
{
std::size_t poly_size = polynomial.poly_.size();
if ((poly_size > 0) && (polynomial.poly_.back() == 0))
{
poly_iter it = polynomial.poly_.end ();
poly_iter begin = polynomial.poly_.begin();
std::size_t count = 0;
while ((begin != it) && (*(--it) == 0))
{
++count;
}
if (0 != count)
{
polynomial.poly_.resize(poly_size - count, field_element(field_,0));
}
}
}
inline field_polynomial operator + (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result += a;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_symbol& b)
{
return a + field_element(a.galois_field(),b);
}
inline field_polynomial operator + (const field_symbol& a, const field_polynomial& b)
{
return b + field_element(b.galois_field(),a);
}
inline field_polynomial operator - (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result -= a;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_symbol& b)
{
return a - field_element(a.galois_field(),b);
}
inline field_polynomial operator - (const field_symbol& a, const field_polynomial& b)
{
return b - field_element(b.galois_field(),a);
}
inline field_polynomial operator * (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator * (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result *= a;
return result;
}
inline field_polynomial operator * (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result %= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result %= n;
return result;
}
inline field_polynomial operator ^ (const field_polynomial& a, const int& n)
{
field_polynomial result = a;
result ^= n;
return result;
}
inline field_polynomial operator << (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result <<= n;
return result;
}
inline field_polynomial operator >> (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result >>= n;
return result;
}
inline field_polynomial gcd(const field_polynomial& a, const field_polynomial& b)
{
if (&a.galois_field() == &b.galois_field())
{
if ((!a.valid()) && (!b.valid()))
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
if (!a.valid()) return b;
if (!b.valid()) return a;
field_polynomial x = a % b;
field_polynomial y = b;
field_polynomial z = x;
while ((z = (y % x)).valid())
{
y = x;
x = z;
}
return x;
}
else
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
}
inline field_polynomial generate_X(const field& gfield)
{
const field_element xgfe[2] = {
galois::field_element(gfield, 0),
galois::field_element(gfield, 1)
};
field_polynomial X_(gfield,1,xgfe);
return X_;
}
inline std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial)
{
if (polynomial.deg() >= 0)
{
/*
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly[i].index()
<< ((i != (polynomial.deg())) ? " " : "");
}
std::cout << " poly form: ";
*/
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly_[i].poly()
<< " "
<< "x^"
<< i
<< ((static_cast<int>(i) != (polynomial.deg())) ? " + " : "");
}
}
return os;
}
} // namespace galois
} // namespace schifra
#endif
+115
View File
@@ -0,0 +1,115 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#define INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <string>
#include <sstream>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
namespace galois
{
inline std::string convert_to_string(const unsigned int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_string(const int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_bin(const unsigned int& value, const unsigned int& field_descriptor)
{
std::string output = std::string(field_descriptor, ' ');
for (unsigned int i = 0; i < field_descriptor; ++i)
{
output[i] = ((((value >> (field_descriptor - 1 - i)) & 1) == 1) ? '1' : '0');
}
return output;
}
inline void alpha_table(std::ostream& os, const field& gf)
{
std::vector<std::string> str_list;
for (unsigned int i = 0; i < gf.size() + 1; ++i)
{
str_list.push_back("alpha^" + convert_to_string(gf.index(i),2) + "\t" +
convert_to_bin (i,gf.pwr()) + "\t" +
convert_to_string(gf.alpha(i),2));
}
std::sort(str_list.begin(),str_list.end());
std::copy(str_list.begin(),str_list.end(),std::ostream_iterator<std::string>(os,"\n"));
}
inline void polynomial_alpha_form(std::ostream& os, const field_polynomial& polynomial)
{
for (int i = 0; i < (polynomial.deg() + 1); ++i)
{
field_symbol alpha_power = polynomial.galois_field().index(polynomial[i].poly());
if (alpha_power != 0)
os << static_cast<unsigned char>(224) << "^" << convert_to_string(alpha_power,2);
else
os << 1;
os << " * "
<< "x^"
<< i
<< ((i != (polynomial.deg())) ? " + " : "");
}
}
inline void polynomial_alpha_form(std::ostream& os, const std::string& prepend, const field_polynomial& polynomial)
{
os << prepend;
polynomial_alpha_form(os,polynomial);
os << std::endl;
}
} // namespace reed_solomon
} // namespace schifra
#endif
+201
View File
@@ -0,0 +1,201 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#include <iostream>
namespace schifra
{
namespace reed_solomon
{
namespace bitio
{
template <std::size_t symbol_bit_count> class convert_data_to_symbol;
template <>
class convert_data_to_symbol<2>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=4)
{
(* s_it ) = (*d_it) & 0x03;
(*(s_it + 1)) = ((*d_it) >> 2) & 0x03;
(*(s_it + 2)) = ((*d_it) >> 4) & 0x03;
(*(s_it + 3)) = ((*d_it) >> 6) & 0x03;
}
}
};
template <>
class convert_data_to_symbol<4>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=2)
{
(* s_it ) = (*d_it) & 0x0F;
(*(s_it + 1)) = ((*d_it) >> 4) & 0x0F;
}
}
};
template <>
class convert_data_to_symbol<8>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*s_it) = (*d_it) & 0xFF;
}
}
};
template <>
class convert_data_to_symbol<16>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=2, d_it+=2, ++s_it)
{
(*s_it) = (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
}
}
};
template <>
class convert_data_to_symbol<24>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=3, d_it+=3, ++s_it)
{
(*s_it) |= (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
(*s_it) |= (static_cast<int>((*(d_it + 2))) << 16) & 0x00FF0000;
}
}
};
template <std::size_t symbol_bit_count> class convert_symbol_to_data;
template <>
class convert_symbol_to_data<4>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0x0000000F;
(*d_it) |= ((*(s_it + 1)) & 0x0000000F) << 4;
}
}
};
template <>
class convert_symbol_to_data<8>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = static_cast<BitBlock>((*s_it) & 0xFF);
}
}
};
template <>
class convert_symbol_to_data<16>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0xFFFF;
}
}
};
} // namespace bitio
} // namespace reed_solomon
} // namespace schifra
#endif
+382
View File
@@ -0,0 +1,382 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
struct block
{
public:
typedef galois::field_symbol symbol_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef traits::symbol<code_length> symbol;
typedef block<code_length,fec_length,data_length> block_t;
enum error_t
{
e_no_error = 0,
e_encoder_error0 = 1,
e_encoder_error1 = 2,
e_decoder_error0 = 3,
e_decoder_error1 = 4,
e_decoder_error2 = 5,
e_decoder_error3 = 6,
e_decoder_error4 = 7
};
block()
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
}
block(const std::string& _data, const std::string& _fec)
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = static_cast<galois::field_symbol>(_data[i]);
}
for (std::size_t i = 0; i < fec_length; ++i)
{
data[i + data_length] = static_cast<galois::field_symbol>(_fec[i]);
}
}
galois::field_symbol& operator[](const std::size_t& index)
{
return data[index];
}
const galois::field_symbol& operator[](const std::size_t& index) const
{
return data[index];
}
galois::field_symbol& operator()(const std::size_t& index)
{
return operator[](index);
}
galois::field_symbol& fec(const std::size_t& index)
{
return data[data_length + index];
}
bool data_to_string(std::string& data_str) const
{
if (data_str.length() != data_length)
{
return false;
}
for (std::size_t i = 0; i < data_length; ++i)
{
data_str[i] = static_cast<char>(data[i]);
}
return true;
}
bool fec_to_string(std::string& fec_str) const
{
if (fec_str.length() != fec_length)
{
return false;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_str[i] = static_cast<char>(data[data_length + i]);
}
return true;
}
std::string fec_to_string() const
{
std::string fec_str(fec_length,0x00);
fec_to_string(fec_str);
return fec_str;
}
void clear(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < code_length; ++i)
{
data[i] = value;
}
}
void clear_data(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = value;
}
}
void clear_fec(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < fec_length; ++i)
{
data[data_length + i] = value;
}
}
void reset(galois::field_symbol value = 0)
{
clear(value);
errors_detected = 0;
errors_corrected = 0;
zero_numerators = 0;
unrecoverable = false;
error = e_no_error;
}
template <typename BlockType>
void copy_state(const BlockType& b)
{
errors_detected = b.errors_detected;
errors_corrected = b.errors_corrected;
zero_numerators = b.zero_numerators;
unrecoverable = b.unrecoverable;
error = static_cast<error_t>(b.error);
}
inline std::string error_as_string() const
{
switch (error)
{
case e_no_error : return "No Error";
case e_encoder_error0 : return "Invalid Encoder";
case e_encoder_error1 : return "Incompatible Generator Polynomial";
case e_decoder_error0 : return "Invalid Decoder";
case e_decoder_error1 : return "Decoder Failure - Non-zero Syndrome";
case e_decoder_error2 : return "Decoder Failure - Too Many Errors/Erasures";
case e_decoder_error3 : return "Decoder Failure - Invalid Symbol Correction";
case e_decoder_error4 : return "Decoder Failure - Invalid Codeword Correction";
default : return "Invalid Error Code";
}
}
std::size_t errors_detected;
std::size_t errors_corrected;
std::size_t zero_numerators;
bool unrecoverable;
error_t error;
galois::field_symbol data[code_length];
};
template <std::size_t code_length, std::size_t fec_length>
inline void copy(const block<code_length,fec_length>& src_block, block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < code_length; ++index)
{
dest_block.data[index] = src_block.data[index];
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[], block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < (code_length - fec_length); ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[],
const std::size_t& src_length,
block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < src_length; ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
block<code_length,fec_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool copy(const T src_data[],
const std::size_t src_length,
block<code_length,fec_length> dest_block_stack[stack_size])
{
const std::size_t data_length = code_length - fec_length;
if (src_length > (stack_size * data_length))
{
return false;
}
const std::size_t row_count = src_length / data_length;
for (std::size_t row = 0; row < row_count; ++row, src_data += data_length)
{
copy(src_data, dest_block_stack[row]);
}
if ((src_length % data_length) != 0)
{
copy(src_data, src_length % data_length, dest_block_stack[row_count]);
}
return true;
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void full_copy(const block<code_length,fec_length>& src_block,
T dest_data[])
{
for (std::size_t i = 0; i < code_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
T dest_data[])
{
const std::size_t data_length = code_length - fec_length;
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < data_length; ++j, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block_stack[i][j]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline std::ostream& operator<<(std::ostream& os, const block<code_length,fec_length>& rs_block)
{
for (std::size_t i = 0; i < code_length; ++i)
{
os << static_cast<char>(rs_block[i]);
}
return os;
}
template <typename T, std::size_t block_length>
struct data_block
{
public:
typedef T value_type;
T& operator[](const std::size_t index) { return data[index]; }
const T& operator[](const std::size_t index) const { return data[index]; }
T* begin() { return data; }
const T* begin() const { return data; }
T* end() { return data + block_length; }
const T* end() const { return data + block_length; }
void clear(T value = 0)
{
for (std::size_t i = 0; i < block_length; ++i)
{
data[i] = value;
}
}
private:
T data[block_length];
};
template <typename T, std::size_t block_length>
inline void copy(const data_block<T,block_length>& src_block, data_block<T,block_length>& dest_block)
{
for (std::size_t index = 0; index < block_length; ++index)
{
dest_block[index] = src_block[index];
}
}
template <typename T, std::size_t block_length, std::size_t stack_size>
inline void copy(const data_block<T,block_length> src_block_stack[stack_size],
data_block<T,block_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t block_length>
inline void full_copy(const data_block<T,block_length>& src_block, T dest_data[])
{
for (std::size_t i = 0; i < block_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
typedef std::vector<std::size_t> erasure_locations_t;
} // namespace reed_solomon
} // namepsace schifra
#endif
@@ -0,0 +1,998 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length,
std::size_t fec_length,
typename encoder_type = encoder<code_length,fec_length>,
typename decoder_type = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
class codec_validator
{
public:
typedef block<code_length,fec_length> block_type;
codec_validator(const galois::field& gf,
const unsigned int gpii,
const std::string& msg)
: field_(gf),
generator_polynomial_(galois::field_polynomial(field_)),
rs_encoder_(reinterpret_cast<encoder_type*>(0)),
rs_decoder_(reinterpret_cast<decoder_type*>(0)),
message(msg),
genpoly_initial_index_(gpii),
blocks_processed_(0),
block_failures_(0)
{
traits::equivalent_encoder_decoder<encoder_type,decoder_type>();
if (
!make_sequential_root_generator_polynomial(field_,
genpoly_initial_index_,
fec_length,
generator_polynomial_)
)
{
return;
}
rs_encoder_ = new encoder_type(field_,generator_polynomial_);
rs_decoder_ = new decoder_type(field_,genpoly_initial_index_);
if (!rs_encoder_->encode(message,rs_block_original))
{
std::cout << "codec_validator() - ERROR: Encoding process failed!" << std::endl;
return;
}
}
bool execute()
{
schifra::utils::timer timer;
timer.start();
bool result = stage1() &&
stage2() &&
stage3() &&
stage4() &&
stage5() &&
stage6() &&
stage7() &&
stage8() &&
stage9() &&
stage10() &&
stage11() &&
stage12() ;
timer.stop();
double time = timer.time();
print_codec_properties();
std::cout << "Blocks decoded: " << blocks_processed_ <<
"\tDecoding Failures: " << block_failures_ <<
"\tRate: " << ((blocks_processed_ * data_length) * 8.0) / (1048576.0 * time) << "Mbps" << std::endl;
/*
Note: The throughput rate is not only the throughput of reed solomon
encoding and decoding, but also that of the steps needed to add
simulated transmission errors to the reed solomon block such as
the calculation of the positions and additions of errors and
erasures to the reed solomon block, which normally in a true
data transmission medium would not be taken into consideration.
*/
return result;
}
~codec_validator()
{
delete rs_encoder_;
delete rs_decoder_;
}
void print_codec_properties()
{
std::cout << "Codec: RS(" << code_length << "," << data_length << "," << fec_length <<") ";
}
private:
bool stage1()
{
/* Burst Error Only Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage1() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage1() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage1() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage2()
{
/* Burst Erasure Only Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage2() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
std::cout << "stage2() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage2() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage3()
{
/* Consecutive Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage3() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage3() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage3() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage4()
{
/* Consecutive Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage4() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage4() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage4() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage5()
{
/* Distanced Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,
erasure_count,
erasure_list,
between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage5() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage5() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage5() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage6()
{
/* Distanced Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list,between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage6() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage6() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage6() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage7()
{
/* Intermittent Error Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count < (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 1; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage7() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage7() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage7() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage8()
{
/* Intermittent Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 4; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage8() - Decoding Failure! start position: " << start_position << "\t scale: " << scale << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage8() - Error Correcting Failure! start position: " << start_position << "\t scale: " << scale <<std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != (rs_block.errors_corrected + rs_block.zero_numerators))
{
print_codec_properties();
std::cout << "stage8() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage9()
{
/* Burst Interleaved Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_interleaved_errors_erasures
(
rs_block,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage9() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage9() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage9() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage10()
{
/* Segmented Burst Errors */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t distance_between_blocks = 0; distance_between_blocks < 5; ++distance_between_blocks)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_segmented
(
rs_block,
start_position,
distance_between_blocks
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage10() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage10() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage10() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage11()
{
/* No Errors */
const std::size_t initial_failure_count = block_failures_;
block_type rs_block = rs_block_original;
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage11() - Decoding Failure!" << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.unrecoverable)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
++blocks_processed_;
return (block_failures_ == initial_failure_count);
}
bool stage12()
{
/* Random Errors Only */
const std::size_t initial_failure_count = block_failures_;
std::vector<std::size_t> random_error_index;
generate_error_index((fec_length >> 1),random_error_index,0xA5A5A5A5);
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t error_index = 0; error_index < error_index_size; ++error_index)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_at_index
(
rs_block,
error_count,
error_index,
random_error_index
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage12() - Decoding Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage12() - Error Correcting Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage12() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
protected:
codec_validator() {}
private:
codec_validator(const codec_validator&);
const codec_validator& operator=(const codec_validator&);
const galois::field& field_;
galois::field_polynomial generator_polynomial_;
encoder_type* rs_encoder_;
decoder_type* rs_decoder_;
block_type rs_block_original;
const std::string& message;
const unsigned int genpoly_initial_index_;
unsigned int blocks_processed_;
unsigned int block_failures_;
};
template <std::size_t data_length>
void create_messages(std::vector<std::string>& message_list, const bool full_test_set = false)
{
/* Various message bit patterns */
message_list.clear();
if (full_test_set)
{
for (std::size_t i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length, static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
}
template <std::size_t field_descriptor, std::size_t gen_poly_index, std::size_t code_length, std::size_t fec_length>
inline bool codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length>
validator(field, gen_poly_index, message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length>
inline bool shortened_codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
typedef shortened_encoder<code_length,fec_length> encoder_type;
typedef shortened_decoder<code_length,fec_length> decoder_type;
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length,encoder_type,decoder_type>
validator(field,gen_poly_index,message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
inline bool codec_validation_test00()
{
return codec_validation_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 22>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 24>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ;
}
inline bool codec_validation_test01()
{
return shortened_codec_validation_test<8,120,126,14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 1 RS Code */
shortened_codec_validation_test<8,120,194,16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 2 RS Code */
shortened_codec_validation_test<8,120,219,18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 3 RS Code */
shortened_codec_validation_test<8,120,225,20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 4 RS Code */
shortened_codec_validation_test<8, 1,204,16>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* DBV/MPEG-2 TSP RS Code */
shortened_codec_validation_test<8, 1,104,27>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Outer RS Code */
shortened_codec_validation_test<8, 1,204,12>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Inner RS Code */
shortened_codec_validation_test<8,120, 72,10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ; /* VDL Mode 3 RS Code */
}
} // namespace reed_solomon
} // namespace schifra
#endif
+485
View File
@@ -0,0 +1,485 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
decoder(const galois::field& field, const unsigned int& gen_initial_index = 0)
: decoder_valid_(field.size() == code_length),
field_(field),
X_(galois::generate_X(field_)),
gen_initial_index_(gen_initial_index)
{
if (decoder_valid_)
{
//Note: code_length and field size can be used interchangeably
create_lookup_tables();
}
};
const galois::field& field() const
{
return field_;
}
bool decode(block_type& rsblock) const
{
std::vector<std::size_t> erasure_list;
return decode(rsblock,erasure_list);
}
bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
if ((!decoder_valid_) || (erasure_list.size() > fec_length))
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error0;
return false;
}
galois::field_polynomial received(field_,code_length - 1);
load_message(received,rsblock);
galois::field_polynomial syndrome(field_);
if (compute_syndrome(received,syndrome) == 0)
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = false;
return true;
}
galois::field_polynomial lambda(galois::field_element(field_,1));
erasure_locations_t erasure_locations;
if (!erasure_list.empty())
{
prepare_erasure_list(erasure_locations, erasure_list);
compute_gamma(lambda, erasure_locations);
}
if (erasure_list.size() < fec_length)
{
modified_berlekamp_massey_algorithm(lambda, syndrome, erasure_list.size());
}
std::vector<int> error_locations;
find_roots(lambda, error_locations);
if (0 == error_locations.size())
{
/*
Syndrome is non-zero yet no error locations have
been obtained, conclusion:
It is possible that there are MORE errrors in the
message than can be detected and corrected for this
particular code.
*/
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error1;
return false;
}
else if (((2 * error_locations.size()) - erasure_list.size()) > fec_length)
{
/*
Too many errors\erasures! 2E + S <= fec_length
L = E + S
E = L - S
2E = 2L - 2S
2E + S = 2L - 2S + S
= 2L - S
Where:
L : Error Locations
E : Errors
S : Erasures
*/
rsblock.errors_detected = error_locations.size();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error2;
return false;
}
else
rsblock.errors_detected = error_locations.size();
return forney_algorithm(error_locations, lambda, syndrome, rsblock);
}
private:
decoder();
decoder(const decoder& dec);
decoder& operator=(const decoder& dec);
protected:
void load_message(galois::field_polynomial& received, const block_type& rsblock) const
{
/*
Load message data into received polynomial in reverse order.
*/
for (std::size_t i = 0; i < code_length; ++i)
{
received[code_length - 1 - i] = rsblock[i];
}
}
void create_lookup_tables()
{
root_exponent_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
root_exponent_table_.push_back(field_.exp(field_.alpha(code_length - i),(1 - gen_initial_index_)));
}
syndrome_exponent_table_.reserve(fec_length);
for (int i = 0; i < static_cast<int>(fec_length); ++i)
{
syndrome_exponent_table_.push_back(field_.alpha(gen_initial_index_ + i));
}
gamma_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
gamma_table_.push_back((1 + (X_ * galois::field_element(field_,field_.alpha(i)))));
}
}
void prepare_erasure_list(erasure_locations_t& erasure_locations, const erasure_locations_t& erasure_list) const
{
/*
Note: 1. Erasure positions must be unique.
2. Erasure positions must exist within the code block.
There are NO exceptions to these rules!
*/
erasure_locations.resize(erasure_list.size());
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
erasure_locations[i] = (code_length - 1 - erasure_list[i]);
}
}
int compute_syndrome(const galois::field_polynomial& received,
galois::field_polynomial& syndrome) const
{
int error_flag = 0;
syndrome = galois::field_polynomial(field_,fec_length - 1);
for (std::size_t i = 0; i < fec_length; ++i)
{
syndrome[i] = received(syndrome_exponent_table_[i]);
error_flag |= syndrome[i].poly();
}
return error_flag;
}
void compute_gamma(galois::field_polynomial& gamma, const erasure_locations_t& erasure_locations) const
{
for (std::size_t i = 0; i < erasure_locations.size(); ++i)
{
gamma *= gamma_table_[erasure_locations[i]];
}
}
void find_roots(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search: Find the roots of the error locator polynomial
via an exhaustive search over all non-zero elements in the
given finite field.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
const std::size_t polynomial_degree = poly.deg();
for (int i = 1; i <= static_cast<int>(code_length); ++i)
{
if (0 == poly(field_.alpha(i)).poly())
{
root_list.push_back(i);
if (polynomial_degree == root_list.size())
{
break;
}
}
}
}
void compute_discrepancy(galois::field_element& discrepancy,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t& l,
const std::size_t& round) const
{
/*
Compute the lambda discrepancy at the current round of BMA
*/
const std::size_t upper_bound = std::min(static_cast<int>(l), lambda.deg());
discrepancy = 0;
for (std::size_t i = 0; i <= upper_bound; ++i)
{
discrepancy += lambda[i] * syndrome[round - i];
}
}
void modified_berlekamp_massey_algorithm(galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t erasure_count) const
{
/*
Modified Berlekamp-Massey Algorithm
Identify the shortest length linear feed-back shift register (LFSR)
that will generate the sequence equivalent to the syndrome.
*/
int i = -1;
std::size_t l = erasure_count;
galois::field_element discrepancy(field_,0);
galois::field_polynomial previous_lambda = lambda << 1;
for (std::size_t round = erasure_count; round < fec_length; ++round)
{
compute_discrepancy(discrepancy, lambda, syndrome, l, round);
if (discrepancy != 0)
{
galois::field_polynomial tau = lambda - (discrepancy * previous_lambda);
if (static_cast<int>(l) < (static_cast<int>(round) - i))
{
const std::size_t tmp = round - i;
i = static_cast<int>(round - l);
l = tmp;
previous_lambda = lambda / discrepancy;
}
lambda = tau;
}
previous_lambda <<= 1;
}
}
bool forney_algorithm(const std::vector<int>& error_locations,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
block_type& rsblock) const
{
/*
The Forney algorithm for computing the error magnitudes
*/
const galois::field_polynomial omega = (lambda * syndrome) % fec_length;
const galois::field_polynomial lambda_derivative = lambda.derivative();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
for (std::size_t i = 0; i < error_locations.size(); ++i)
{
const unsigned int error_location = error_locations[i];
const galois::field_symbol alpha_inverse = field_.alpha(error_location);
const galois::field_symbol numerator = (omega(alpha_inverse) * root_exponent_table_[error_location]).poly();
const galois::field_symbol denominator = lambda_derivative(alpha_inverse).poly();
if (0 != numerator)
{
if (0 != denominator)
{
rsblock[error_location - 1] ^= field_.div(numerator, denominator);
rsblock.errors_corrected++;
}
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error3;
return false;
}
}
else
++rsblock.zero_numerators;
}
if (lambda.deg() == static_cast<int>(rsblock.errors_detected))
return true;
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error4;
return false;
}
}
protected:
bool decoder_valid_;
const galois::field& field_;
std::vector<galois::field_symbol> root_exponent_table_;
std::vector<galois::field_symbol> syndrome_exponent_table_;
std::vector<galois::field_polynomial> gamma_table_;
const galois::field_polynomial X_;
const unsigned int gen_initial_index_;
};
template <std::size_t code_length,
std::size_t fec_length,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
shortened_decoder(const galois::field& field, const unsigned int gen_initial_index = 0)
: decoder_(field, gen_initial_index)
{}
inline bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
erasure_locations_t shifted_position_erasure_list(erasure_list.size(),0);
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
shifted_position_erasure_list[i] = erasure_list[i] + padding_length;
}
if (decoder_.decode(block, shifted_position_erasure_list))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
inline bool decode(block_type& rsblock) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (decoder_.decode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
private:
typedef decoder<natural_length,fec_length> natural_decoder_type;
const natural_decoder_type decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif
+204
View File
@@ -0,0 +1,204 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class encoder
{
public:
typedef traits::reed_solomon_triat<code_length, fec_length,data_length> trait;
typedef block<code_length, fec_length> block_type;
encoder(const galois::field& gfield, const galois::field_polynomial& generator)
: encoder_valid_(code_length == gfield.size()),
field_(gfield),
generator_(generator)
{}
~encoder()
{}
inline bool encode(block_type& rsblock) const
{
if (!encoder_valid_)
{
rsblock.error = block_type::e_encoder_error0;
return false;
}
const galois::field_polynomial parities = msg_poly(rsblock) % generator_;
const galois::field_symbol mask = field_.mask();
if (parities.deg() == (fec_length - 1))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = parities[fec_length - 1 - i].poly() & mask;
}
}
else
{
/*
Note: Encoder should never branch here.
Possible issues to look for:
1. Generator polynomial degree is not equivelent to fec length
2. Field and code length are not consistent.
*/
rsblock.error = block_type::e_encoder_error1;
return false;
}
return true;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
std::string::const_iterator itr = data.begin();
const galois::field_symbol mask = field_.mask();
for (std::size_t i = 0; i < data_length; ++i, ++itr)
{
rsblock.data[i] = static_cast<typename block_type::symbol_type>(*itr) & mask;
}
return encode(rsblock);
}
private:
encoder();
encoder(const encoder& enc);
encoder& operator=(const encoder& enc);
inline galois::field_polynomial msg_poly(const block_type& rsblock) const
{
galois::field_polynomial message(field_, code_length);
for (std::size_t i = fec_length; i < code_length; ++i)
{
message[i] = rsblock.data[code_length - 1 - i];
}
return message;
}
const bool encoder_valid_;
const galois::field& field_;
const galois::field_polynomial generator_;
};
template <std::size_t code_length,
std::size_t fec_length ,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_encoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
typedef block<natural_length,fec_length> short_block_t;
shortened_encoder(const galois::field& gfield,
const galois::field_polynomial& generator)
: encoder_(gfield, generator)
{}
inline bool encode(block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = block.fec(i);
}
return true;
}
else
return false;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
return true;
}
else
return false;
}
private:
const encoder<natural_length,fec_length> encoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,171 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef typename decoder_type::block_type block_type;
file_decoder(const decoder_type& decoder,
const std::string& input_file_name,
const std::string& output_file_name)
: current_block_index_(0)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_decoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: output file could not be created." << std::endl;
return;
}
current_block_index_ = 0;
while (remaining_bytes >= code_length)
{
process_complete_block(decoder,in_stream,out_stream);
remaining_bytes -= code_length;
current_block_index_++;
}
if (remaining_bytes > 0)
{
process_partial_block(decoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_complete_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream)
{
in_stream.read(&buffer_[0],static_cast<std::streamsize>(code_length));
copy<char,code_length,fec_length>(buffer_,code_length,block_);
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_complete_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < data_length; ++i)
{
buffer_[i] = static_cast<char>(block_[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(data_length));
}
inline void process_partial_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
if (read_amount <= fec_length)
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
in_stream.read(&buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
block_.data[i] = static_cast<typename block_type::symbol_type>(buffer_[i]);
}
if ((read_amount - fec_length) < data_length)
{
for (std::size_t i = (read_amount - fec_length); i < data_length; ++i)
{
block_.data[i] = 0;
}
}
for (std::size_t i = 0; i < fec_length; ++i)
{
block_.fec(i) = static_cast<typename block_type::symbol_type>(buffer_[(read_amount - fec_length) + i]);
}
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
buffer_[i] = static_cast<char>(block_.data[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(read_amount - fec_length));
}
block_type block_;
std::size_t current_block_index_;
char buffer_[code_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,138 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#include <cstring>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef typename encoder_type::block_type block_type;
file_encoder(const encoder_type& encoder,
const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_encoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: output file could not be created." << std::endl;
return;
}
std::memset(data_buffer_,0,sizeof(data_buffer_));
std::memset(fec_buffer_ ,0,sizeof(fec_buffer_ ));
while (remaining_bytes >= data_length)
{
process_block(encoder,in_stream,out_stream,data_length);
remaining_bytes -= data_length;
}
if (remaining_bytes > 0)
{
process_block(encoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(const encoder_type& encoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
in_stream.read(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < read_amount; ++i)
{
block_.data[i] = (data_buffer_[i] & 0xFF);
}
if (read_amount < data_length)
{
for (std::size_t i = read_amount; i < data_length; ++i)
{
block_.data[i] = 0x00;
}
}
if (!encoder.encode(block_))
{
std::cout << "reed_solomon::file_encoder.process_block() - Error during encoding of block!" << std::endl;
return;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_buffer_[i] = static_cast<char>(block_.fec(i) & 0xFF);
}
out_stream.write(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
out_stream.write(&fec_buffer_[0],fec_length);
}
block_type block_;
char data_buffer_[data_length];
char fec_buffer_[fec_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,247 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#include <iostream>
#include <string>
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t stack_size>
class file_interleaver
{
public:
file_interleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (0 == remaining_bytes)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: output file could not be created." << std::endl;
return;
}
while (remaining_bytes >= (block_length * stack_size))
{
process_block(in_stream,out_stream);
remaining_bytes -= (block_length * stack_size);
}
if (remaining_bytes > 0)
{
process_incomplete_block(in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
interleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
interleave<char,block_length,stack_size>(block_stack_,complete_row_count);
else
interleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
template <std::size_t block_length, std::size_t stack_size>
class file_deinterleaver
{
public:
file_deinterleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t input_file_size = schifra::fileio::file_size(input_file_name);
if (input_file_size == 0)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: output file could not be created." << std::endl;
return;
}
for (std::size_t i = 0; i < (input_file_size / (block_length * stack_size)); ++i)
{
process_block(in_stream,out_stream);
}
if ((input_file_size % (block_length * stack_size)) != 0)
{
process_incomplete_block(in_stream,out_stream,(input_file_size % (block_length * stack_size)));
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
deinterleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
deinterleave<char,block_length>(block_stack_,complete_row_count);
else
deinterleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,210 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#define INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void* create_encoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
galois::field_polynomial gen_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
gen_polynomial)
)
{
return reinterpret_cast<void*>(0);
}
return new encoder<code_length,fec_length>(field,gen_polynomial);
}
template <std::size_t code_length, std::size_t fec_length>
void* create_decoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
return new decoder<code_length,fec_length>(field,static_cast<unsigned int>(gen_poly_index));
}
template <std::size_t code_length, std::size_t max_fec_length = 128>
class general_codec
{
public:
general_codec(const galois::field& field,
const std::size_t& gen_poly_index)
{
for (std::size_t i = 0; i < max_fec_length; ++i)
{
encoder_[i] = 0;
decoder_[i] = 0;
}
encoder_[ 2] = create_encoder<code_length, 2>(field, gen_poly_index);
encoder_[ 4] = create_encoder<code_length, 4>(field, gen_poly_index);
encoder_[ 6] = create_encoder<code_length, 6>(field, gen_poly_index);
encoder_[ 8] = create_encoder<code_length, 8>(field, gen_poly_index);
encoder_[ 10] = create_encoder<code_length, 10>(field, gen_poly_index);
encoder_[ 12] = create_encoder<code_length, 12>(field, gen_poly_index);
encoder_[ 14] = create_encoder<code_length, 14>(field, gen_poly_index);
encoder_[ 16] = create_encoder<code_length, 16>(field, gen_poly_index);
encoder_[ 18] = create_encoder<code_length, 18>(field, gen_poly_index);
encoder_[ 20] = create_encoder<code_length, 20>(field, gen_poly_index);
encoder_[ 22] = create_encoder<code_length, 22>(field, gen_poly_index);
encoder_[ 24] = create_encoder<code_length, 24>(field, gen_poly_index);
encoder_[ 26] = create_encoder<code_length, 26>(field, gen_poly_index);
encoder_[ 28] = create_encoder<code_length, 28>(field, gen_poly_index);
encoder_[ 30] = create_encoder<code_length, 30>(field, gen_poly_index);
encoder_[ 32] = create_encoder<code_length, 32>(field, gen_poly_index);
encoder_[ 64] = create_encoder<code_length, 64>(field, gen_poly_index);
encoder_[ 80] = create_encoder<code_length, 80>(field, gen_poly_index);
encoder_[ 96] = create_encoder<code_length, 96>(field, gen_poly_index);
encoder_[128] = create_encoder<code_length,128>(field, gen_poly_index);
decoder_[ 2] = create_decoder<code_length, 2>(field, gen_poly_index);
decoder_[ 4] = create_decoder<code_length, 4>(field, gen_poly_index);
decoder_[ 6] = create_decoder<code_length, 6>(field, gen_poly_index);
decoder_[ 8] = create_decoder<code_length, 8>(field, gen_poly_index);
decoder_[ 10] = create_decoder<code_length, 10>(field, gen_poly_index);
decoder_[ 12] = create_decoder<code_length, 12>(field, gen_poly_index);
decoder_[ 14] = create_decoder<code_length, 14>(field, gen_poly_index);
decoder_[ 16] = create_decoder<code_length, 16>(field, gen_poly_index);
decoder_[ 18] = create_decoder<code_length, 18>(field, gen_poly_index);
decoder_[ 20] = create_decoder<code_length, 20>(field, gen_poly_index);
decoder_[ 22] = create_decoder<code_length, 22>(field, gen_poly_index);
decoder_[ 24] = create_decoder<code_length, 24>(field, gen_poly_index);
decoder_[ 26] = create_decoder<code_length, 26>(field, gen_poly_index);
decoder_[ 28] = create_decoder<code_length, 28>(field, gen_poly_index);
decoder_[ 30] = create_decoder<code_length, 30>(field, gen_poly_index);
decoder_[ 32] = create_decoder<code_length, 32>(field, gen_poly_index);
decoder_[ 64] = create_decoder<code_length, 64>(field, gen_poly_index);
decoder_[ 80] = create_decoder<code_length, 80>(field, gen_poly_index);
decoder_[ 96] = create_decoder<code_length, 96>(field, gen_poly_index);
decoder_[128] = create_decoder<code_length,128>(field, gen_poly_index);
}
~general_codec()
{
delete static_cast<reed_solomon::encoder<code_length, 2>*>(encoder_[ 2]);
delete static_cast<reed_solomon::encoder<code_length, 4>*>(encoder_[ 4]);
delete static_cast<reed_solomon::encoder<code_length, 6>*>(encoder_[ 6]);
delete static_cast<reed_solomon::encoder<code_length, 8>*>(encoder_[ 8]);
delete static_cast<reed_solomon::encoder<code_length, 10>*>(encoder_[ 10]);
delete static_cast<reed_solomon::encoder<code_length, 12>*>(encoder_[ 12]);
delete static_cast<reed_solomon::encoder<code_length, 14>*>(encoder_[ 14]);
delete static_cast<reed_solomon::encoder<code_length, 16>*>(encoder_[ 16]);
delete static_cast<reed_solomon::encoder<code_length, 18>*>(encoder_[ 18]);
delete static_cast<reed_solomon::encoder<code_length, 20>*>(encoder_[ 20]);
delete static_cast<reed_solomon::encoder<code_length, 22>*>(encoder_[ 22]);
delete static_cast<reed_solomon::encoder<code_length, 24>*>(encoder_[ 24]);
delete static_cast<reed_solomon::encoder<code_length, 26>*>(encoder_[ 26]);
delete static_cast<reed_solomon::encoder<code_length, 28>*>(encoder_[ 28]);
delete static_cast<reed_solomon::encoder<code_length, 30>*>(encoder_[ 30]);
delete static_cast<reed_solomon::encoder<code_length, 32>*>(encoder_[ 32]);
delete static_cast<reed_solomon::encoder<code_length, 64>*>(encoder_[ 64]);
delete static_cast<reed_solomon::encoder<code_length, 80>*>(encoder_[ 80]);
delete static_cast<reed_solomon::encoder<code_length, 96>*>(encoder_[ 96]);
delete static_cast<reed_solomon::encoder<code_length,128>*>(encoder_[128]);
delete static_cast<reed_solomon::decoder<code_length, 2>*>(decoder_[ 2]);
delete static_cast<reed_solomon::decoder<code_length, 4>*>(decoder_[ 4]);
delete static_cast<reed_solomon::decoder<code_length, 6>*>(decoder_[ 6]);
delete static_cast<reed_solomon::decoder<code_length, 8>*>(decoder_[ 8]);
delete static_cast<reed_solomon::decoder<code_length, 10>*>(decoder_[ 10]);
delete static_cast<reed_solomon::decoder<code_length, 12>*>(decoder_[ 12]);
delete static_cast<reed_solomon::decoder<code_length, 14>*>(decoder_[ 14]);
delete static_cast<reed_solomon::decoder<code_length, 16>*>(decoder_[ 16]);
delete static_cast<reed_solomon::decoder<code_length, 18>*>(decoder_[ 18]);
delete static_cast<reed_solomon::decoder<code_length, 20>*>(decoder_[ 20]);
delete static_cast<reed_solomon::decoder<code_length, 22>*>(decoder_[ 22]);
delete static_cast<reed_solomon::decoder<code_length, 24>*>(decoder_[ 24]);
delete static_cast<reed_solomon::decoder<code_length, 26>*>(decoder_[ 26]);
delete static_cast<reed_solomon::decoder<code_length, 28>*>(decoder_[ 28]);
delete static_cast<reed_solomon::decoder<code_length, 30>*>(decoder_[ 30]);
delete static_cast<reed_solomon::decoder<code_length, 32>*>(decoder_[ 32]);
delete static_cast<reed_solomon::decoder<code_length, 64>*>(decoder_[ 64]);
delete static_cast<reed_solomon::decoder<code_length, 80>*>(decoder_[ 80]);
delete static_cast<reed_solomon::decoder<code_length, 96>*>(decoder_[ 96]);
delete static_cast<reed_solomon::decoder<code_length,128>*>(decoder_[128]);
}
template <typename Block>
bool encode(Block& block) const
{
/*
cl : code length
fl : fec length
*/
typedef reed_solomon::encoder<Block::trait::code_length,Block::trait::fec_length> encoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (encoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<encoder_type*>(encoder_[Block::trait::fec_length])->encode(block);
}
template <typename Block>
bool decode(Block& block) const
{
typedef reed_solomon::decoder<Block::trait::code_length,Block::trait::fec_length> decoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (decoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<decoder_type*>(decoder_[Block::trait::fec_length])->decode(block);
}
private:
void* encoder_[max_fec_length + 1];
void* decoder_[max_fec_length + 1];
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,639 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_reed_solomon_block.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
inline void interleave(block<code_length,fec_length> (&block_stack)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
for (std::size_t j = i + 1; j < code_length; ++j)
{
typename block<code_length,fec_length>::symbol_type tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length,row_count> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
interleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length,row_count> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_code_length; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length - fec_length; ++index)
{
block_stack[row].data[index] = auxiliary_stack[row].data[index];
}
for (std::size_t index = 0; index < fec_length; ++index)
{
block_stack[row].fec[index] = auxiliary_stack[row].fec[index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> (&block_stack)[block_length])
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count],
const std::size_t partial_block_length)
{
if (partial_block_length == block_length)
{
interleave<T,block_length,row_count>(block_stack);
}
else
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
deinterleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_code_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < code_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> (&block_stack)[block_length])
{
data_block<T,block_length> auxiliary_stack[block_length];
for (std::size_t row = 0; row < block_length; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[index][row] = block_stack[row][index];
}
}
copy<T,block_length,block_length>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void deinterleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
if (row_count == 1) return;
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_block_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < block_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack)
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
std::size_t x1 = i + skip_columns;
std::size_t x2 = j + skip_columns;
T tmp = block_stack[i][x2];
block_stack[i][x2] = block_stack[j][x1];
block_stack[j][x1] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack, const std::size_t& row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = skip_columns;
for (std::size_t index = skip_columns; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = skip_columns;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = skip_columns; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t data_length>
inline void interleave(T* block_stack[data_length])
{
for (std::size_t i = 0; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t data_length, std::size_t skip_columns>
inline void interleave_columnskip(T* block_stack[data_length])
{
for (std::size_t i = skip_columns; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,238 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#include <cstddef>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_reed_solomon_bitio.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_encoder(const encoder_type& enc)
: encoder_(enc)
{}
bool encode(data_ptr_type data)
{
data_ptr_type curr_data_ptr = data;
for (std::size_t row = 0; row < data_length; ++row, curr_data_ptr += data_length)
{
copy(curr_data_ptr, data_length, block_stack_[row]);
if (!encoder_.encode(block_stack_[row]))
{
return false;
}
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
if (!encoder_.encode(vertical_block))
{
return false;
}
for (std::size_t fec_index = 0; fec_index < fec_length; ++fec_index)
{
block_stack_[data_length + fec_index].fec(fec_index) = vertical_block.fec(fec_index);
}
}
return true;
}
bool encode_and_interleave(data_ptr_type data)
{
if (!encode(data))
{
return false;
}
interleave<code_length,fec_length>(block_stack_);
return true;
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < code_length; ++row, output_data += code_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,code_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_encoder(const square_product_code_encoder& spce);
square_product_code_encoder& operator=(const square_product_code_encoder& spce);
block_type block_stack_[code_length];
const encoder_type& encoder_;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_decoder(const decoder_type& decoder)
: decoder_(decoder)
{}
void decode(data_ptr_type data)
{
copy_proxy(data);
decode_proxy();
}
void deinterleave_and_decode(data_ptr_type data)
{
copy_proxy(data);
interleave<code_length,fec_length>(block_stack_);
decode_proxy();
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < data_length; ++row, output_data += data_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,data_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_decoder(const square_product_code_decoder& spcd);
square_product_code_decoder& operator=(const square_product_code_decoder& spcd);
void copy_proxy(data_ptr_type data)
{
for (std::size_t row = 0; row < code_length; ++row, data += code_length)
{
bitio::convert_data_to_symbol<traits::symbol<code_length>::size>(data,code_length,block_stack_[row].data);
}
}
void decode_proxy()
{
bool first_iteration_failure = false;
for (std::size_t row = 0; row < data_length; ++row)
{
if (!decoder_.decode(block_stack_[row]))
{
first_iteration_failure = true;
}
}
if (!first_iteration_failure)
{
/*
Either no errors detected or all errors have
been detected and corrected.
*/
return;
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
decoder_.decode(vertical_block);
}
}
block_type block_stack_[code_length];
const decoder_type& decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,411 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_file_encoder.hpp"
#include "schifra_reed_solomon_file_decoder.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void create_messages(const encoder<code_length,fec_length>& rs_encoder,
std::vector< block<code_length,fec_length> >& original_block_list,
const bool full_test_set = false)
{
const std::size_t data_length = code_length - fec_length;
std::vector<std::string> message_list;
if (full_test_set)
{
for (unsigned int i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF)) ;
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
block<code_length,fec_length> current_block;
rs_encoder.encode(message_list[i],current_block);
original_block_list.push_back(current_block);
}
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_errors_decoder_speed_test
{
public:
all_errors_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
corrupt_message_all_errors(block,error_count,start_position,1);
rs_block.push_back(block);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Errors Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_erasures_decoder_speed_test
{
public:
all_erasures_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<erasure_locations_t> erasure_list;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
erasure_locations_t erasures;
corrupt_message_all_erasures(block,erasures,erasure_count,start_position,1);
if (erasure_count != erasures.size())
{
std::cout << "all_erasures_decoder_speed_test() - Failed to properly generate erasures list. Details:";
std::cout << "(" << block_index << "," << erasure_count << "," << start_position << ")" << std::endl;
}
rs_block.push_back(block);
erasure_list.push_back(erasures);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i],erasure_list[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Erasures Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
void speed_test_00()
{
all_errors_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
void speed_test_01()
{
all_erasures_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
} // namespace reed_solomon
} // namespace schifra
#endif
@@ -0,0 +1,64 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#define INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#include <cstddef>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
inline bool make_sequential_root_generator_polynomial(const galois::field& field,
const std::size_t initial_index,
const std::size_t num_elements,
galois::field_polynomial& generator_polynomial)
{
if (
(initial_index >= field.size()) ||
((initial_index + num_elements) > field.size())
)
{
return false;
}
galois::field_element alpha(field, 2);
galois::field_polynomial X = galois::generate_X(field);
generator_polynomial = galois::field_element(field, 1);
for (std::size_t i = initial_index; i < (initial_index + num_elements); ++i)
{
generator_polynomial *= (X + (alpha ^ static_cast<galois::field_symbol>(i)));
}
return true;
}
} // namespace schifra
#endif
+198
View File
@@ -0,0 +1,198 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_UTILITES_HPP
#define INCLUDE_SCHIFRA_UTILITES_HPP
#include <cstddef>
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#include <windows.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#endif
namespace schifra
{
namespace utils
{
const std::size_t high_bits_in_char[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
template <typename T>
inline std::size_t hamming_distance_element(const T v1, const T v2)
{
std::size_t distance = 0;
const unsigned char* it1 = reinterpret_cast<const unsigned char*>(&v1);
const unsigned char* it2 = reinterpret_cast<const unsigned char*>(&v2);
for (std::size_t i = 0; i < sizeof(T); ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
inline std::size_t hamming_distance(const unsigned char data1[], const unsigned char data2[], const std::size_t length)
{
std::size_t distance = 0;
const unsigned char* it1 = data1;
const unsigned char* it2 = data2;
for (std::size_t i = 0; i < length; ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
template <typename ForwardIterator>
inline std::size_t hamming_distance(ForwardIterator it1_begin, ForwardIterator it2_begin, ForwardIterator it1_end)
{
std::size_t distance = 0;
ForwardIterator it1 = it1_begin;
ForwardIterator it2 = it2_begin;
for (; it1 != it1_end; ++it1, ++it2)
{
distance += hamming_distance_element(*it1,*it2);
}
return distance;
}
class timer
{
public:
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
timer()
: in_use_(false)
{
QueryPerformanceFrequency(&clock_frequency_);
}
inline void start()
{
in_use_ = true;
QueryPerformanceCounter(&start_time_);
}
inline void stop()
{
QueryPerformanceCounter(&stop_time_);
in_use_ = false;
}
inline double time() const
{
return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart);
}
#else
timer()
: in_use_(false)
{
start_time_.tv_sec = 0;
start_time_.tv_usec = 0;
stop_time_.tv_sec = 0;
stop_time_.tv_usec = 0;
}
inline void start()
{
in_use_ = true;
gettimeofday(&start_time_,0);
}
inline void stop()
{
gettimeofday(&stop_time_, 0);
in_use_ = false;
}
inline unsigned long long int usec_time() const
{
if (!in_use_)
{
if (stop_time_.tv_sec >= start_time_.tv_sec)
{
return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) +
(stop_time_.tv_usec - start_time_.tv_usec);
}
else
return std::numeric_limits<unsigned long long int>::max();
}
else
return std::numeric_limits<unsigned long long int>::max();
}
inline double time() const
{
return usec_time() * 0.000001;
}
#endif
inline bool in_use() const
{
return in_use_;
}
private:
bool in_use_;
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
LARGE_INTEGER start_time_;
LARGE_INTEGER stop_time_;
LARGE_INTEGER clock_frequency_;
#else
struct timeval start_time_;
struct timeval stop_time_;
#endif
};
} // namespace utils
} // namespace schifra
#endif