C++实现伽罗华域生成及四则运算(一)

数学领域有一个伽罗华(瓦)域,其广泛运用于加密算法中,本文则探索并记录C++实现形式如 G F ( 2 n ) GF(2^n) GF(2n)伽罗瓦域生成器及四则运算的步骤及方法。

一、什么是伽罗瓦域

不是本文重点,已经知道的略过,简单来说就是该域是一个有限数字集合,其上面加、异或是一个意思,乘、除跟我们正常理解的乘除略有差异, G F ( 2 n ) GF(2^n) GF(2n)伽罗瓦域就有 2 n 2^n 2n个值,详情请参阅以下:

二、模型定义

定义了一个模版类GFM,仅实现 G F ( 2 n ) GF(2^n) GF(2n)形式的,且n处于常用的2~15之间,上代码:

/*伽罗瓦域类GF(2^n)形式*/
template<uint8_t n>
class GFM {
    private:
        uint16_t* gf; //用于存放伽罗瓦域的值数组指针,x-1对应生成元的次幂,当x>0时,gf[x]=2^(x-1)
        uint16_t* base; //用于存放伽罗瓦域值对应的下标指针,当x>0时,gf[base[x]]=x=2^(base[x]-1)
        uint16_t N = power(2, n); //数组长度
        bool overlap; //内置的本原多项式是否正确,默认正确为false
        void init(uint16_t formuler); //初始化
        int8_t operatorOrder(char c); //返回二元操作符优先级
        uint16_t calculate(uint16_t a, uint16_t b, char opt); //进行二元运算
    public:
        //构造函数
        GFM(uint16_t formuler=0) { //用户指定本原多项式构造,默认使用内置本原多项式
            cout << "构造GF" << dec << N << endl;
            if (n < 2 || n > 15) throw TypeException("幂次只有是在[2,15]之间");
            gf = (uint16_t*)malloc(sizeof(uint16_t) * N);
            base = (uint16_t*)malloc(sizeof(uint16_t) * N);
            init(formuler); //使用内置本原多项式
        }
        ~GFM() {
            free(gf);
            free(base);
            gf = nullptr;
            base =nullptr;
            cout << "析构GF" << dec << N << endl;
        }
        void toString(); //将构造出的伽罗瓦域输出
        uint16_t* getGF(); //获取伽罗瓦域值数组
        uint16_t* getBase(); //获取值下标数组
        uint16_t getLength(); //返回数组长度
        uint16_t multi(uint16_t a1, uint16_t a2); //乘法
        uint16_t adver(uint16_t a); //求乘法逆元
        uint16_t calc(const char* expr); //求表达式的值
        void matrixAdd(uint16_t* res, uint16_t* A1, uint16_t r1, uint16_t c1, uint16_t* A2, uint16_t r2, uint16_t c2); //矩阵加法
        void matrixMulti(uint16_t* res, uint16_t* A1, uint16_t r1, uint16_t c1, uint16_t* A2, uint16_t r2, uint16_t c2); //矩阵乘法
};

在头文件里声明了模版类,也运用了动态内存分配技术,这样可以根据用户需求生成不同的伽罗瓦域。请看生成器的测试代码片断:

GFM<4> gf4;
gf4.toString();
GFM<8> gf8;
gf8.toString();

控制台输出结果片断如下:

