GF(2^8)有限域的加法与乘法纯C语言的两种实现方式

GF(2^8)这是啥我就不多做解释了,某度某科与各位大佬的博客都有写,,,,

加法运算,超级简单,就是一个异或运算就解决了,这里主要说下乘法运算。

我们先规定下这里的模乘的不可约多项式为m=x^8+x^4+x^3+x+1

我说下在这里我的做法:

因为是二进制上的转化,所以我们可以先将输入的两个十六进制串转化为二进制,转化完后对它们进行乘法运算(下面会有样例)得到多项式mx,然后找到最高幂的次数,比较一下与8的差值,得到差c,再将不可约多项式乘上x^c,再与mx进行异或运算,再寻找下一个最高项的指数,重复以上运算,直到出现最高项的指数小于8。然后就得到了答案。

例如:0x57*0x83=x^13+x^11+x^9+x^8+x^6+x^5+x^4+x^3+x+1,                用二进制表示:010101101111011

第一次:最高幂为13,13-8=5,所以将m*x^5=x^13+x^9+x^8+x^6+x^5     用二进制表示:010001101100000

异或得到 000100000011011即多项式:x^11+x^4+x^3+x+1

第二次:最高幂为11,11-8=3,所以将m*x^3=x^11+x^7+x^6+x^4+x^3  二进制表示:000100011011000

异或得到:00000001100001即多项式:x^7+x^6+1,

第三次:最高幂为7小于8,不满足,取模结束

得到答案用十六进制表示为0xC1

经过运算暂未发现错误答案,若发现,还望各位大佬告知,菜鸡在此感谢万分

实现代码:

///2的8次方有限域内的加乘
///指定x^8+x^4+x^3+x+1为不可约多项式
///加法原理:异或操作
///乘法原理:循环操作,具体看过程
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
const int maxn=1010;
char sa[maxn],sb[maxn],sc[maxn];///要进行运算的十六进制串
int a[maxn],b[maxn],c[maxn];///a,b用来接收两个串转化成的二进制,c为中转及保存加法值
int sl[maxn];///用十六个空间存两个二进制相乘
int NB[maxn];///为不可约多项式的二进制表示
void init()///初始化
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    memset(sa,0,sizeof(sa));
    memset(sb,0,sizeof(sb));
    memset(sc,0,sizeof(sc));
    memset(sl,0,sizeof(sl));
}
void changebit(char s[],int flag)///将十六进制转为二进制(验证正确)
{
    int l=0;
    for(int i=2; i<4; i++)
    {
        memset(c,0,sizeof(c));
        int n=s[i],cnt=0;
        if(s[i]>='A')
            n-=55;
        else
            n-='0';
        while(n)
        {
            c[cnt++]=n%2;
            n/=2;
        }
        if(flag==1)
        {
            for(int j=3; j>=0; j--)
                a[l++]=c[j];
        }
        else
        {
            for(int j=3; j>=0; j--)
                b[l++]=c[j];
        }
    }


}
void bitchange()///将二进制转为十六进制
{
    sc[0]='0',sc[1]='x';
    int l=2;
    for(int i=0; i<8; i++)
    {
        if((i+1)%4==0)
        {
            int ans=c[i-3]*8+c[i-2]*4+c[i-1]*2+c[i];
            if(ans>9)
                sc[l++]='A'+ans-10;
            else
                sc[l++]=ans+'0';
        }
    }
}
void cy()///乘法运算
{
    for(int i=0; i<8; i++)
    {
        for(int j=0; j<8; j++)
        {
            if(a[i]&&b[j])
            {
                if(sl[14-i-j]==1)///最大两个x^7相乘
                    sl[14-i-j]=0;///如果已经有值则二进制归0
                else
                    sl[14-i-j]=1;
            }
        }
    }
}
int jisuan()///模拟过程
{
    int ans=0,i;///用来记录最大项大于8多少次
    for( i=16; i>=0; i--)
    {
        if(sl[i]==1)
        {
            ans=i-8;
            break;
        }
    }
    if(ans<0||(ans==0&&sl[0]==0))
        return 1;///计算结束
    else
        NB[ans]=1,NB[1+ans]=1,NB[3+ans]=1,NB[4+ans]=1,NB[8+ans]=1;
    return 0;
}
void jiafa()
{
    init();
    printf("请输入要进行运算的一字节十六进制串(以0x为开头)\n\n");
    scanf("%s %s",sa,sb);
    changebit(sa,1),changebit(sb,2);
    for(int i=0; i<8; i++)
        c[i]=a[i]^b[i];
    bitchange();
    printf("\n得到十六进制相加结果:%s\n\n",sc);
}
void chenfa()
{
    init();
    printf("请输入要进行运算的一字节十六进制串(以0x为开头)\n\n");
    scanf("%s %s",sa,sb);
    changebit(sa,1),changebit(sb,2);
    cy();
    while(1)
    {
        memset(NB,0,sizeof(NB));
        if(jisuan())
        {
            for(int i=0; i<8; i++)
                c[7-i]=sl[i];
            break;
        }
        else
            for(int i=0; i<16; i++)
                sl[i]^=NB[i];
    }

    bitchange();
    printf("\n得到答案:%s\n\n",sc);
}
int main()
{
    while(true)
    {
        printf("请选择进行的运算: 0.退出运算  1.加法运算  2.乘法运算\n\n");
        int ch;
        scanf("%d",&ch);
        switch(ch)
        {
        case 0:
            system("cls");
            printf("\n欢迎使用!\n");
            exit(0);
        case 1:
            system("cls");
            jiafa();
            break;
        case 2:
            system("cls");
            chenfa();
            break;
        default :
            system("cls");
            printf("\n输入错误!请重新输入:\n\n");
            break;
        }
    }
    return 0;
}

