由于项目的需要,在网上扒了半天,没有找到域GF(2^n)的C语言实现的系统的介绍。本文试图解释偶特征有限域的实现,让读者不必像我一样浪费太多时间在搜索中。本文以GF(2^8)为例。转载请注明出处,谢谢!
甲、有限域的加法实现
简单的异或运算即可:
unsigned char add(unsigned
char a, unsigned char b) {
return a ^ b;
}
乙、有限域的减法实现
与加法相同
unsigned char sub(unsigned char a, unsigned
char b) {
return a ^ b;
}
丙、有限域的乘法实现
算法简介
输入:8-bit数a,b,
输出:8-bit数c
1、设定c的初始值为0
2、执行以下循环8次
(1)如果b的最低位是1,则c与a做异或运算。
(2)检查a的最高位是否为1.
(3)a左移一位,即舍弃最高位,最低位以0补充。
(4)如果在上一步左移前,a的最高位是1,则a与十六进制数0x1b做异或运算。
(5)b右移1位,即舍弃最低位,最高位以0补充。
3、c
就是a和b的乘积。
乘法伪代码:
unsigned char mul(unsigned char a, unsigned char b) {
unsigned char p = 0;
unsigned char counter;
unsigned char hi_bit_set;
for(counter = 0; counter < 8; counter++) {
if((b & 1) == 1)
p ^= a;
hi_bit_set = (a & 0x80);
a <<= 1;
if(hi_bit_set == 0x80)
a ^= 0x1b;
b >>= 1;
}
return p;
}
例子假设 .
1.c
= 0; a = 7(0000 0111); b=3(0000 0011).
2.进入8次循环
第一次循环
(1)b
的最低位为1 , 故c=0^a=7.
(2)a的值原来是7,
左移一位后a的值为14(0000 1110).
(3)在a左移一位前,a=7(0000
0111), 显然它的最高位不是1,因此不需要与十六进制数0x1b做异或运算。
(4)b
右移一位,得b=1(00000001).
第二次循环
(1)b
的最低位为1 , 故c=c^a=7^14=9.
(2)左移一位后a的值为28(000
11100).
(3)在a左移一位前,a=14(0000
1110), 显然它的最高位不是1,因此不需要与十六进制数0x1b做异或运算。
(4)b
右移一位,得b=1(00000000).
在第三到第八次循环中,b=0,最低位为0,c的值不再改变。
3.
最后c=9,返回c=9;
丁、有限域乘法的快速实现
1、指数表和对数表
有限域的非零元素构成一个Abel群,从而每个非零元素都可以用群的某个生成元素表示。GF(2^8)的生成元素有:
3 5
6 9 11 14 17 18 19 20 23 24 25 26 28 30 3133 34 35 39 40 42 44 48
49 60 62 63 65 69 70 71 72 73 75 76 78 79 82 84 86 8788 89 90 91 95
100 101 104 105 109 110 112 113 118 119 121 122 123 126 129 132134
135 136 138 142 143 144 147 149 150 152 153 155 157 160 164 165 166
167 169170 172 173 178 180 183 184 185 186 190 191 192 193 196 200
201 206 207 208 214215 218 220 221 222 226 227 229 230 231 233 234
235 238 240 241 244 245 246 248251 253 254 255
这些数的16进制表示:
03 05 06 09 0b 0e 11 12 13 14 17 18 19 1a 1c 1e
1f 21 22 23 27 28 2a 2c 30 31 3c 3e 3f 41 45 46
47 48 49 4b 4c 4e 4f 52 54 56 57 58 59 5a 5b 5f
64 65 68 69 6d 6e 70 71 76 77 79 7a 7b 7e 81 84
86 87 88 8a 8e 8f 90 93 95 96 98 99 9b 9d a0 a4
a5 a6 a7 a9 aa ac ad b2 b4 b7 b8 b9 ba be bf c0
c1 c4 c8 c9 ce cf d0 d6 d7 da dc dd de e2 e3 e5
e6 e7 e9 ea eb ee f0 f1 f4 f5 f6 f8 fb fd fe ff
2、利用指数表和对数表进行快速乘法
本方法需要事先存储指数表和对数表,因此需要512Byte的内存。对AES来说,此方法对加密速度影响不大(最多只用3数乘法),但解密时(15数连乘),此方法可加快解密速度。
注意到,有限域GF(2^8)有256个数,但是,对数表只有255个数,这是因为0是一个比较特殊的数,任何数乘以0 都等于0.
unsigned
char Logtable[256]
=
{ 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223,
3,
100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28,
193,
125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201,
9, 120,
101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218,
142,
150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70,
131, 56,
102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136,
145, 16,
126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61,
186,
43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115,
167, 87,
175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230,
173, 232,
44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169,
81, 160,
127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118,
123, 183,
204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41,
157,
151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63,
91, 209,
83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211,
171,
68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153,
227, 165,
103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247,
112, 7};
unsigned charAlogtable[256]
=
{ 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19,
53,
95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102,
170,
229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171,
230, 49,
83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178,
205,
76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120,
136,
131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73,
219, 118, 154,
181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97,
163,
254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32,
96, 160,
251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63,
65,
195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191,
218, 117,
159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122,
142, 137, 128,
155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67,
197, 84,
252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70,
202,
69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81,
243, 14,
18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242,
13, 23,
57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82,
246, 1};
快速乘法:
unsigned
char mul(unsigned char
a,unsignedchar
b) {
if (a && b)
return Alogtable[(Logtable[a] + Logtable[b])%5];
else return 0;
}
戊、
有限域除法实现
unsigned char div(unsigned char
a,unsignedchar b) {
int j;
if (b == 0) {
printf( "Division by zero\n" );
abort();
}
if (a == 0) return (0);
if ((j = Logtable[a] - Logtable[b]) < 0) j += 255;
return (Alogtable[j]);
}
己、逆元
unsigned charinv(unsigned
charin) {
if(in == 0)return 0;
else
return Alogtable[(255 -
Logtable[in])];
}