构造GF16
GF[0]=0, GF[1]=1, GF[2]=2, GF[3]=4, GF[4]=8, GF[5]=3, GF[6]=6, GF[7]=c, GF[8]=b, GF[9]=5, 
GF[a]=a, GF[b]=7, GF[c]=e, GF[d]=f, GF[e]=d, GF[f]=9, 
BS[0]=0, BS[1]=1, BS[2]=2, BS[3]=5, BS[4]=3, BS[5]=9, BS[6]=6, BS[7]=b, BS[8]=4, BS[9]=f, 
BS[a]=a, BS[b]=8, BS[c]=7, BS[d]=e, BS[e]=c, BS[f]=d, 
构造GF256
GF[00]=00, GF[01]=01, GF[02]=02, GF[03]=04, GF[04]=08, GF[05]=10, GF[06]=20, GF[07]=40, GF[08]=80, GF[09]=1d, 
GF[0a]=3a, GF[0b]=74, GF[0c]=e8, GF[0d]=cd, GF[0e]=87, GF[0f]=13, GF[10]=26, GF[11]=4c, GF[12]=98, GF[13]=2d, 
GF[14]=5a, GF[15]=b4, GF[16]=75, GF[17]=ea, GF[18]=c9, GF[19]=8f, GF[1a]=03, GF[1b]=06, GF[1c]=0c, GF[1d]=18, 
GF[1e]=30, GF[1f]=60, GF[20]=c0, GF[21]=9d, GF[22]=27, GF[23]=4e, GF[24]=9c, GF[25]=25, GF[26]=4a, GF[27]=94, 
GF[28]=35, GF[29]=6a, GF[2a]=d4, GF[2b]=b5, GF[2c]=77, GF[2d]=ee, GF[2e]=c1, GF[2f]=9f, GF[30]=23, GF[31]=46, 
GF[32]=8c, GF[33]=05, GF[34]=0a, GF[35]=14, GF[36]=28, GF[37]=50, GF[38]=a0, GF[39]=5d, GF[3a]=ba, GF[3b]=69, 
GF[3c]=d2, GF[3d]=b9, GF[3e]=6f, GF[3f]=de, GF[40]=a1, GF[41]=5f, GF[42]=be, GF[43]=61, GF[44]=c2, GF[45]=99, 
GF[46]=2f, GF[47]=5e, GF[48]=bc, GF[49]=65, GF[4a]=ca, GF[4b]=89, GF[4c]=0f, GF[4d]=1e, GF[4e]=3c, GF[4f]=78, 
GF[50]=f0, GF[51]=fd, GF[52]=e7, GF[53]=d3, GF[54]=bb, GF[55]=6b, GF[56]=d6, GF[57]=b1, GF[58]=7f, GF[59]=fe, 
GF[5a]=e1, GF[5b]=df, GF[5c]=a3, GF[5d]=5b, GF[5e]=b6, GF[5f]=71, GF[60]=e2, GF[61]=d9, GF[62]=af, GF[63]=43, 
GF[64]=86, GF[65]=11, GF[66]=22, GF[67]=44, GF[68]=88, GF[69]=0d, GF[6a]=1a, GF[6b]=34, GF[6c]=68, GF[6d]=d0, 
GF[6e]=bd, GF[6f]=67, GF[70]=ce, GF[71]=81, GF[72]=1f, GF[73]=3e, GF[74]=7c, GF[75]=f8, GF[76]=ed, GF[77]=c7, 
GF[78]=93, GF[79]=3b, GF[7a]=76, GF[7b]=ec, GF[7c]=c5, GF[7d]=97, GF[7e]=33, GF[7f]=66, GF[80]=cc, GF[81]=85, 
GF[82]=17, GF[83]=2e, GF[84]=5c, GF[85]=b8, GF[86]=6d, GF[87]=da, GF[88]=a9, GF[89]=4f, GF[8a]=9e, GF[8b]=21, 
GF[8c]=42, GF[8d]=84, GF[8e]=15, GF[8f]=2a, GF[90]=54, GF[91]=a8, GF[92]=4d, GF[93]=9a, GF[94]=29, GF[95]=52, 
GF[96]=a4, GF[97]=55, GF[98]=aa, GF[99]=49, GF[9a]=92, GF[9b]=39, GF[9c]=72, GF[9d]=e4, GF[9e]=d5, GF[9f]=b7, 
GF[a0]=73, GF[a1]=e6, GF[a2]=d1, GF[a3]=bf, GF[a4]=63, GF[a5]=c6, GF[a6]=91, GF[a7]=3f, GF[a8]=7e, GF[a9]=fc, 
GF[aa]=e5, GF[ab]=d7, GF[ac]=b3, GF[ad]=7b, GF[ae]=f6, GF[af]=f1, GF[b0]=ff, GF[b1]=e3, GF[b2]=db, GF[b3]=ab, 
GF[b4]=4b, GF[b5]=96, GF[b6]=31, GF[b7]=62, GF[b8]=c4, GF[b9]=95, GF[ba]=37, GF[bb]=6e, GF[bc]=dc, GF[bd]=a5, 
GF[be]=57, GF[bf]=ae, GF[c0]=41, GF[c1]=82, GF[c2]=19, GF[c3]=32, GF[c4]=64, GF[c5]=c8, GF[c6]=8d, GF[c7]=07, 
GF[c8]=0e, GF[c9]=1c, GF[ca]=38, GF[cb]=70, GF[cc]=e0, GF[cd]=dd, GF[ce]=a7, GF[cf]=53, GF[d0]=a6, GF[d1]=51, 
GF[d2]=a2, GF[d3]=59, GF[d4]=b2, GF[d5]=79, GF[d6]=f2, GF[d7]=f9, GF[d8]=ef, GF[d9]=c3, GF[da]=9b, GF[db]=2b, 
GF[dc]=56, GF[dd]=ac, GF[de]=45, GF[df]=8a, GF[e0]=09, GF[e1]=12, GF[e2]=24, GF[e3]=48, GF[e4]=90, GF[e5]=3d, 
GF[e6]=7a, GF[e7]=f4, GF[e8]=f5, GF[e9]=f7, GF[ea]=f3, GF[eb]=fb, GF[ec]=eb, GF[ed]=cb, GF[ee]=8b, GF[ef]=0b, 
GF[f0]=16, GF[f1]=2c, GF[f2]=58, GF[f3]=b0, GF[f4]=7d, GF[f5]=fa, GF[f6]=e9, GF[f7]=cf, GF[f8]=83, GF[f9]=1b, 
GF[fa]=36, GF[fb]=6c, GF[fc]=d8, GF[fd]=ad, GF[fe]=47, GF[ff]=8e, 
BS[00]=00, BS[01]=01, BS[02]=02, BS[03]=1a, BS[04]=03, BS[05]=33, BS[06]=1b, BS[07]=c7, BS[08]=04, BS[09]=e0, 
BS[0a]=34, BS[0b]=ef, BS[0c]=1c, BS[0d]=69, BS[0e]=c8, BS[0f]=4c, BS[10]=05, BS[11]=65, BS[12]=e1, BS[13]=0f, 
BS[14]=35, BS[15]=8e, BS[16]=f0, BS[17]=82, BS[18]=1d, BS[19]=c2, BS[1a]=6a, BS[1b]=f9, BS[1c]=c9, BS[1d]=09, 
BS[1e]=4d, BS[1f]=72, BS[20]=06, BS[21]=8b, BS[22]=66, BS[23]=30, BS[24]=e2, BS[25]=25, BS[26]=10, BS[27]=22, 
BS[28]=36, BS[29]=94, BS[2a]=8f, BS[2b]=db, BS[2c]=f1, BS[2d]=13, BS[2e]=83, BS[2f]=46, BS[30]=1e, BS[31]=b6, 
BS[32]=c3, BS[33]=7e, BS[34]=6b, BS[35]=28, BS[36]=fa, BS[37]=ba, BS[38]=ca, BS[39]=9b, BS[3a]=0a, BS[3b]=79, 
BS[3c]=4e, BS[3d]=e5, BS[3e]=73, BS[3f]=a7, BS[40]=07, BS[41]=c0, BS[42]=8c, BS[43]=63, BS[44]=67, BS[45]=de, 
BS[46]=31, BS[47]=fe, BS[48]=e3, BS[49]=99, BS[4a]=26, BS[4b]=b4, BS[4c]=11, BS[4d]=92, BS[4e]=23, BS[4f]=89, 
BS[50]=37, BS[51]=d1, BS[52]=95, BS[53]=cf, BS[54]=90, BS[55]=97, BS[56]=dc, BS[57]=be, BS[58]=f2, BS[59]=d3, 
BS[5a]=14, BS[5b]=5d, BS[5c]=84, BS[5d]=39, BS[5e]=47, BS[5f]=41, BS[60]=1f, BS[61]=43, BS[62]=b7, BS[63]=a4, 
BS[64]=c4, BS[65]=49, BS[66]=7f, BS[67]=6f, BS[68]=6c, BS[69]=3b, BS[6a]=29, BS[6b]=55, BS[6c]=fb, BS[6d]=86, 
BS[6e]=bb, BS[6f]=3e, BS[70]=cb, BS[71]=5f, BS[72]=9c, BS[73]=a0, BS[74]=0b, BS[75]=16, BS[76]=7a, BS[77]=2c, 
BS[78]=4f, BS[79]=d5, BS[7a]=e6, BS[7b]=ad, BS[7c]=74, BS[7d]=f4, BS[7e]=a8, BS[7f]=58, BS[80]=08, BS[81]=71, 
BS[82]=c1, BS[83]=f8, BS[84]=8d, BS[85]=81, BS[86]=64, BS[87]=0e, BS[88]=68, BS[89]=4b, BS[8a]=df, BS[8b]=ee, 
BS[8c]=32, BS[8d]=c6, BS[8e]=ff, BS[8f]=19, BS[90]=e4, BS[91]=a6, BS[92]=9a, BS[93]=78, BS[94]=27, BS[95]=b9, 
BS[96]=b5, BS[97]=7d, BS[98]=12, BS[99]=45, BS[9a]=93, BS[9b]=da, BS[9c]=24, BS[9d]=21, BS[9e]=8a, BS[9f]=2f, 
BS[a0]=38, BS[a1]=40, BS[a2]=d2, BS[a3]=5c, BS[a4]=96, BS[a5]=bd, BS[a6]=d0, BS[a7]=ce, BS[a8]=91, BS[a9]=88, 
BS[aa]=98, BS[ab]=b3, BS[ac]=dd, BS[ad]=fd, BS[ae]=bf, BS[af]=62, BS[b0]=f3, BS[b1]=57, BS[b2]=d4, BS[b3]=ac, 
BS[b4]=15, BS[b5]=2b, BS[b6]=5e, BS[b7]=9f, BS[b8]=85, BS[b9]=3d, BS[ba]=3a, BS[bb]=54, BS[bc]=48, BS[bd]=6e, 
BS[be]=42, BS[bf]=a3, BS[c0]=20, BS[c1]=2e, BS[c2]=44, BS[c3]=d9, BS[c4]=b8, BS[c5]=7c, BS[c6]=a5, BS[c7]=77, 
BS[c8]=c5, BS[c9]=18, BS[ca]=4a, BS[cb]=ed, BS[cc]=80, BS[cd]=0d, BS[ce]=70, BS[cf]=f7, BS[d0]=6d, BS[d1]=a2, 
BS[d2]=3c, BS[d3]=53, BS[d4]=2a, BS[d5]=9e, BS[d6]=56, BS[d7]=ab, BS[d8]=fc, BS[d9]=61, BS[da]=87, BS[db]=b2, 
BS[dc]=bc, BS[dd]=cd, BS[de]=3f, BS[df]=5b, BS[e0]=cc, BS[e1]=5a, BS[e2]=60, BS[e3]=b1, BS[e4]=9d, BS[e5]=aa, 
BS[e6]=a1, BS[e7]=52, BS[e8]=0c, BS[e9]=f6, BS[ea]=17, BS[eb]=ec, BS[ec]=7b, BS[ed]=76, BS[ee]=2d, BS[ef]=d8, 
BS[f0]=50, BS[f1]=af, BS[f2]=d6, BS[f3]=ea, BS[f4]=e7, BS[f5]=e8, BS[f6]=ae, BS[f7]=e9, BS[f8]=75, BS[f9]=d7, 
BS[fa]=f5, BS[fb]=eb, BS[fc]=a9, BS[fd]=51, BS[fe]=59, BS[ff]=b0, 
析构GF256
析构GF16

