リードソロモン(RS)符号によるECC

データ伝送時には避けて通れない伝送誤り。エラーという。

パソコン上でデータを扱う際に意識することはないが、データを物理的に変換して転送する機会があれば、ノイズその他の外来要因によって容易に発生する。

CD、DVD、HDD、SSDなどの各種ディスク、イーサネットやBluetoothなどの伝送、QRコードの読み取りなど、エラー検出・訂正がなければ成立しないといっても過言ではない。

通常、ユーザーから見えない裏側で、このような処理が行われている。

エラー検出としてCRCなどが有名であるが、さらに訂正機能を持つ符号(ECC=error correcting code)としてリードソロモン符号(RS符号)の生成方法について記載する。RS符号はCD/DVD、地上波デジタルなどで幅広く使用されているコードである。

  • ガロア拡大体(α、GF(2^8))と多項式(ベクトル)表現の変換表を原始多項式(通常0x11d)で定義する。(init_galois_alpha_table())
  • 入力データを多項式表現と見立て、αに変換する。
  • 入力データ列を生成多項式で除算する。ガロア拡大体上で演算する。(ecc_rs_generate_by_mod::generate())
  • 余りをECCデータ(RS符号)とする。
  • ECCを加えたデータ列は、簡単な計算でエラーの有無を判別できる。(test())
  • エラーを訂正するには、シンドロームを算出し、位置多項式よりエラー位置を算出、その式からエラー位置と内容を特定して訂正する。(repair())

クラス化して自由に利用できるようにしたので、いろいろと応用可能。詳しい使い方はmain()を参照願います。

//リードソロモン符号によるECCライブラリ(ecc_rsクラス)
//version 1.0
//Copyright (C) 2021 Shigeno Sho, Subaudio Software

#include <iostream>
#include "ecc_rs.h"

#include <windows.h>
#pragma comment(lib, "winmm.lib")

#define PRINT_DEBUG_MESSAGES

#ifdef PRINT_DEBUG_MESSAGES
void print_matrix( unsigned char **matrix, int rows, int columns, unsigned char *rev_alpha )
{
    int i, l;

    for( i = 0; i < rows; i++ ){
        for( l = 0; l < columns; l++ ){
            if( matrix[ i ][ l ] == 1 )
                printf( "      1");
            else if( matrix[ i ][ l ] )
                printf( " α^%03d", rev_alpha[ matrix[ i ][ l ] ] );
            else
                printf( "      0");
        }
        printf( "\n" );
    }
    printf( "\n" );
}
#endif

//ガロア拡大体のα⇔ベクトル表現テーブルを準備する
//生成に必要な原始多項式はコンストラクタで定義しておく
void ecc_rs_base::init_galois_alpha_table( void )
{
    int i, temp;

    this->rev_alpha[ 0 ] = 0;         //0はαで表現できない
    temp = 1;
    for( i = 0; i < 255; i++ ){
        this->alpha[ i ] = ( unsigned char )( temp & 0xff );
        this->rev_alpha[ temp & 0xff ] = i;
        temp <<= 1;
        if( temp & 0x100 )
            temp ^= this->primitive_polynominal;
    }

#ifdef PRINT_DEBUG_MESSAGES
    for( i = 0; i < 255; i++ ){
        printf( " α^%d = %x", i, this->alpha[ i ] );
        printf( "\t%x = α^%d", i, this->rev_alpha[ i ] );
        printf( "\n" );
    }
    printf( "\n\n" );
#endif
}

