My C++ Reed–Solomon code, ported to the browser so you can encode real bytes, corrupt a symbol, and watch the syndromes react — without a compiler. Flip between basic (evaluation encoder) and prod (systematic encoder + syndrome detector); the logic matches the source on the right line-for-line.

Playground

codeword

stdout


            

Source (C++)

#include <iostream>
        #include <vector>
        #include <cstdint>
        #include <stdexcept>
        using namespace std;

        // ── GF(2^8) arithmetic ──
        uint8_t gf_add(uint8_t a, uint8_t b) { return a ^ b; }

        uint8_t xtime(uint8_t value) {
            bool overflow = value & 0x80;
            value <<= 1;
            if (overflow) value ^= 0x1B;          // x^8 = x^4 + x^3 + x + 1
            return value;
        }

        uint8_t gf_mul(uint8_t x, uint8_t y) {
            uint8_t result = 0;
            while (y != 0) {
                if (y & 1) result ^= x;
                x = xtime(x);
                y >>= 1;
            }
            return result;
        }

        uint8_t gf_inverse(uint8_t value) {
            if (value == 0) throw runtime_error("zero has no multiplicative inverse");
            for (int candidate = 1; candidate < 256; candidate++)
                if (gf_mul(value, candidate) == 1) return candidate;
            throw runtime_error("inverse not found");
        }

        uint8_t gf_div(uint8_t a, uint8_t b) { return gf_mul(a, gf_inverse(b)); }

        // ── polynomials, ascending order: {3,5,7} = 3 + 5x + 7x^2 ──
        vector<uint8_t> poly_mul(const vector<uint8_t>& a, const vector<uint8_t>& b) {
            vector<uint8_t> result(a.size() + b.size() - 1, 0);
            for (size_t i = 0; i < a.size(); i++)
                for (size_t j = 0; j < b.size(); j++)            // x^i * x^j = x^(i+j)
                    result[i+j] = gf_add(result[i+j], gf_mul(a[i], b[j]));
            return result;
        }

        vector<uint8_t> poly_mod(vector<uint8_t> dividend, const vector<uint8_t>& divisor) {
            while (dividend.size() >= divisor.size()) {
                uint8_t lead = dividend.back();
                if (lead == 0) { dividend.pop_back(); continue; }
                uint8_t factor = gf_div(lead, divisor.back());   // cancel the top term
                for (size_t i = 0; i < divisor.size(); i++) {
                    int di = dividend.size() - divisor.size() + i;
                    dividend[di] = gf_add(dividend[di], gf_mul(divisor[i], factor));
                }
                while (!dividend.empty() && dividend.back() == 0) dividend.pop_back();
            }
            return dividend;                                      // remainder
        }

        // G(x) = (x + a)(x + a^2) ... (x + a^parity),  a = 2
        vector<uint8_t> generator_polynomial(int paritySymbols) {
            vector<uint8_t> generator = {1};
            uint8_t alpha = 2;
            for (int i = 0; i < paritySymbols; i++) {
                generator = poly_mul(generator, {alpha, 1});
                alpha = gf_mul(alpha, 2);
            }
            return generator;
        }

        vector<uint8_t> systematic_encode(const vector<uint8_t>& message, int paritySymbols) {
            auto generator = generator_polynomial(paritySymbols);

            vector<uint8_t> dividend(paritySymbols, 0);
            dividend.insert(dividend.end(), message.begin(), message.end());   // M(x) * x^parity
            auto parity = poly_mod(dividend, generator);
            parity.resize(paritySymbols, 0);

            // Parity goes in the LOW-order coefficients, message above it, so the
            // codeword stays divisible by G(x). (My first draft did message ‖ parity,
            // which left a clean word with NON-zero syndromes — the bug below.)
            vector<uint8_t> codeword = parity;
            codeword.insert(codeword.end(), message.begin(), message.end());
            return codeword;
        }

        uint8_t evaluate_polynomial(const vector<uint8_t>& poly, uint8_t x) {
            uint8_t result = 0, power = 1;
            for (uint8_t coefficient : poly) {
                result = gf_add(result, gf_mul(coefficient, power));
                power  = gf_mul(power, x);
            }
            return result;
        }

        // syndromes: evaluate the received word at a, a^2, ... a^parity (roots of G).
        vector<uint8_t> syndrome(const vector<uint8_t>& codeword, int paritySymbols) {
            vector<uint8_t> s;
            uint8_t alpha = 2;
            for (int i = 0; i < paritySymbols; i++) {
                s.push_back(evaluate_polynomial(codeword, alpha));
                alpha = gf_mul(alpha, 2);
            }
            return s;
        }

        // roots of the error-locator are the error positions.
        vector<int> chien_search(const vector<uint8_t>& locator) {
            vector<int> positions;
            uint8_t alpha = 1;
            for (int i = 0; i < 255; i++) {
                if (evaluate_polynomial(locator, alpha) == 0) positions.push_back(i);
                alpha = gf_mul(alpha, 2);
            }
            return positions;
        }

        // next stage — find Lambda(x), its roots, then the magnitudes (still stubbed).
        vector<uint8_t> berlekamp_massey(const vector<uint8_t>& syndromes);
        vector<uint8_t> forney(const vector<uint8_t>& s,
                               const vector<uint8_t>& locator,
                               const vector<int>& positions);

        vector<uint8_t> decode(vector<uint8_t> codeword, int paritySymbols) {
            auto s = syndrome(codeword, paritySymbols);

            bool hasError = false;
            for (uint8_t x : s) if (x != 0) { hasError = true; break; }
            if (!hasError) return codeword;            // syndromes all zero -> clean

            // auto locator    = berlekamp_massey(s);
            // auto positions  = chien_search(locator);
            // auto magnitudes = forney(s, locator, positions);
            // for (size_t i = 0; i < positions.size(); i++)
            //     codeword[positions[i]] ^= magnitudes[i];
            return codeword;                            // detection only, for now
        }

        int main() {
            string text = "Hello";
            vector<uint8_t> message(text.begin(), text.end());
            auto codeword = systematic_encode(message, 4);
            auto s = syndrome(codeword, 4);             // {0, 0, 0, 0} when clean
            auto out = decode(codeword, 4);
        }