内置了2个数组gf和base,如注释一样,gf[0] = 0是定义,gf[1] = 1 2 0 2^0 20,这两个数组的内存申请在构造函数里,销毁内存则在析构函数里完成。构造函数里的init函数实现了对2个数组的初始化及本原多项式的取值,当参数formuler=0时,使用内置的本原多项式,当其不为0时,它就代表用户指定的本原多项式,比如用户想对GF(2^8)指定 x 8 + x 7 + x 6 + x + 1 x^8+x^7+x^6+x+1 x8+x7+x6+x+1作为其本原多项式,则将其编码为: ( 111000011 ) 2 = 1 C 3 (111000011)_2=1C3 (111000011)2=1C3

template<uint8_t n>
void GFM<n>::init(uint16_t formuler) {
    //初始化数据
    memset(gf, 0, sizeof(uint16_t)*N);
    memset(base, 0, sizeof(uint16_t)*N);
    overlap = false;
    *gf = 0;
    *(gf+1) = 1;
    *base = 0;
    *(base+1) = 1;
    uint16_t overflow;//溢出时异或的值
    if (formuler != 0) {
        overflow = formuler;
    } else {
    //选取内置对应的本原多项式
        switch (n) {
            case 2:
                overflow = 0x07; //x^2+x+1
            break;
            case 3:
                overflow = 0x0b; //x^3+x+1
            break;
            case 4:
                overflow = 0x13; //x^4+x+1
            break;
            case 5:
                overflow = 0x25; //x^5+x^2+1
            break;
            case 6:
                overflow = 0x43; //x^6+x+1
            break;
            case 7:
                overflow = 0x89; //x^7+x3+1
            break;
            case 8:
                overflow = 0x11d; //x^8+x^4+x^3+x^2+1
            break;
            case 9:
                overflow = 0x211; //x^9+x^4+1
            break;
            case 10:
                overflow = 0x409; //x^10+x^3+1
            break;
            case 11:
                overflow = 0x805; //x^11+x^2+1
            break;
            case 12:
                overflow = 0x1053; //x^12+x^6+x^4+x+1
            break;
            case 13:
                overflow = 0x201b; //x^13+x^4+x^3+x+1
            break;
            case 14:
                overflow = 0x4443; //x^14+x^10+x^6+x+1
            break;
            case 15:
                overflow = 0x8003; //x^15+x+1
            break;
        } //end of switch
    } //end of if
    
    //利用生成元进行生成
    for (uint16_t i = 2; i < N; i++) {
        *(gf+i) = *(gf+i-1) << 1; //乘2,gf[i] = gf[i-1]*2
        if (*(gf+i) >= N) {
            *(gf+i) ^= overflow;
        }
        if (*(base+*(gf+i))) overlap = true;
        *(base+*(gf+i)) = i;
    }
}