//生成多項式を生成する
//生成多項式generative_polynominal = Π(i=0, 2t-1){x-α^i}
//gp[0]はx^0の係数,gp[1]はx^1の係数...と、配列の添字は各xの乗数位置の係数を意味する
//入力データを生成多項式で除算した余りとしてのECCを求めるために使用する。
//生成したgenerative_polynominalはgenerate_ecc_by_mod()で使用される。
void ecc_rs_generate_by_mod::init_generative_polynominal( void )
{
    int i, l;
    unsigned char gp_temp[ 257 ];

    //まず初期化する
    for( i = 0; i < 2 * t + 1; i++ )
        this->generative_polynominal[ i ] = 0;

    //初期値x-α^0を代入しておく
    this->generative_polynominal[ 0 ] = this->alpha[ 0 ];       //α^0に等しい
    this->generative_polynominal[ 1 ] = 1;                //xの係数は1

    //(x-α^i)を順次掛けていく
    //xを掛けたものと-α^iを掛けたものを足し合わせることで求める
    for( i = 1; i < 2 * t; i++ ){
        //xを掛けることは配列を一つずらすことに他ならない
        for( l = 0; l < 2 * this->t + 1; l++ )
            gp_temp[ l + 1 ] = this->generative_polynominal[ l ];

        gp_temp[ 0 ] = 0;

        //-α^iを掛けることは各要素にα^iを掛けるだけである
        //ただし0はいくら掛けても0である
        for( l = 0; l < 2 * this->t + 1; l++ ){
            if( this->generative_polynominal[ l ] )
                //gp[l]×α^i
                this->generative_polynominal[ l ] = alpha[ ( rev_alpha[ this->generative_polynominal[ l ] ] + i ) % 255 ];
            else
                this->generative_polynominal[ l ] = 0;

            //足し合わせる(ベクトル同士のxor)ことで(x-α^i)を掛けたことになる
            this->generative_polynominal[ l ] ^= gp_temp[ l ];
        }
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "生成多項式=\n" );
    for( i = 0; i < 2 * t + 1; i++ ){
        if( this->generative_polynominal[ i ] ){
            if( i )
                printf( "+" );
            printf( " α^%dx^%d ", rev_alpha[ this->generative_polynominal[ i ] ], i );
        }
    }
    printf( "\n\n" );
#endif
}

//検査行列を生成し掃き出し法による係数を求める
//generate_ecc()で使用される
void ecc_rs_generate_by_coefficient::init_coefficient( void )
{
    int i, l;
    unsigned char **data = new unsigned char * [ 2 * this->t ];

    for( i = 0; i < 2 * this->t; i++ )
        data[ i ] = new unsigned char [ this->k + 1 ];

    for( i = 0; i < 2 * this->t; i++ ){
        data[ i ][ this->k ] = 0;
        for( l = 0; l < this->k; l++ )
            data[ i ][ l ] = alpha[ ( this->k - l - 1 ) * i ];
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "検査行列=\n" );
    print_matrix( data, 2 * this->t, this->k + 1, rev_alpha );
#endif

    this->galois_row_reduction( data, 2 * this->t, this->k - 2 * this->t );

#ifdef PRINT_DEBUG_MESSAGES
    printf( "検査行列(変形)=\n" );
    print_matrix( data, 2 * t, k + 1, rev_alpha );
#endif

    for( i = 0; i < 2 * this->t; i++ ){
        for( l = 0; l < this->k - 2 * this->t; l++ )
            this->coefficient[ i ][ l ] = data[ i ][ l ];
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "計算用係数表=\n" );
    print_matrix( this->coefficient, 2 * this->t, this->k - 2 * this->t, rev_alpha );
#endif

    for( i = 0; i < 2 * this->t; i++ )
        delete[] data[ i ];
    delete[] data;
}