上面是笨办法,就是模拟做出来的,下面是简单方法:具体原理参考这位大佬:https://blog.csdn.net/bupt073114/article/details/27382533

我就是用他的原理自己实现了一波

代码:

#include<cstdio>
#include<cstdlib>
void jiafa()
{
    printf("请输入两个十六进制串:\n");
    int hex1,hex2;
    scanf("%x%x",&hex1,&hex2);
    printf("\n得到有限域内相加结果 : %#X\n\n",hex1^hex2);
}
void chenfa()
{
    int a[16],b[16],s[32];
    printf("请输入两个十六进制串:\n");
    int hex1,hex2;
    scanf("%x%x",&hex1,&hex2);
    int n=hex2,cnt=0;
    while(n)///转化为二进制
    {
        s[cnt++]=n%2;
        n/=2;
    }
    a[1]=0x01,b[1]=hex1;
    for(int i=2; i<=8; i++)
        a[i]=a[i-1]<<1;///得到0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80
    for(int i=2; i<=8; i++)
    {
        if(b[i-1]&0x80)///如果最高为为1就对不可约多项式取模,否则直接左移
            b[i]=((b[i-1]<<1)^0x1B);
        else
            b[i]=b[i-1]<<1;
        b[i]&=0xFF;///直接取后两位
    }
    int hex=0x00;
    for(int i=7; i>=0; i--)
    {
        if(s[i]==1)///当二进制的这一位为1的时候才能异或
            hex^=b[i+1];
    }
    printf("\n得到有限域内相乘结果 : %#X\n\n",hex);
}
int main()
{
    while(1)
    {
        printf("请选择进行的运算: 0.退出运算  1.加法运算  2.乘法运算\n\n");
        int ch;
        scanf("%d",&ch);
        switch(ch)
        {
        case 0:
            system("cls");
            printf("\n欢迎使用!\n");
            exit(0);
        case 1:
            system("cls");
            jiafa();
            break;
        case 2:
            system("cls");
            chenfa();
            break;
        default :
            system("cls");
            printf("\n输入错误!请重新输入:\n\n");
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lee371042/article/details/84559042