三、输出

不是重点,只贴代码:

template<uint8_t n>
void GFM<n>::toString() {
    if (this->overlap) {
        cout << "请检查本原多项式值" << endl;
        return;
    }
    for (uint16_t i = 0; i < this->N; i++) {
        cout << "GF[" << hex << setw((int)ceil(n/4.0)) << setfill('0') << i << "]=" << setw((int)ceil(n/4.0)) << setfill('0') << *(this->gf+i) << ", ";
        if ((i + 1) % 10 == 0) { //每10个一换行
            cout << endl;
        }
    }
    cout << endl;
    for (uint16_t i = 0; i < N; i++) {
        cout << "BS[" << hex << setw((int)ceil(n/4.0)) << setfill('0') << i << "]=" << setw((int)ceil(n/4.0)) << setfill('0') << *(this->base+i) << ", ";
        if ((i + 1) % 10 == 0) { //每10个一换行
            cout << endl;
        }
    }
    cout << endl;
}

四、四则运算

(一)基础二元运算

加、减都是直接异或就行,所以在我的类模版里找不到加、减函数,乘除函数实现如下:

/*乘法*/
template<uint8_t n>
uint16_t GFM<n>::multi(uint16_t a1, uint16_t a2) {
    uint16_t e1 = *(this->base + a1) - 1; //2^e1 = a1
    uint16_t e2 = *(this->base + a2) - 1;
    return *(this->gf + (e1 + e2) % (this->N-1) + 1); //对应的生成元相应的幂次之和,除0以外,伽罗瓦域的值是有周期,这个周期就是N-1
}