//data[行][列]で示されるrows行の拡大行列を、ガロア拡大体上で掃き出し法による演算を行う
//この際、offset列のデータは無視する
void ecc_rs_base::galois_row_reduction( unsigned char **data, int row, int offset )
{
    int i, l, m;
    unsigned char temp, temp2;

    for( i = 0; i < row; i++ ){
        temp = data[ i ][ i + offset ];
        if( temp ){
            temp = rev_alpha[ temp ];
            //行のデータを割る(1にする)
            for( l = 0; l < row + offset + 1; l++ ){
                if( data[ i ][ l ] )
                    data[ i ][ l ] = alpha[ ( rev_alpha[ data[ i ][ l ] ] - temp + 255 ) % 255 ];
                else
                    data[ i ][ l ] = 0;
            }   
        }

        //基準列の1にしたデータ以外を0にする
        for( l = 0; l < row; l++ ){
            if( l != i ){
                temp = data[ l ][ i + offset ];
                if( temp ){
                    temp = rev_alpha[ temp ];
                    for( m = 0; m < row + offset + 1; m++ ){
                        temp2 = data[ i ][ m ];
                        if( temp2 ){
                            temp2 = rev_alpha[ temp2 ];
                            data[ l ][ m ] ^= alpha[ ( temp + temp2 ) % 255 ];
                        }
                    }
                }
            }
        }
    }
}

