一、有限域簡介
有限域亦稱伽羅瓦域(Galois Fields),是伽羅瓦於 18 世紀 30 年代研究代數方程根式求解問題時引出的概念。有限域在密碼學、近代編碼、計算機理論、組合數學等方面有着廣泛的應用
在抽象代數中,域是一個對加法和乘法封閉的集合,其中要求每個元素都有加法逆元,每個非零元素都有乘法逆元。若域 \(F\) 只包含有限個元素,則稱為有限域,有限域中元素的個數稱為有限域的階。可以證明,有限域的階必為素數的冪,即有限域的階可表示為 \(p^n\)(\(p\) 是素數,\(n\) 是正整數)。有限域通常記為 \(GF(p^n)\)
二、有限域同構
因為網上似乎都沒有如何尋找有限域同構映射的資料,而正好我上課學到了相關的內容,在此結合自己的理解作簡單的介紹。因為不是數學系相關的學生,而且對有限域的理解僅處於皮毛,有很多定理沒辦法給出詳細的證明,在邏輯上或許會多有漏洞,如果讀者發現我的漏洞希望能夠指出。
(雖然指出了我也不一定能聽懂,但還是希望能夠指出)
另外,有限域的相關知識(例如有限域的性質,有限域的構造等)將默認讀者已經了解,在閱讀后續內容前先保證對上述知識有所了解
關於復合域強烈建議參考這篇博客: AES 和 SM4 S 盒復合域實現方法,本文提到的內容參考了論文《適合SMS4算法硬件實現的S盒構造新方法》中給出的求解同構映射的方法 (--- 2022.04.28 更新 ---)
上面的鏈接好像打不開了,不過我在github上好像找到了對應的作者,SM4-with-AESENCLAST 這個鏈接是對應的資料。
很多尋找有限域同構的方法采用的都是正規基之類的,但我這塊不是很了解,可能沒法給各位滿意的答復。我這里提到的方法是《適合 SMS4 算法硬件實現的 S 盒構造新方法》(徐艷華、白雪飛、郭立)這篇論文中的采用的方法,但論文里邊原理部分感覺不是很清楚。這篇博客是我根據上課學到的內容結合自己的理解寫的,原理上應該會有紕漏 (--- 2022.12.27 更新 ---)
關於復合域優化SM4算法強烈建議參考下方論文: (--- 2023.05.27 更新 ---)
[1] 陳晨,郭華,王闖等.一種基於復合域的國密SM4算法快速軟件實現方法[J].密碼學報,2023,10(02):289-305.
2.1 尋找同構映射思路
首先,任意相同階數的有限域都同構。假設 \(p(x)\) 和 \(q(x)\) 都是域 \(F_p\) 上的 \(n\) 階不可約多項式,那么有限域 \(F_1 = F_p[x] / p(x)\) 和 \(F_2 = F_p[x] / q(x)\) 都是 \(p^n\) 階有限域。
有下面兩條重要定理:
- 如果假設 \(\alpha\) 是多項式 \(p(x)\) 的一個根,那么有限域 \(F_1\) 可以表示成 \(F_p[\alpha]\)
- 如果假設 \(\beta\) 是多項式 \(q(x)\) 的一個根,那么有限域 \(F_2\) 可以表示成 \(F_p[\beta]\)
現在需要找到一個兩者的同構映射 \(\phi\)
首先,根 \(\alpha\) 和 \(\beta\) 滿足 \(p(\alpha)=0\) 和 \(q(\beta)=0\)
直接將 \(\alpha\) 映射到 \(\beta\) 是不可行的,因為線性關系無法保證,即無法保證 \(p(\beta)=0\)
那么如果找到 \(\beta ' \in F_p[\beta]\) 使得 \(p(\beta')=0\) 成立,這樣就可以構造 \(\alpha \to \beta '\) 的映射
2.2 尋找同構映射例子
求有限域 \(Z_3[x] / (x^2 + 1)\) 和 \(Z_3[x] / (x^2 + x +2)\) 之間的同構映射
記 \(p(x) = x^2 + 1\) ,\(q(x) = x^2 + x + 2\)
且有 \(\alpha = \overline{x} \; mod \; p(x)\) 為 \(p(x)\) 的一個根
且有 \(\beta = \overline{x} \; mod \; q(x)\) 為 \(q(x)\) 的一個根
尋找得到 \(\beta' = \beta + 2\) ,使得 \(p(\beta') = (\beta + 2)^2 + 1 = \beta^2 + \beta + 2 = 0\)
那么對應的映射為 \(\alpha \to \beta + 2\)
也就是原先 \(Z_3[\alpha]\) 中的元素 \(a_1 \alpha + a_0\) 將被映射成 \(a_1 (\beta + 2) + a_0 = a_1 \beta + (2a_1 + a_0) \in Z_3[\beta]\)
或者說原先 \(Z_3[x] / (x^2 + 1)\) 中的元素 \(a_1 x + a_0\) 將被映射到 \(Z_3[x] / (x^2 + x +2)\) 中的 \(a_1 x + (2a_1 + a_0)\)
2.3 同構映射逆映射
在 2.2 中已經求出了一個同構映射 \(\alpha \to \beta + 2\)
很容易發現 \(q(\alpha - 2) = (\alpha - 2)^2 + (\alpha - 2) + 2 = \alpha^2 + 1 = 0\)
也就是說逆映射為 \(\beta \to \alpha - 2\)
三、復合域與同構
3.1 復合域
接下來介紹一個稍微復雜的有限域——復合域,復合域在密碼學中具有非常大的用途,將一個高階的有限域轉化為兩個或多個低階有限域的復合,便於后續分析
記 \(p(x) = x^2 + x + 4\) ,\(F_2[x] / p(x)\) 為 \(2^2\) 階有限域
記 \(q(x) = x^4 + x^3 + 1\) ,\(F_2[x] / q(x)\)為 \(2^4\) 階有限域
那么將兩者復合得到 \(F : b_1 x + b_2 \; mod \; p(x), \; b_i \in F_2[x] / q(x)\) ,為 \((2^4)^2 = 2^8\) 階有限域(復合域)
3.2 復合域同構
通過一個例子來了解求復合域同構的過程
記 \(F_2[x] / r(x)\) 為 \(2^8\) 階有限域, \(r(x) = x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1\)
記 \(F[x] / (p(x), q(y)) = (a_3 y^3 + a_2 y^2 + a_1 y + a_0) x + (b_3 y^3 + b_2 y^2 + b_1 y + b_0)\) 為上述 3.1 中的 \((2^4)^2\) 階有限域
求 \(F_2[x] / r(x) \to F[x] / (p(x), q(x))\) 的一個同構映射
首先,需要遍歷 \(F[x] / (p(x), q(y))\) 的全部元素,找到其中一個 \(\beta'\) 滿足 \(r(\beta') = 0\) 的元素 \((y^2 + 1)x + (y^3 + y^2 + y)\)
記 \(\alpha = \overline{x} \; mod \; r(x)\) 為 \(r(x)\) 的根
那么同構映射為 \(\alpha \to \beta'\)
四、映射矩陣
4.1 有限域與矩陣
在密碼學中,常將多項式表示為矩陣的形式,例如在 \(GF(2^8)\) 上的多項式
假設 \(p(x)\) 和 \(q(x)\) 都是 \(F_2\) 上的 \(8\) 次不可約多項式,那么可以構成 \(2^8\) 階有限域 \(F_2[x]/p(x)\) 和 \(F_2[x]/q(x)\)
假設 \(\alpha\) 是多項式 \(p(x)\) 的一個根,那么有限域 \(F_2[x]/p(x)\) 可以表示成 \(F_2[\alpha]\)
假設 \(\beta\) 是多項式 \(q(x)\) 的一個根,那么有限域 \(F_2[x]/q(x)\) 可以表示成 \(F_2[\beta]\)
且假設 \(c_7 x^7 + c_6 x^6 + c_5 x^5 + \cdots + c_1 x + c_0\) 是 \(F_2[x]/p(x)\) 上的一個多項式,那么該多項式也可以等價於 \(c_7 \alpha^7 + c_6 \alpha^6 + c_5 \alpha^5 \cdots c_1 \alpha + c_0\) ,即
4.2 多項式矩陣
假設 \(\alpha^i = a_{7,i} x^7 + a_{6,i} x^6 + \cdots a_{1,i} x + a_{0,i}\)
那么
當 \(\alpha = \overline{x} \; mod \; p(x)\) 時,上式為單位陣 \(I\)
4.3 同構映射與矩陣
假設 \(c_7 x^7 + c_6 x^6 + c_5 x^5 + \cdots + c_1 x + c_0\) 是 \(F_2[x]/p(x)\) 上的多項式
假設 \(d_7 x^7 + d_6 x^6 + d_5 x^5 + \cdots + d_1 x + d_0\) 是 \(F_2[x]/q(x)\) 上的多項式
記它們兩者的矩陣表示為 \(C\) 和 \(D\)
要找到兩個域的映射關系,將一個多項式映射到另一個多項式
也就是要找到一個映射矩陣 \(T\) ,使得一個多項式的矩陣表示 \(C\) 和另一個多項式的矩陣表示 \(D\) 滿足 \(TC = D\)
上文提到,可以找到一個同構映射 \(\alpha \to \beta'\) ,使得有限域 \(F_2[\alpha]\) 和有限域 \(F_2[\beta]\) 同構
根據同構關系的線性性質,有 \(\alpha^i \to \beta'^i\) ,故映射為
記 \(\alpha\) 對應的矩陣(如4.2所示)為 \(A\) , \(\beta'\) 對應的矩陣為 \(B\)
那么映射矩陣 \(T\) 滿足 \(TAC = BC\) ,即 \(T= B A^{-1}\)
為了計算方便,一般選取的根 \(\alpha = \overline{x} \; mod \; p(x)\)
那么 \(\alpha\) 對應的矩陣 \(A\) 即為單位陣 \(I\)
那么 \(T = B\)
假設 \(\beta'^i = b_{7,i} x^7 + b_{6,i} x^6 + \cdots b_{1,i} x + b_{0,i}\)
那么
4.4 一般算法流程
首先,需要找到兩個域 \(F_2[x]/p(x)\) 和 \(F_2[x]/q(x)\) 滿足映射關系的 \(\alpha\) 和 \(\beta'\)
其中 \(\alpha = \overline{x} \; mod \; p(x)\) , \(\beta = \overline{x} \; mod \; q(x)\)
且 \(p(\beta') = 0, \beta' \in F_2[\beta] = F_2[x]/q(x)\)
計算 \(\beta'^i, i = 0, 1, \cdots , 7\) ,並將 \(\beta'^i\) 的系數值置於矩陣 \(T\) 的倒數第 \(i\) 列(從0開始)
五、代碼實現(尋找同構映射)
有限域的四則運算:點擊此處跳轉
假設 \(p(x) = x^8 + x^4 + x^3 + x + 1\) ,\(q(x) = x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1\)
需要求解 \(F_2[x]/p(x)\) 和 \(F_2[x]/q(x)\) 之間的映射關系
5.1 有限域類(GF28)
def gf2_mul(a: int, b: int, poly: int) -> int:
"""有限域乘法"""
ans = 0
digit = poly.bit_length() - 1
while b:
if b & 1:
ans = ans ^ a
a, b = a << 1, b >> 1
if a >> digit:
a = a ^ poly
return ans
class GF256:
def __init__(self, value, poly):
self.value = value
self.poly = poly
def __add__(self, other):
"""加法"""
return GF256(self.value ^ other.value, self.poly)
def __sub__(self, other):
"""減法"""
return GF256(self.value ^ other.value, self.poly)
def __mul__(self, other):
"""乘法"""
return GF256(gf2_mul(self.value, other.value, self.poly), self.poly)
def __pow__(self, power, modulo=None):
"""冪"""
res = GF256(1, self.poly)
for i in range(power):
res = res * self
return res
5.2 p(x)和q(x)定義
px = 0b100011011 # x^8 + x^4 + x^3 + x + 1
qx = 0b111110101 # x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1
p = lambda x: x ** 8 + x ** 4 + x ** 3 + x + x ** 0
q = lambda x: x ** 8 + x ** 7 + x ** 6 + x ** 5 + x ** 4 + x ** 2 + x ** 0
5.3 遍歷搜索
for i in range(2 ** 8):
# 遍歷 F_2[x]/q(x) 的元素
t = GF256(i, qx)
if p(t).value == 0: # 滿足p(t)=0
print(bin(t.value))
得到8個結果
0b100000
0b110011
0b111110
0b1110000
0b10011111
0b10100110
0b10101010
0b11001110
5.4 結果
令 \(\alpha = \overline{x} \; mod \; p(x)\) 為 \(p(x)\) 的一個根
令 \(\beta = \overline{x} \; mod \; q(x)\) 為 \(q(x)\) 的一個根
上述結果也就是找到了8個映射關系,分別為
值 | 關系 |
---|---|
0b100000 | \(\alpha \to \beta^5\) |
0b110011 | \(\alpha \to \beta^5 + \beta^4 + \beta + \beta^0\) |
0b111110 | \(\alpha \to \beta^5 + \beta^4 + \beta^3 + \beta^2 + \beta^1\) |
0b1110000 | \(\alpha \to \beta^6 + \beta^5 + \beta^4\) |
0b10011111 | \(\alpha \to \beta^7 + \beta^4 + \beta^3 + \beta^2 + \beta^1 + \beta^0\) |
0b10100110 | \(\alpha \to \beta^7 + \beta^5 + \beta^2 + \beta^1\) |
0b10101010 | \(\alpha \to \beta^7 + \beta^5 + \beta^3 + \beta^1\) |
0b11001110 | \(\alpha \to \beta^7 + \beta^6 + \beta^3 + \beta^2 + \beta^1\) |
六、有限域同構與密碼學
在例如 AES 和 SM4 這類對稱密碼的 S 盒變換的底層,所使用的就是有限域 \(GF(2^8)\) 的求逆變換(除了求逆還涉及一些仿射變換)。
如果采用硬件(例如FPGA)實現密碼算法,可將 \(GF(2^8)\) 的同構於 \(GF((2^4)^2)\) 復合域甚至同構於 \(GF(((2^2)^2)^2)\) 復合域,便於分析有限域的求逆表達式,使用邏輯函數代替原先的查表運算,能夠節省門電路資源
如果使用軟件實現,可以利用有限域同構關系將 SM4 的 S盒 轉化為 AES 的 S盒,利用 AES 指令集完成 SM4 的 S盒 操作
七、求解復合域同構映射的示例代碼
(--- 2023.11.24 更新 ---)
下面給出復合域同構映射的示例python代碼,用於搜索SM4算法對應的復合域,參考論文是陳晨等人的《一種基於復合域的國密SM4算法快速軟件實現方法》。論文里有比本博客更詳細的原理介紹,流程詳見論文中的算法1.
陳晨,郭華,王闖等.一種基於復合域的國密SM4算法快速軟件實現方法[J].密碼學報,2023,10(02):289-305.
python代碼需要提前安裝好一個有關復合域運算的庫 gf2lib,通過指令 pip install gf2lib
即可安裝。下方代碼實現了Gf242復合域類以及Gf28有限域類,使用論文中的搜索算法搜索出復合條件的映射矩陣。代碼的輸出結果和論文中給出的數據完全一致
# -*- coding:utf-8 -*-
"""
需要安裝的包:gf2lib
類:Gf242
GF(2^4^2)復合域元素,為F[x]/(P(x),Q(y)),P(x) = x^2 + x + 4, Q(y) = y^4 + y^3 + 1
支持加、減、乘、冪、判等運算
(1,0)代表單位元e
類:Gf28
GF(2^8)元素,為F[x]/r(x), r(x) = x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1,即SM4復合域
支持加、減、乘、冪、判等運算
函數:gf28_items
函數:gf242_items
函數:gf242_p
函數:gf28_p
函數:cast_gf28_to_gf242
函數:cast_gf242_to_gf28
功能1:搜索GF(2^4^2)本原元
功能2:搜索指定GF(2^8)和GF(2^4^2)的映射矩陣
"""
from math import gcd
from gf2lib import gf2poly
from gf2lib.gf2matrix import GF2Matrix
from typing import Tuple, List
class Gf28:
@staticmethod
def one():
"""單位元"""
return Gf28(1)
@staticmethod
def zero():
"""零元"""
return Gf28(0)
def __init__(self, n: int):
self.n = n
def __mul__(self, other):
sm4_poly = 0b111110101 # x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1
return Gf28(gf2poly.mul(self.n, other.n, sm4_poly))
def __add__(self, other):
return Gf28(self.n ^ other.n)
def __pow__(self, power, modulo=None):
assert not (power == 0 and self.n == 0)
r = Gf28.one()
for _ in range(power):
r = r * self
return r
def __eq__(self, other):
return self.n == other.n
def __str__(self):
return str(self.n)
class Gf242:
def __init__(self, a: Tuple[int, int]):
self.a = a
@staticmethod
def gf24_mul(a: int, b: int) -> int:
gf24_poly = 0b11001 # y^4+y^3+1
return gf2poly.mul(a, b, gf24_poly)
@staticmethod
def one():
"""單位元"""
return Gf242((1, 0))
@staticmethod
def zero():
"""零元"""
return Gf242((0, 0))
def __add__(self, other):
return Gf242((self.a[0] ^ other.a[0], self.a[1] ^ other.a[1]))
def __mul__(self, other):
# P(x) = x^2 + x + 4
a0, a1 = self.a[0], self.a[1]
b0, b1 = other.a[0], other.a[1]
# c2x^2 + c1x + c0
c0 = Gf242.gf24_mul(a0, b0)
c1 = Gf242.gf24_mul(a0, b1) ^ Gf242.gf24_mul(a1, b0)
c2 = Gf242.gf24_mul(a1, b1)
# c2x^2 = c2x + 4*c2
r0 = c0 ^ Gf242.gf24_mul(c2, 4)
r1 = c1 ^ c2
return Gf242((r0, r1))
def __pow__(self, power, modulo=None):
assert not (power == 0 and self == Gf242.zero())
r = Gf242.one()
for _ in range(power):
r = r * self
return r
def __eq__(self, other):
return self.a == other.a
def __str__(self):
return str(self.a)
def gf28_items() -> List[Gf28]:
"""返回GF(2^8)所有元素"""
return [Gf28(a) for a in range(256)]
def gf242_items() -> List[Gf242]:
"""返回GF(2^4^2)中所有元素"""
return [Gf242((a0, a1)) for a0 in range(16) for a1 in range(16)]
def gf242_p(a: Gf242) -> Gf242:
"""帶入至GF(2^4^2)多項式"""
return a * a + a + Gf242((4, 0))
def gf28_p(a):
"""帶入至GF(2^8)多項式"""
# x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1
return a ** 8 + a ** 7 + a ** 6 + a ** 5 + a ** 4 + a ** 2 + a ** 0
def cast_gf28_to_gf242(a: Gf28, T: GF2Matrix) -> Gf242:
"""將GF(2^8)元素映射至GF(2^4^2)
:param a: GF(2^8)元素
:param T: 映射矩陣
:return: T*a
"""
b = T * GF2Matrix.from_int(a.n, 8)
b = b.to_int()
return Gf242((b & 0x0F, b >> 4))
def cast_gf242_to_gf28(a: Gf242, T: GF2Matrix) -> Gf28:
"""將GF(2^4^2)元素映射至GF(2^8)
:param a: GF(2^4^2)元素
:param T: 映射矩陣
:return: T*a
"""
b = T * GF2Matrix.from_int((a.a[1] << 4) + a.a[0], 8)
b = b.to_int()
return Gf28(b)
# 計算GF242本原元,得到(0,1)和(1,1),即x和1+x
print("GF242本原元:")
for g in gf242_items():
flag = True
if gf242_p(g) != Gf242.zero():
flag = False
t = g
for i in range(2, 255):
t = t * g
if t == Gf242.one():
flag = False
if flag:
print(g)
print("搜索映射矩陣:beta=", (0, 1))
result = []
# step1 選擇本原元 x
beta = Gf242((0, 1))
flag = [1 for _ in range(256)]
t = 1
while t <= 255:
# step2
beta_t = beta ** t
if gf28_p(beta_t) == Gf242.zero():
result.append(beta_t)
t = t + 1
# step3
else:
for j in range(8):
flag[(t * (2 ** j)) % 255] = 0
# step4,5
t = t + 1
while flag[t] == 0 or gcd(t, 255) > 1:
t = t + 1
if not t <= 255:
break
for beta in result:
# 打印結果
print("滿足條件的beta^t: ", beta, ", 映射矩陣 col 0-7: ", end='')
for i in range(7, -1, -1):
a = beta ** i
print((a.a[1] << 4) + a.a[0], end=', ')
print()
# 計算映射矩陣
M = GF2Matrix.from_int(0b00000001, 8) # (0, 0, ..., 1)
for i in range(1, 8):
a = beta ** i
a = (a.a[1] << 4) + a.a[0]
M = GF2Matrix.from_int(a, 8) | M
# 計算映射和逆映射矩陣
T = M
T_inv = M.inverse()
# # 測試乘法是否滿足同構,遍歷所有元素
# for i in range(256):
# for j in range(256):
# a28, b28 = Gf28(i), Gf28(j)
# a242 = cast_gf28_to_gf242(a28, T)
# b242 = cast_gf28_to_gf242(b28, T)
# assert a28 * b28 == cast_gf242_to_gf28(a242 * b242, T_inv)
# assert a28 + b28 == cast_gf242_to_gf28(a242 + b242, T_inv)
# 打印映射矩陣
for item in T.transpose().matrix:
print(item)