原文:https://blog.csdn.net/luotuo44/article/details/41645597
现在重点讲一下GF(2n),特别是GF(28),因为8刚好是一个字节的比特数。
前面说到, G F ( p ) GF(p) GF(p),p得是一个素数,才能保证集合中的所有元素都有加法和乘法逆元(0除外)。但我们却很希望0到255这256个数字也能组成一个域。因为很多领域需要用到。mod 256的余数范围就是0到255,但256不是素数。小于256的最大素数为251,所以很多人就直接把大于等于251的数截断为250。在图像处理中,经常会这样做。但如果要求图像无损的话,就不能截断。
貌似已经到了死胡同,救星还是有的,那就是 G F ( p n ) GF(p^n) GF(pn),其中p为素数。在这里我们只需令p为2,n为8,即 G F ( 2 8 ) GF(2^8) GF(28)。
G F ( 2 8 ) GF(2^8) GF(28)由一组从 0x00
到 0xff
的256个值组成,加上加法和乘法,因此是( 2 8 2^8 28)。GF代表伽罗瓦域,以发明这一理论的数学家的名字命名。 G F ( 2 8 ) GF(2^8) GF(28) 的一个特性是一个加法或乘法的操作的结果必须是在{0x00 ... 0xff}
这组数中。虽然域论是相当深奥的,但 G F ( 2 8 ) GF(2^8) GF(28)加法的最终结果却很简单。 G F ( 2 8 ) GF(2^8) GF(28) 加法就是异或(XOR
)操作。
要弄懂 G F ( 2 n ) GF(2^n) GF(2n),要先明白多项式运算。这里的多项式和初中学的多项式运算有一些区别。虽然它们的表示形式都是这样的: f ( x ) = x 6 + x 4 + x 2 + x + 1 f(x) = x^6 + x^ 4 + x^2 + x + 1 f(x)=x6+x4+x2+x+1。下面是它的一些特点。
看一些例子吧。对于 f ( x ) = x 6 + x 4 + x 2 + x + 1 。 g ( x ) = x 7 + x + 1 f(x) = x^6 + x^4 + x^2 + x + 1。g(x) = x^7 + x + 1 f(x)=x6+x4+x2+x+1。g(x)=x7+x+1。
那么:
f ( x ) + g ( x ) = x 7 + x 6 + x 4 + x 2 + ( 1 + 1 ) x + ( 1 + 1 ) 1 = x 7 + x 6 + x 4 + x 2 f(x) + g(x) = x^7 + x^6 + x^4+ x^2 + (1+1)x + (1+1)1 = x^7 + x^6 + x^4 + x^2 f(x)+g(x)=x7+x6+x4+x2+(1+1)x+(1+1)1=x7+x6+x4+x2
f ( x ) – g ( x ) f(x) – g(x) f(x)–g(x) 等于 f ( x ) + g ( x ) f(x) + g(x) f(x)+g(x)。
f ( x ) ∗ g ( x ) = ( x 1 3 + x 1 1 + x 9 + x 8 + x 7 ) + ( x 7 + x 5 + x 3 + x 2 + x ) + ( x 6 + x 4 + x 2 + x + 1 ) = x 1 3 + x 1 1 + x 9 + x 8 + x 6 + x 5 + x 4 + x 3 + 1 f(x) * g(x) =(x^13 + x^11 + x^9 + x^8 + x^7) + (x^7 + x^5 + x^3 + x^2 + x) + (x^6+ x^4 + x^2 + x + 1) = x^13 + x^11 + x^9 + x^8 + x^6 + x^5+ x^4+ x^3+1 f(x)∗g(x)=(x13+x11+x9+x8+x7)+(x7+x5+x3+x2+x)+(x6+x4+x2+x+1)=x13+x11+x9+x8+x6+x5+x4+x3+1
得其余数,也就是mod操作的结果。
对于多项式也类似素数,有素多项式。其定义和素数类似,素多项式不能表示为其他两个多项式相乘的乘积。
指数小于3的多项式有8个,分别是 0 0 0, 1 1 1, x x x,$ x+1 , , , x^2$, x 2 + 1 x^2+1 x2+1, x 2 + x x^2 + x x2+x, x 2 + x + 1 x^2+x+1 x2+x+1。对于 G F ( 2 3 ) GF(2^3) GF(23)来说,其中一个素多项式为 x 3 + x + 1 x^3+x+1 x3+x+1。上面8个多项式进行四则运算后 m o d ( x 3 + x + 1 ) mod (x^3+x+1) mod(x3+x+1)的结果都是 8 个之中的某一个(域内值互相四则运算)。当然也可以证明这是一个域,所以每一个多项式都是有加法和乘法逆元的(0除外)。注意,这些逆元都是和素多项式相关的,同一个多项式,取不同的素多项式,就有不同的逆元多项式。
对于 G F ( 2 8 ) GF(2^8) GF(28),其中一个素多项式为 x 8 + x 4 + x 3 + x + 1 x^8 + x^4 + x^3 +x +1 x8+x4+x3+x+1。对应地,小于8次的多项式有256个。
由素多项式得到的域,其加法单位元都是0,乘法单位元是1。
重点来了:
前面讲到了对素多项式取模,然后可以得到一个域。但这和最初的目的有什么关系吗?多项式和0, 1, ……,255没有什么关系。确实是没有什么关系,但多项式的系数确可以组成0, 1, 2,……255这些数。回到刚才的 G F ( 2 3 ) GF(2^3) GF(23),对应的8个多项式,其系数刚好就是 000,001, 010, 011, 100, 101, 110, 111。这不正是0到7这8个数的二进制形式吗?也就是说,它们有一一对应映射的关系。多项式对应一个值,我们可以称这个值为多项式值。
对于 G F ( 2 3 ) GF(2^3) GF(23),取素多项式为 x 3 + x + 1 x^3 + x+1 x3+x+1 ,那么多项式 x 2 + x x^2+x x2+x 的乘法逆元就是x+1。系数对应的二进制分别为110和011。此时,我们就认为对应的十进制数6和3互为逆元。即使 mod 8不能构成一个域,但通过上面的对应映射,0到7这8个数一样有对应逆元了(为了顺口,说成0到7。实际0是没有乘法逆元的)。同样,对于 G F ( 2 8 ) GF(2^8) GF(28) 也是一样的。所以0到255,这256个数都可以通过这样的方式得到乘法逆元(同样,0是没有乘法逆元的)。
其实,通过前面的讲解,已经可以对GF(2^8)进行四则运算了。但计算起来相当麻烦。接下来就是讲解一下怎么用简单的方法进行四则运算,以及编程的实现(对于码农来说,这才是终极目标啊)。
**下面讲解的所有运算,默认的素多项式为 $ x^8 +x^4 + x^3 +x +1 , 用 m ( x ) 表 示 。 ∗ ∗ ,用 m(x) 表示。** ,用m(x)表示。∗∗GF(2^8)$的素多项式有多个,但这个经典啊。
加法和减法就是经典的异或运算,没有什么可说的。
前面的一个多项式相乘例子有说到怎么进行相乘计算,但过于复杂。《密码编码学与网络安全》一书说到了一个计算乘法的技巧。
首先有, x 8 m o d m ( x ) = [ m ( x ) – x 8 ] = x 4 + x 3 + x + 1 x^8 mod m(x) = [m(x) – x^8] = x^4 + x^3 +x +1 x8modm(x)=[m(x)–x8]=x4+x3+x+1。
对于多项式f(x), 有:
f ( x ) = b 7 x 7 + b 6 x 6 + b 5 x 5 + b 4 x 4 + b 3 x 3 + b 2 x 2 + b 1 x + b 0 f(x) = b_7x^7 + b_6x^6 + b_5x^5 + b_4x^4 + b_3x^3 + b_2x^2 + b_1x + b_0 f(x)=b7x7+b6x6+b5x5+b4x4+b3x3+b2x2+b1x+b0
x ∗ f ( x ) = ( b 7 x 8 + b 6 x 7 + b 5 x 6 + b 4 x 5 + b 3 x 4 + b 2 x 3 + b 1 x 2 + b 0 x ) m o d m ( x ) x * f(x) = (b_7x^8 + b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x ^2+ b_0x) mod m(x) x∗f(x)=(b7x8+b6x7+b5x6+b4x5+b3x4+b2x3+b1x2+b0x)modm(x)
如果 b 7 b_7 b7等于0,那么结果是一个小于8的多项式,不需要取模计算了。如果 b 7 b_7 b7等于1,那么通过上面所得就有:
$x * f(x) = ( b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x ^2+ b_0x) + (x^4 + x^3 +x + 1) $ [1]
对于C语言来说,通过位移运算符<< 和 异或运算,很容易计算。对于x的指数高于一次的情况,可以通过递归的形式使用。如:x^2 * f(x) = x*[x*f(x)]。
虽然有上面的技巧,但还是过于复杂。在大量运算中(比如图像处理),耗时太多。于是人们就想到了通过查表的形式计算。
首先,在群中定义幂运算为重复运用群的运算符。假如运算符为普通的加法,那么幂运算就是多个加法一起使用。
如果元素g满足下面的条件,我们就称g为生成元:对于集合中的任何的一个元素,都可以通过元素g的幂 g k g^k gk得到。并定义 g 0 = e g^0 = e g0=e,假设h为 g 的逆元,那么还定义 g ( − k ) = h k g^{(-k)} = h^k g(−k)=hk。比如,整数集合,都可以由生成元1得到。 2 = 1 + 1 = 1 2 2 = 1 + 1 = 1^2 2=1+1=12、 3 = 1 3 = 1 + 1 + 1 3 = 1^3=1 + 1 + 1 3=13=1+1+1、……。负数可以通过幂取负数得到。
将生成元应用到多项式中, GF(2^n)中的所有多项式都是可以通过多项式生成元g通过幂求得。即域中的任意元素a,都存在一个k,使得a = g^k。
对于 g k = a g^k = a gk=a,有正过程和逆过程。知道 k 求 a 是正过程,知道了 a 反过来求k是逆过程。同样,假设有 g n = a g^n = a gn=a 和 g m = b g^m = b gm=b 。现在需要求 a ∗ b a*b a∗b,那么就有 a ∗ b = g n ∗ g m = g ( n + m ) a*b = g^n* g^m = g^(n+m) a∗b=gn∗gm=g(n+m) 。我们只需要:根据 a 和 b ,分别求得 n 和 m 。然后直接计算 g ( n + m ) g^(n+m) g(n+m) 即可。求,并不是真的傻乎乎地通过计算而得到,而是通过查表。这里,构造两个表,正表和反表。正表是知道了指数,求值。反表是知道了值,求指数。接下来要做的就是构造这两个表。为了做除法运算,还要构造逆元表。
在给出三个表的构造代码前,有几个东西要讲一下。
虽然生成元g的幂次厉害,但多项式0,是无法用生成元生成的。g0等于多项式1,而不是0。为什么?逆向思考一下:假如存在k使得gk = 0,那么g^(k+1)等于多少呢?
G F ( 2 n ) GF(2^n) GF(2n)是一个有限域,就是元素个数是有限的,但指数k是可以无穷的。所以必然存在循环。这个循环的周期是2n-1,因为多项式0,g不能生成,少了一个。所以对于GF(28),当k大于等于255时,g^k =g^(k%255)。所以对于正表,生成元的指数,取0到254即可,对应地生成255个不同的多项式,多项式的取值范围为1到255。
有了上面的讨论,对于正表,只需依次计算 g 0 g^0 g0、 g 1 g^1 g1、 g 2 g^2 g2,……, g 254 g^{254} g254 即可。对于 G F ( 2 8 ) GF(2^8) GF(28),素多项式 m ( x ) = x 8 + x 4 + x 3 + x + 1 m(x) = x^8 + x^4 + x^3 +x +1 m(x)=x8+x4+x3+x+1 ,对应的生成元 g ( x ) = x + 1 g(x) = x + 1 g(x)=x+1 。下面是具体的实现代码:
int table[256];
int i;
table[0] = 1;//g^0
for(i = 1; i < 255; ++i)//生成元为x + 1
{
//下面是m_table[i] = m_table[i-1] * (x + 1)的简写形式
table[i] = (table[i-1] << 1 ) ^ table[i-1];
//最高指数已经到了8,需要模上m(x)
if( table[i] & 0x100 ) // 如果table[i] 大于 2^8 就 执行上面 [1] 的乘法技巧
{
table[i] ^= 0x11B;//用到了前面说到的乘法技巧 0x11B 就是 2^8 + 2^4 + 2^3 + 1
}
}
输出:
正表(十进制) | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 5 | 15 | 17 | 51 | 85 | 255 | 26 | 46 | 114 | 150 | 161 | 248 |
95 | 225 | 56 | 72 | 216 | 115 | 149 | 164 | 247 | 2 | 6 | 10 | 30 | 34 |
229 | 52 | 92 | 228 | 55 | 89 | 235 | 38 | 106 | 190 | 217 | 112 | 144 | 171 |
83 | 245 | 4 | 12 | 20 | 60 | 68 | 204 | 79 | 209 | 104 | 184 | 211 | 110 |
76 | 212 | 103 | 169 | 224 | 59 | 77 | 215 | 98 | 166 | 241 | 8 | 24 | 40 |
131 | 158 | 185 | 208 | 107 | 189 | 220 | 127 | 129 | 152 | 179 | 206 | 73 | 219 |
181 | 196 | 87 | 249 | 16 | 48 | 80 | 240 | 11 | 29 | 39 | 105 | 187 | 214 |
254 | 25 | 43 | 125 | 135 | 146 | 173 | 236 | 47 | 113 | 147 | 174 | 233 | 32 |
251 | 22 | 58 | 78 | 210 | 109 | 183 | 194 | 93 | 231 | 50 | 86 | 250 | 21 |
195 | 94 | 226 | 61 | 71 | 201 | 64 | 192 | 91 | 237 | 44 | 116 | 156 | 191 |
159 | 186 | 213 | 100 | 172 | 239 | 42 | 126 | 130 | 157 | 188 | 223 | 122 | 142 |
155 | 182 | 193 | 88 | 232 | 35 | 101 | 175 | 234 | 37 | 111 | 177 | 200 | 67 |
252 | 31 | 33 | 99 | 165 | 244 | 7 | 9 | 27 | 45 | 119 | 153 | 176 | 203 |
69 | 207 | 74 | 222 | 121 | 139 | 134 | 145 | 168 | 227 | 62 | 66 | 198 | 81 |
18 | 54 | 90 | 238 | 41 | 123 | 141 | 140 | 143 | 138 | 133 | 148 | 167 | 242 |
57 | 75 | 221 | 124 | 132 | 151 | 162 | 253 | 28 | 36 | 108 | 180 | 199 | 82 |
这个正表,下标值等于生成元的指数,下标对应的元素值等于对应的多项式值。
例如:下标为 3 的(下标从 0 开始),这里 合并同类项时,系数们进行异或操作,不是平常的加法操作。看上面多项式运算第2条;
( x + 1 ) 3 = ( x + 1 ) 2 ∗ ( x + 1 ) = ( x 2 + x + x + 1 ) ∗ ( x + 1 ) = ( x 2 + 1 ) ∗ ( x + 1 ) = x 3 + x 2 + x + 1 (x + 1)^3 = (x + 1)^2 * (x + 1) = (x^2 + x + x + 1) * (x + 1) = (x^2 + 1) * (x + 1) = x^3 + x^2 + x + 1 (x+1)3=(x+1)2∗(x+1)=(x2+x+x+1)∗(x+1)=(x2+1)∗(x+1)=x3+x2+x+1
那么 该值就是 2 3 + 2 2 + 2 + 1 = 15 2^3 + 2^2 + 2 + 1 = 15 23+22+2+1=15
反表和正表是对应的,所以反表中元素的个数也是255个。正表中,生成元g的指数k的取值范围为0到254。多项式值 g k g^k gk 的取值范围为1到255。所以在反表中,下标的取值范围为1到255,元素值的取值范围为0到254。实现代码如下:
int arc_table[256];
for(i = 0; i < 255; ++i)
arc_table[ table[i] ] = i;
反表 (十进制) | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
*** | 0 | 25 | 1 | 50 | 2 | 26 | 198 | 75 | 199 | 27 | 104 | 51 | 238 |
100 | 4 | 224 | 14 | 52 | 141 | 129 | 239 | 76 | 113 | 8 | 200 | 248 | 105 |
125 | 194 | 29 | 181 | 249 | 185 | 39 | 106 | 77 | 228 | 166 | 114 | 154 | 201 |
101 | 47 | 138 | 5 | 33 | 15 | 225 | 36 | 18 | 240 | 130 | 69 | 53 | 147 |
150 | 143 | 219 | 189 | 54 | 208 | 206 | 148 | 19 | 92 | 210 | 241 | 64 | 70 |
102 | 221 | 253 | 48 | 191 | 6 | 139 | 98 | 179 | 37 | 226 | 152 | 34 | 136 |
126 | 110 | 72 | 195 | 163 | 182 | 30 | 66 | 58 | 107 | 40 | 84 | 250 | 133 |
43 | 121 | 10 | 21 | 155 | 159 | 94 | 202 | 78 | 212 | 172 | 229 | 243 | 115 |
175 | 88 | 168 | 80 | 244 | 234 | 214 | 116 | 79 | 174 | 233 | 213 | 231 | 230 |
44 | 215 | 117 | 122 | 235 | 22 | 11 | 245 | 89 | 203 | 95 | 176 | 156 | 169 |
127 | 12 | 246 | 111 | 23 | 196 | 73 | 236 | 216 | 67 | 31 | 45 | 164 | 118 |
204 | 187 | 62 | 90 | 251 | 96 | 177 | 134 | 59 | 82 | 161 | 108 | 170 | 85 |
151 | 178 | 135 | 144 | 97 | 190 | 220 | 252 | 188 | 149 | 207 | 205 | 55 | 63 |
83 | 57 | 132 | 60 | 65 | 162 | 109 | 71 | 20 | 42 | 158 | 93 | 86 | 242 |
68 | 17 | 146 | 217 | 35 | 32 | 46 | 137 | 180 | 124 | 184 | 38 | 119 | 153 |
103 | 74 | 237 | 222 | 197 | 49 | 254 | 24 | 13 | 99 | 140 | 128 | 192 | 247 |
对于逆元表,先看逆元的定义。若a和b互为逆元,则有 a ∗ b = e a * b = e a∗b=e。用生成元表示为: g n ∗ g m = e = 1 g^n * g^m = e = 1 gn∗gm=e=1。又因为 e = g 0 = g 255 e = g^0 = g^{255} e=g0=g255(循环,回头了)。所以 g k ∗ g ( 255 − k ) = g ( k + 255 − k ) = e g^k * g^{(255-k)} = g^{(k + 255 -k)} = e gk∗g(255−k)=g(k+255−k)=e。于是 g k g^k gk 和 g ( 255 − k ) g^{(255-k)} g(255−k) 互为逆元。对于多项式值val,求其逆元。可以先求val对应的g幂次是多少。即g的多少次方等于val。可以通过反向表查询, 设为 k k k。那么其逆元的幂次为 255 − k 255-k 255−k。此时再通过正向表查询即可。实现代码如下:
int inverse_table[256];
for(i = 1; i < 256; ++i)//0没有逆元,所以从1开始
{
int k = arc_table[i];
k = 255 - k;
k %= 255;//m_table的取值范围为 [0, 254]
inverse_table[i] = table[k];
}
逆表 (十进制) | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
*** | 1 | 141 | 246 | 203 | 82 | 123 | 209 | 232 | 79 | 41 | 192 | 176 | 225 |
116 | 180 | 170 | 75 | 153 | 43 | 96 | 95 | 88 | 63 | 253 | 204 | 255 | 64 |
58 | 110 | 90 | 241 | 85 | 77 | 168 | 201 | 193 | 10 | 152 | 21 | 48 | 68 |
44 | 69 | 146 | 108 | 243 | 57 | 102 | 66 | 242 | 53 | 32 | 111 | 119 | 187 |
29 | 254 | 55 | 103 | 45 | 49 | 245 | 105 | 167 | 100 | 171 | 19 | 84 | 37 |
237 | 92 | 5 | 202 | 76 | 36 | 135 | 191 | 24 | 62 | 34 | 240 | 81 | 236 |
22 | 94 | 175 | 211 | 73 | 166 | 54 | 67 | 244 | 71 | 145 | 223 | 51 | 147 |
121 | 183 | 151 | 133 | 16 | 181 | 186 | 60 | 182 | 112 | 208 | 6 | 161 | 250 |
131 | 126 | 127 | 128 | 150 | 115 | 190 | 86 | 155 | 158 | 149 | 217 | 247 | 2 |
222 | 106 | 50 | 109 | 216 | 138 | 132 | 114 | 42 | 20 | 159 | 136 | 249 | 220 |
251 | 124 | 46 | 195 | 143 | 184 | 101 | 72 | 38 | 200 | 18 | 74 | 206 | 231 |
12 | 224 | 31 | 239 | 17 | 117 | 120 | 113 | 165 | 142 | 118 | 61 | 189 | 188 |
11 | 40 | 47 | 163 | 218 | 212 | 228 | 15 | 169 | 39 | 83 | 4 | 27 | 252 |
122 | 7 | 174 | 99 | 197 | 219 | 226 | 234 | 148 | 139 | 196 | 213 | 157 | 248 |
177 | 13 | 214 | 235 | 198 | 14 | 207 | 173 | 8 | 78 | 215 | 227 | 93 | 80 |
91 | 35 | 56 | 52 | 104 | 70 | 3 | 140 | 221 | 156 | 125 | 160 | 205 | 26 |
求完三个表后,现在总结一下三个表下标和下标对应元素值的含义。
有了这些表,现在再去求多项式相乘,那么超级简单了。代码如下:
int mul(int x, int y)
{
if( !x || !y )
return 0;
return table[ (arc_table[x] + arc_table[y]) % 255];
}
除法直接使用上面的逆元表即可,所以 a/b 等于 mul(a, inverse_table[b]); 这里b不能取 0。0 没有逆元,不能除于 0。
拉格朗日插值是什么,可以参考维基百科。拉格朗日插值的一个很常见应用是:知道了平面上的n个点的坐标值,现在求一个函数 f ( x ) f(x) f(x),它经过这n个点。
在实数里面,利用拉格朗日插值法是很容易求的。但对于 G F ( p ) GF(p) GF(p)和 G F ( p n ) GF(p^n) GF(pn),拉格朗日插值法就有点难了。一开始我甚至怀疑拉格朗日插值法能不能用于 G F ( p ) GF(p) GF(p)和 G F ( p n ) GF(p^n) GF(pn),毕竟这两个东西的运算规则是奇葩的(特别是 G F ( p n ) GF(p^n) GF(pn))。不得不说,拉格朗日更奇葩,他构造出来的拉格朗日插值法也能用于 G F ( p ) GF(p) GF(p) 和 G F ( p n ) GF(p^n) GF(pn)。
对于 G F ( p ) GF(p) GF(p)和 G F ( p n ) GF(p^n) GF(pn),拉格朗日插值法中的分母,直接用其逆元即可。计算起来也不是太难,用前面提到的逆元表更是容易。
拉格朗日插值法中的分子就坑爹了。虽然展开后,有一些规律,但对于编程来说,是很麻烦的。
还好,在中国知网那里搜到了一篇文章,里面有讲到怎么把拉格朗日插值法中的分子展开成利于编程实现的形式。鉴于读者们可能不能在知网下载文章,所以我就把文章上传到csdn中。读者可以点这里下载,细看。这里就不讲了,直接给出实现代码。
#include
#include
using namespace std;
int accumulate(const std::vector &vec, int start, int end)
{
int i, val = 0;
while( start != end)
{
val += vec[start++];
}
return val;
}
std::vector fun(std::vector& vec)
{
int i, j;
int size = vec.size();
std::vector factor;
std::vector result(vec.size() + 1, 1);
factor.resize(size, 1);
for(j = 0; j < size; ++j)
{
std::vector temp;
for(i = 0; i < size - j; ++i)
{
temp.push_back(vec[i] * factor[i]);
}
result[j + 1] = accumulate(temp, 0, temp.size());
for(i = 1; i < temp.size(); ++i)
factor[i-1] = accumulate(temp, i, temp.size());
}
return result;
}
int main()
{
int val[] = {2, 3, 5};
std::vector vec(val, val + sizeof(val)/sizeof(val[0]));
//结果数组中,依次是高最次幂的系数,次高次幂的系数....一次幂的系数,常数项的系数
std::vector result = fun(vec);
int i = 0;
for(i = 0; i < result.size(); ++i)
cout<
需要注意的是,上面代码是那篇文章的直接实现,是在实数域里面的运算。需要修改才能用于 G F ( 2 8 ) GF(2^8) GF(28)。只需把代码里面的加法和乘法替换成 G F ( 2 8 ) GF(2^8) GF(28)的加法和乘法即可。