/*乘法逆元,用于除法*/
template<uint8_t n>
uint16_t GFM<n>::adver(uint16_t a) {
    if (a == 0) throw TypeException("除0错误");
    if (a == 1) return 1;
    uint16_t e1 = *(base + a) - 1; //2^e1 = a
    uint16_t e2 = this->N - 1 - e1; //对于GF256,gf[255] * gf[2] == 1,所以它俩互为乘法逆元
    return *(this->gf + e2 + 1);
}

(二)表达式运算

先使用calculate(uint16_t a, uint16_t b, char opt)函数对加减乘除进行封装,然后就是对表达式的解析了,有点像计算器的实现,这里囊括了小括号、十六进制、十进制、八进制数字、加减乘除运算符的解析:

/*计算表达式,要支持+-*\/()*/
template<uint8_t n>
uint16_t GFM<n>::calc(const char* expr) {
    stack<char> stack_expr; //符号栈
    stack<uint16_t> stack_num; //数值栈
    uint16_t a, b, result; //用于运算的2个值
    char ch; //当前操作符
    stack_expr.push('#'); //先存入计算器表达式的底标志

    for (int i = 0; *(expr + i) !=0; i++) {
        ch = *(expr + i);
        if (ch == '(') {
            stack_expr.push(ch);
        } else if (ch == ')') {
            while (stack_expr.top() != '(' && stack_expr.top() != '#') {
                ch = stack_expr.top();
                stack_expr.pop();
                b = stack_num.top();
                stack_num.pop();
                a = stack_num.top();
                stack_num.pop();
                stack_num.push(this->calculate(a, b, ch)); //将结果压栈用于下次运算
            }
            stack_expr.pop(); //退出'('
        } else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { //字符串开头是数字
            //判断进制
            uint8_t base_flag = 10; //默认10进制
            if (ch == '0') {
                if (*(expr + i + 1) == 'x' || *(expr + i + 1) == 'X') {// 16进制标识
                    base_flag = 16;
                } else if (*(expr + i + 1) >= '0' && *(expr + i + 1) <= '9') { //8进制标识
                    base_flag = 8;
                }
            }
            //连续读取数字,包括16进制数
            string num = "";
            for (int j = i; *(expr + j) != 0 && ((*(expr + j) >= '0' && *(expr + j) <= '9') || (*(expr + j) >= 'a' && \
            *(expr + j) <= 'f') || (*(expr + j) >= 'A' && *(expr + j) <= 'F')) || (*(expr + j) == 'x' || *(expr + j) == 'X'); j++) {
                ch = *(expr + j);
                num.append(1,ch); //将数字字符加入结尾
            }
            stack_num.push(stoi(num, nullptr, base_flag)); //将解析完的数字压栈
            i += num.length()-1; //跳过数字,接着读取
        } else if (ch == '+' || ch == '-' || ch == '^' || ch == '*' || ch == '/') { //加、减、异或、乘、除均为二元操作符,后压栈
            if (this->operatorOrder(stack_expr.top()) >= this->operatorOrder(ch) && stack_expr.top() != '(') { //高优先级运算符
                while (this->operatorOrder(stack_expr.top()) >= this->operatorOrder(ch) && stack_expr.top() != '(' && 
                stack_num.size() > 1) { //若遇到前面压栈的运算符优先级高
                    b = stack_num.top();
                    stack_num.pop();
                    a = stack_num.top();
                    stack_num.pop();
                    stack_num.push(this->calculate(a, b, stack_expr.top())); //将结果压栈用于下次运算
                    stack_expr.pop(); //弹出已算过的运算符
                }
            }
            stack_expr.push(ch); //将当前在读运算符压栈
        }
    }//end of for

    //对栈中剩余数字进行运算
    while (stack_expr.size() > 0 && '#' != stack_expr.top() && stack_num.size() > 1) {
        ch = stack_expr.top();
        stack_expr.pop();
        b = stack_num.top();
        stack_num.pop();
        a = stack_num.top();
        stack_num.pop();
        stack_num.push(this->calculate(a, b, ch)); //将结果压栈用于下次运算
    }
    result = stack_num.top();
    stack_num.pop();
    stack_expr.pop(); //弹出'#'
    if (stack_num.size() > 0 || stack_expr.size() > 0) { //运算符、数字数量不匹配
        throw TypeException("错误表达式");
    }
    return result;
}

