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

2019-04-14 20:49发布

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 #include #include #include #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为开头) "); 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(" 得到十六进制相加结果:%s ",sc); } void chenfa() { init(); printf("请输入要进行运算的一字节十六进制串(以0x为开头) "); 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(" 得到答案:%s ",sc); } int main() { while(true) { printf("请选择进行的运算: 0.退出运算 1.加法运算 2.乘法运算 "); int ch; scanf("%d",&ch); switch(ch) { case 0: system("cls"); printf(" 欢迎使用! "); exit(0); case 1: system("cls"); jiafa(); break; case 2: system("cls"); chenfa(); break; default : system("cls"); printf(" 输入错误!请重新输入: "); break; } } return 0; } 上面是笨办法,就是模拟做出来的,下面是简单方法:具体原理参考这位大佬:https://blog.csdn.net/bupt073114/article/details/27382533 我就是用他的原理自己实现了一波 代码: #include #include void jiafa() { printf("请输入两个十六进制串: "); int hex1,hex2; scanf("%x%x",&hex1,&hex2); printf(" 得到有限域内相加结果 : %#X ",hex1^hex2); } void chenfa() { int a[16],b[16],s[32]; printf("请输入两个十六进制串: "); 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(" 得到有限域内相乘结果 : %#X ",hex); } int main() { while(1) { printf("请选择进行的运算: 0.退出运算 1.加法运算 2.乘法运算 "); int ch; scanf("%d",&ch); switch(ch) { case 0: system("cls"); printf(" 欢迎使用! "); exit(0); case 1: system("cls"); jiafa(); break; case 2: system("cls"); chenfa(); break; default : system("cls"); printf(" 输入错误!请重新输入: "); break; } } return 0; }