//入力データを生成多項式で割ることで、余りとしてエラー訂正コードを得る
//dataをgenerative_polynominalで割ることでリードソロモンコードを得る
//この方法では生成が遅いので、検査行列Hを変形した係数とデータから計算するほうが早くてよいと思われる
void ecc_rs_generate_by_mod::generate( unsigned char *input )
{
    unsigned char *data = new unsigned char[ this->k ];
    unsigned char buf;
    int i, l;

    //データをコピーする(入力データが壊れるため)
    for( i = 0; i < this->k - 2 * this->t; i++ )
        data[ i ] = input[ i ];

    //ECCコードに該当する部分はあらかじめ0に設定しておく
    for( i = this->k - 2 * this->t; i < this->k; i++ )
        data[ i ] = 0;

    for( i = 0; i < this->k - 2 * this->t; i++ ){
        if( data[ i ] ){
            buf = rev_alpha[ data[ i ] ];
            for( l = 0; l <= 2 * this->t; l++ ){
                if( this->generative_polynominal[ 2 * this->t - l ] ){
                    data[ i + l ] ^= alpha[ ( rev_alpha[ this->generative_polynominal[ 2 * this->t - l ] ] + buf ) % 255 ];
                }
            }
        }
    }

    for( i = this->k - 2 * this->t; i < this->k; i++ )
        input[ i ] = data[ i ];

#ifdef PRINT_DEBUG_MESSAGES
    printf( "データ&ECC=\n" );
    for( i = 0; i < this->k - 2 * this->t; i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    for( i = this->k - 2 * this->t; i < this->k; i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    printf( "\n\n" );
#endif

    delete[] data;
}

//検査行列から入力データのECCを得る
void ecc_rs_generate_by_coefficient::generate( unsigned char *input )
{
    int i, l;

    //入力データからECCデータを割り出す
    for( i = 0; i < 2 * this->t; i++ ){
        input[ i + ( this->k - 2 * this->t ) ] = 0;
        for( l = 0; l < this->k - 2 * this->t; l++ ){
            if( input[ l ] && this->coefficient[ i ][ l ] )
                input[ i + this->k - 2 * this->t ] ^= alpha[ ( rev_alpha[ input[ l ] ] + rev_alpha[ this->coefficient[ i ][ l ] ] ) % 255 ];
        }
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "データ&ECC(係数)=\n" );
    for( i = 0; i < k - ( 2 * t ); i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    for( i = k - ( 2 * t ); i < k; i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    printf( "\n\n" );
#endif
}

//ECCデータを検査する
//シンドロームが0であれば0を、非0であれば非0を返す。
//0の場合はエラーがないと思われる。(エラーがあるのに偶然の一致が発生する可能性もある)
int ecc_rs_base::test( unsigned char *input )
{
    int i, l;
    unsigned char x;

    x = 0;

    //シンドロームを計算する。
    for( i = 0; i < 2 * this->t; i++ ){
        x = 0;
        for( l = 0; l < this->k; l++ )
            if( input[ l ] )
                x ^= this->alpha[ ( this->rev_alpha[ input[ l ] ] + ( this->k - l - 1 ) * i ) % 255 ];
        if( x != 0 )
            return( 1 );
    }
    return( 0 );
}

//ECCデータを検査し、エラーを修正する
//返り値はエラーの個数
//-1でエラー訂正不能
int ecc_rs_repair::repair( unsigned char *input )
{
    unsigned char buf;
    int i, l, x, temp;

    //シンドロームを計算する。
    for( i = 0; i < 2 * this->t; i++ ){
        this->syndrome[ i ] = 0;
        for( l = 0; l < this->k; l++ )
            if( input[ l ] )
                this->syndrome[ i ] ^= this->alpha[ ( this->rev_alpha[ input[ l ] ] + ( this->k - l - 1 ) * i ) % 255 ];
    }

    //シンドロームからシンドローム拡大行列を作成する。
    for( i = 0; i < this->t; i++ )
        for( l = 0; l < this->t + 1; l++ )
            this->syn[ i ][ l ] = this->syndrome[ l + i ];

#ifdef PRINT_DEBUG_MESSAGES
    printf( "シンドローム拡大行列=\n" );
    print_matrix( this->syn, this->t, this->t + 1, this->rev_alpha );
#endif

    //シンドローム拡大行列を階段行列に変形する。
    this->galois_row_reduction( (unsigned char **)this->syn, this->t, 0 );

#ifdef PRINT_DEBUG_MESSAGES
    printf( "シンドローム拡大行列(変形)=\n" );
    print_matrix( this->syn, this->t, this->t + 1, this->rev_alpha );
#endif

    //行列の階数≒エラーの数
    //ただし、temp == t の場合は、エラー数がもっと多い可能性もあるのでまだ確定しない。
    temp = 0;
    for( i = 0; i < this->t; i++ ){
        for( l = 0; l < this->t + 1; l++ ){
            if( this->syn[ i ][ l ] ){
                temp++;
                break;
            }
        }
    }

    //δの式を取り出す
    for( i = 0; i < temp; i++ )
        this->delta[ i ] = this->syn[ i ][ temp ];
    delta[ temp ] = 1;
    for( i = temp + 1; i < this->t + 1; i++ )
        this->delta[ i ] = 0;

#ifdef PRINT_DEBUG_MESSAGES
    printf( "δ(x)=\n" );
    for( i = 0; i < this->t + 1; i++ )
        printf( " α^%d", rev_alpha[ delta[ i ] ] );
    printf( "\n\n" );
#endif

    //δの式に代入することでエラー発生場所を特定する
#ifdef PRINT_DEBUG_MESSAGES
    printf( "\nエラー箇所 " );
#endif
    x = 0;
    for( i = 0; i < this->k; i++ )
        this->error_pos[ i ] = 0;
    for( i = 0; i < this->k; i++ ){
        buf = this->delta[ 0 ];
        for( l = 1; l < temp + 1; l++ ){
            if( this->delta[ l ] )
                buf ^= alpha[ ( rev_alpha[ this->delta[ l ] ] + i * l ) % 255 ];
        }
        if( buf == 0 ){
            this->error_pos[ x++ ] = alpha[ i ];
#ifdef PRINT_DEBUG_MESSAGES
            printf( "data[%d] ", k - i - 1 );
#endif
        }
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "\nエラー数 = %d\n", x );
    if( x <= this->t && x == temp )
        printf( "エラー訂正可能\n" );
    else
        printf( "エラー訂正不可\n" );
#endif

    //修正不能が確定すれば-1を返す
    if( x > this->t || x != temp )
        return( -1 );

    //エラー内容を修正する
    for( i = 0; i < x; i++ )
        error[ 0 ][ i ] = 1;
    for( i = 0; i < x; i++ )
        error[ i ][ x ] = syndrome[ i ];
    if( x > 1 ){
        for( i = 0; i < x; i++ )
            error[ 1 ][ i ] = error_pos[ x - 1 - i ];
    }
    for( i = 2; i < x; i++ ){
        for( l = 0; l < x; l++ )
            error[ i ][ l ] = alpha[ ( rev_alpha[ error[ 1 ][ l ] ] * i ) % 255 ];
    }

#ifdef PRINT_DEBUG_MESSAGES
    printf( "code=\n" );
    for( i = 0; i < this->k - ( 2 * this->t ); i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    for( i = this->k - ( 2 * this->t ); i < this->k; i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    printf( "\n\n" );
#endif

#ifdef PRINT_DEBUG_MESSAGES
    printf( "エラー内容拡大行列=\n" );
    print_matrix( error, x, x + 1, rev_alpha );
#endif

    this->galois_row_reduction( (unsigned char **)error, x, 0 );

#ifdef PRINT_DEBUG_MESSAGES
    printf( "エラー内容拡大行列(変形)=\n" );
    print_matrix( error, x, x + 1, rev_alpha );
#endif

    //エラーを訂正する
    for( i = 0; i < x; i++ )
        input[ ( this->k - 1 ) - rev_alpha[ error_pos[ x - i - 1 ] ] ] ^= error[ i ][ x ];

#ifdef PRINT_DEBUG_MESSAGES
    printf( "code=\n" );
    for( i = 0; i < this->k - ( 2 * this->t ); i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    for( i = this->k - ( 2 * this->t ); i < k; i++ ){
        printf( " α^%d", rev_alpha[ input[ i ] ] );
    }
    printf( "\n\n" );
#endif

    return( x );
}

#ifdef PRINT_DEBUG_MESSAGES
int main()
{
    ecc_rs_generate_by_mod eccm( 10, 3 );              //コード長10バイト、エラー訂正可能バイト数は3バイト
    ecc_rs_generate_by_coefficient eccc( 10, 3 );
    ecc_rs_repair eccr( 10, 3 );
    ecc_rs ecc( 10, 3 );

    LARGE_INTEGER start, end, freq;
    unsigned char data[ 10 ], x;

    data[ 0 ] = 3;
    data[ 1 ] = 14;
    data[ 2 ] = 15;
    data[ 3 ] = 92;
    data[ 4 ] = 0;// alpha[ 65 ];
    data[ 5 ] = 0;// alpha[ 35 ];
    data[6] = 0;
    data[7] = 0;
    data[8] = 0;
    data[9] = 0;

    QueryPerformanceFrequency( &freq );
    QueryPerformanceCounter( &start );
    eccm.generate( data );
    QueryPerformanceCounter( &end );
    end.QuadPart -= start.QuadPart;
    printf( "generate_ecc_by_mod: %lldns\n", end.QuadPart * 1000000000 / freq.QuadPart );

    data[ 0 ] = 3;
    data[ 1 ] = 14;
    data[ 2 ] = 15;
    data[ 3 ] = 92;
    data[ 4 ] = 0;// alpha[ 65 ];
    data[ 5 ] = 0;// alpha[ 35 ];
    data[6] = 0;
    data[7] = 0;
    data[8] = 0;
    data[9] = 0;

    QueryPerformanceCounter( &start );
    eccc.generate( data );
    QueryPerformanceCounter( &end );
    end.QuadPart -= start.QuadPart;
    printf( "generate_ecc: %lldns\n", end.QuadPart * 1000000000 / freq.QuadPart );

    //故意にエラーを混入させてみる
    data[ 0 ] = 4;
    data[ 1 ] = 1;
    data[ 2 ] = 1;

    QueryPerformanceCounter( &start );
    x = eccr.repair( data );
    QueryPerformanceCounter( &end );
    end.QuadPart -= start.QuadPart;
    printf( "エラー数=%d\n", x );
    printf( "repair_data: %lldns\n", end.QuadPart * 1000000000 / freq.QuadPart );

    QueryPerformanceCounter( &start );
    x = ecc.test( data );
    QueryPerformanceCounter( &end );
    end.QuadPart -= start.QuadPart;
    printf( "テスト=%d\n", x );
    printf( "test_data: %lldns\n", end.QuadPart * 1000000000 / freq.QuadPart );
}
#endif
//version 1.0
#ifndef _HEADER_ECC_RS
#define _HEADER_ECC_RS

//リードソロモン符号によるECCコードライブラリ
//ECCコード(リードソロモン符号)を得るには2つの手法がある
//入力データを生成多項式で割った余りでECCコードを求める方法
//      この方法は、入力データが破壊されるため、データの写しを控えておく必要がある。
//      そのため、コピーにかかる時間の分だけ遅くなる。
//      しかし、必要なメモリは生成多項式の保持に必要なだけである。
//検査行列を変形して各ECCコードを求めるために必要な係数を求め、その係数を入力データに乗じてECCコードを求める方法
//      この方法では入力データが破壊されないためあらかじめコピーする必要はなく高速であるが、係数保持のためのメモリが必要となる

//ecc_rs_generate_by_modクラス:生成多項式の商の余りでECCを求める。
// ecc_rs_generate_by_mod::generate( unsigned char *data )
//              : dataで指定したデータの末尾にECCデータを付加する。
// 
//ecc_rs_generate_by_coefficientクラス:検査行列を変形した係数によりECCを求める。
// ecc_rs_generate_by_coefficient::generate( unsigned char *data )
//              : dataで指定したデータの末尾にECCデータを付加する。
// 
//ecc_rs_repairクラス:データ+ECCのデータからデータを修正する。
// ecc_rs_repair::repair( unsigned char *data )
//               : dataで指定したデータとECCで復元する。返り値はエラーの個数、-1が帰った場合は訂正不能。
// 
//ecc_rsクラス:ecc_rs_generate_by_coefficientクラスとecc_rs_repairクラスの多重継承クラス。データ生成と修正をするPCなどの場合はこれが良い。
// 
//いずれのクラスも、コンストラクタには(k=全データ長(<255),t=訂正可能バイト数(<255)[,原始多項式])を設定する。
//このパラメータが同じならば各々のクラスで生成したデータには互換性がある。

class ecc_rs_base
{
protected:
    //kはコード長(データ+ECCバイト数)、tはエラー訂正可能バイト数(ECCバイト=t*2)
    ecc_rs_base( unsigned char _k, unsigned char _t ) : ecc_rs_base( _k, _t, 0x11d ){}
    ecc_rs_base( unsigned char _k, unsigned char _t, unsigned int _pp ) : k( _k ), t( _t ), primitive_polynominal( _pp )
    {
        init_galois_alpha_table();
    }
    ~ecc_rs_base(){}

    unsigned char alpha[ 255 ];                     //α→ベクトル表現変換テーブル    
    unsigned char rev_alpha[ 256 ];                 //ベクトル表現→α変換テーブル(rev_alpha[0]は不定)
    unsigned char t;                                //エラー訂正可能バイト数
    unsigned char k;                                //コード(データ+ECC)の全長バイト数
                                                    //2^8ガロア拡大体上で定義するため、2^8-1バイトまでしか扱えない
    void galois_row_reduction( unsigned char **, int, int );
public:
    int test( unsigned char * );                    //エラーが無いかテストする。エラーがないと思われる場合の返り値は0、エラーがある場合は非0
private:
    unsigned int primitive_polynominal;             //原始多項式(通常は0x11d)

    void init_galois_alpha_table( void );
};

class ecc_rs_repair : public virtual ecc_rs_base
{
public:
    ecc_rs_repair( unsigned char _k, unsigned char _t ) : ecc_rs_repair( _k, _t, 0x11d ){}
    ecc_rs_repair( unsigned char _k, unsigned char _t, unsigned int _pp ) : ecc_rs_base( _k, _t, _pp )
    {
        int i;

        syndrome = new unsigned char [ 2 * t ];
        syn = new unsigned char * [ t ];
        for( i = 0; i < t; i++ )
            syn[ i ] = new unsigned char [ t + 1 ];
        delta = new unsigned char [ t + 1 ];
        error_pos = new unsigned char [ k ];
        error = new unsigned char * [ t ];
        for( i = 0; i < t; i ++ )
            error[ i ] = new unsigned char [ t + 1 ];
    }
    ~ecc_rs_repair()
    {
        int i;

        for( i = 0; i < t; i++ )
            delete[] error[ i ];
        delete[] error;
        delete[] error_pos;
        delete[] delta;
        for( i = 0; i < t; i++ )
            delete[] syn[ i ];
        delete[] syn;
        delete[] syndrome;
    }

    int repair( unsigned char * );                  //エラーを訂正する。返り値はエラー数。訂正不能の場合は-1
private:
    //エラー訂正時に利用する一時変数
    //修正のたびに確保→解放すると無駄が多いためコンストラクタとデストラクタで管理する
    unsigned char *syndrome;
    unsigned char **syn;
    unsigned char *delta;
    unsigned char *error_pos;
    unsigned char **error;
};

class ecc_rs_generate_by_coefficient : public virtual ecc_rs_base
{
public:
    ecc_rs_generate_by_coefficient( unsigned char _k, unsigned char _t ) : ecc_rs_generate_by_coefficient( _k, _t, 0x11d ){}
    ecc_rs_generate_by_coefficient( unsigned char _k, unsigned char _t, unsigned int _pp ) : ecc_rs_base( _k, _t, _pp )
    {
        int i;

        coefficient = new unsigned char * [ 2 * t ];
        for( i = 0; i < 2 * t; i++ )
            coefficient[ i ] = new unsigned char [ k - 2 * t ];

        init_coefficient();
    }
    ~ecc_rs_generate_by_coefficient()
    {
        int i;

        for( i = 0; i < 2 * t; i++ )
            delete[] coefficient[ i ];
        delete[] coefficient;
    }

    void generate( unsigned char * );               //検査行列から逆算した係数でECCを求める
private:
    unsigned char **coefficient;                    //generate_ecc()で使用する検査行列を変形した係数

    void init_coefficient( void );
};

class ecc_rs_generate_by_mod : public virtual ecc_rs_base
{
public:
    ecc_rs_generate_by_mod( unsigned char _k, unsigned char _t ) : ecc_rs_generate_by_mod( _k, _t, 0x11d ){}
    ecc_rs_generate_by_mod( unsigned char _k, unsigned char _t, unsigned int _pp ) : ecc_rs_base( _k, _t, _pp )
    {
        generative_polynominal = new unsigned char [ 2 * t + 1 ];

        init_generative_polynominal();
    }
    ~ecc_rs_generate_by_mod()
    {
        delete[] generative_polynominal;
    }

    void generate( unsigned char * );               //生成多項式で除算した余りでECCを求める
private:
    unsigned char *generative_polynominal;          //生成多項式

    void init_generative_polynominal( void );
};

//コード生成とエラー訂正をまとめて行うことができるクラスも作成しておく
class ecc_rs : public ecc_rs_generate_by_coefficient, public ecc_rs_repair
{
public:
    ecc_rs( unsigned char _k, unsigned char _t ) : ecc_rs( _k, _t, 0x11d ){}
    ecc_rs( unsigned char _k, unsigned char _t, unsigned int _pp ) : ecc_rs_base( _k, _t, _pp ), ecc_rs_repair( _k, _t, _pp ), ecc_rs_generate_by_coefficient( _k, _t, _pp ) {}
    ~ecc_rs(){}
};

#endif

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です