以下正常测试及鲁棒性测试:

cout << gf8.calc("2*0xe +3*9+1*0xd+1*0xb") << endl; //空格也是鲁棒性测试的一部分
cout << gf8.calc("1* 0xe+2*9+3*0xd+1*0xb") << endl;
//测试抛出异常
// cout << gf8.calc("(2*0xe+3*9+1*0xd+1*0xb") << endl;
// cout << gf8.calc("1*0xe+-2*9+3*0xd++1*0xb") << endl;

// GFM<16> gf16;
// gf16.toString();

// GFM<1> gf1;
// gf1.toString();

测试结果:

1
0

(三)矩阵运算

实现了矩阵加法和乘法:

/*矩阵加法运算,A1为r行c列,A2为m行n列,运算结果res*/
template<uint8_t n>
void GFM<n>::matrixAdd(uint16_t* res, uint16_t* A1, uint16_t r1, uint16_t c1, uint16_t* A2, uint16_t r2, uint16_t c2) {
    if (r1 != r2 || c1 != c2) throw TypeException("矩阵输行列不一致");
    for (uint16_t i = 0; i < r1 * c1; i++) {
        *(res+i) = *(A1+i)^*(A2+i);
    }
}


/*矩阵乘法运算,A1为r行c列,A2为m行n列,运算结果res为r行n列*/
template<uint8_t n>
void GFM<n>::matrixMulti(uint16_t* res, uint16_t* A1, uint16_t r1, uint16_t c1 , uint16_t* A2, uint16_t r2, uint16_t c2) {
    if (r1 != c2 || c1  != r2) throw TypeException("矩阵输行列不一致");
    for (uint16_t i = 0; i < r1; i++) { //A1逐行
        for (uint16_t k = 0; k < c2; k++) { //A2逐列
            uint16_t temp = 0;
            for (uint16_t j = 0; j < c1 ; j++) { //A1一行中逐列
                temp ^= this->multi(*(A1 + i * c1  + j),*(A2 + j * c2 + k)); //A1一行中逐列、A2一列中逐行
            }
            *(res + i * c2 + k) = temp;
        }        
    }
}

测试代码:

uint16_t res[16];
uint16_t a[16] = {2,3,1,1,1,2,3,1,1,1,2,3,3,1,1,2};
uint16_t b[16] = {0xe,0xb,0xd,9,9,0xe,0xb,0xd,0xd,9,0xe,0xb,0xb,0xd,9,0xe};
gf8.matrixAdd(res, a, 4, 4, b, 4, 4);
for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++){
        cout << hex << res[i*4+j] << " ";
    }
    cout << endl;
}
gf8.matrixMulti(res, a, 4, 4, b, 4, 4);
for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++){
        cout << hex << res[i*4+j] << " ";
    }
    cout << endl;
}

a、b这2个在GF(256)域内的互为乘法逆矩阵,即
[ 02 03 01 01 01 02 03 01 01 01 02 03 03 01 01 02 ] × [ 0 e 0 b 0 d 09 09 0 e 0 b 0 d 0 d 09 0 e 0 b 0 b 0 d 09 0 e ] \begin{bmatrix} 02&03&01&01\\ 01&02&03&01\\ 01&01&02&03\\ 03&01&01&02 \end{bmatrix} \times \begin{bmatrix} 0e&0b&0d&09\\ 09&0e&0b&0d\\ 0d&09&0e&0b\\ 0b&0d&09&0e \end{bmatrix} 02010103030201010103020101010302 × 0e090d0b0b0e090d0d0b0e09090d0b0e
= [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ] =\begin{bmatrix} 1&0&0&0\\ 0&1&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix} = 1000010000100001

测试结果:

c 8 c 8 
8 c 8 c 
c 8 c 8 
8 c 8 c 
1 0 0 0 
0 1 0 0 
0 0 1 0 
0 0 0 1

五、相关资源

<think>嗯,用户问的是如何在MATLAB中计算华域的加法、乘法和幂函数。首先,我得回忆华域的基本概念。华域,也就是有限域,元素个数是素数的幂。MATLAB中应该有相关的函数来处理这个。 然后,我需要确认MATLAB中是否有专门的工具箱。记得之前用过通信工具箱或者可能是专门的Galois域函数。比如,gf函数用来创建华域数组。对吗? 接下来,加法部分。在华域中,加法是按位异或运算,特别是对于二进制域来说。比如,创建两个gf数组,然后直接使用+运算符。但要注意,元素必须在同一个域中,否则会出错。需要给出一个例子,比如GF(2^3),然后两个元素相加。 乘法的话,和加法类似,用*运算符。不过乘法是模多项式乘法,所以结果会根据域的生成多项式来取模。可能需要解释生成多项式的默认设置,或者如何指定不同的生成多项式。比如,3在GF(2^3)中是α^1,所以3*6的结果应该是α^1 * α^2 = α^3,然后根据生成多项式计算模的结果。 幂函数的话,使用.^运算符。比如,计算某个元素的幂次,注意指数可以是负数,这时需要求元。可能需要提醒用户,当元素为零且指数为负时会报错。 然后,需要考虑用户可能的错误,比如不同域的数组运算,或者指数处理不当。需要指出常见的错误和解决方法。例如,确保所有数组在同一个域,生成多项式致。 另外,可能需要提到如何查看生成多项式,使用gf对象的属性,比如default_primpoly,或者自定义生成多项式。这样用户可以更灵活地操作不同的域。 最后,总结步骤,给出示例代码,并强调关键点,比如使用gf函数创建数组,运算符直接使用,以及处理元的问题。这样用户能步步跟着实现,同时避免常见错误。</think>在MATLAB中,华域(Galois Field, GF)的运算可通过`gf`函数结合通信系统工具箱实现。以下是分步说明: --- ### **1. 创建华域数组** 使用`gf(data, m)`定义GF(2^m)的数组,其中`m`是域的次数: ```matlab % 创建GF(2^3)的数组 a = gf([1 2 3], 3); % 元素为α^0, α^1, α^2 b = gf([4 5 6], 3); % 元素为α^2, α^2+α^0, α^2+α^1 ``` --- ### **2. 加法运算** - **规则**:按位异或(XOR),即系数模2相加。 - **代码**: ```matlab c = a + b; % 结果为 [5 7 5],对应多项式系数模2运算 ``` --- ### **3. 乘法运算** - **规则**:基于生成多项式的模乘(默认使用本原多项式)。 - **代码**: ```matlab d = a * b; % 元素级乘法 e = a .* b; % 同上,等价写法 ``` - **示例**:在GF(2^3)中,若默认生成多项式为$D^3 + D + 1$: $$3 \times 6 = α^1 \times α^2 = α^{3} \equiv α^0 + α^1 \ (\text{mod} \ 1 + α + α^3) = 3$$ --- ### **4. 幂函数运算** - **规则**:通过`.^`运算符实现,支持负指数(求元)。 - **代码**: ```matlab f = a.^2; % 每个元素平方 g = a.^-1; % 求每个元素的乘法元 ``` - **注意**:若元素为0且指数为负,会报错。 --- ### **5. 生成多项式设置** 可指定自定义生成多项式(需为本原多项式): ```matlab % 使用生成多项式 x^3 + x^2 + 1 (二进制表示为1101) a = gf([1 2 3], 3, 13); % 13是二进制1101的十进制表示 ``` --- ### **6. 完整示例** ```matlab m = 3; % GF(2^3) a = gf(3, m); % α^1 b = gf(6, m); % α^2 % 加法 sum = a + b; % 3+6=5(二进制: 011⊕110=101) % 乘法 product = a * b; % 3×6=5(α^1×α^2=α^3≡α^0+α^1=3) % 幂函数 power = a.^3; % α^1^3 = α^3 ≡ 3 inverse = a.^-1; % α^(-1) = α^6 ≡ 6 ``` --- ### **关键注意事项** 1. **域致性**:参与运算的数组必须属于同华域。 2. **生成多项式**:未指定时MATLAB使用默认本原多项式,可通过`primpoly(m)`查询。 3. **错误处理**:零元素的运算(如`0^-1`)会抛出错误。 通过以上方法,可高效实现GF(2^m)的算术运算。建议通过`disp(a.x)`查看元素的指数形式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值