WG-8 轻量级序列密码算法
一、概述
WG-8(Welch-Gong-8)是一种基于 GF(2⁸) 有限域的轻量级序列密码,由 Nawaz 和 Gong 提出,适用于资源受限环境(如物联网设备)。其核心设计围绕线性反馈移位寄存器(LFSR)和 Welch-Gong 置换(WGP) 展开,每时钟周期输出 1 比特密钥流。
主要参数
| 参数 | 值 |
|---|---|
| 有限域 | GF(2⁸), p(x)=x⁸+x⁴+x³+x+1 (0x11B) |
| LFSR 级数 | 20 级(每级 8 比特) |
| 密钥长度 | 80 比特 |
| IV 长度 | 80 比特 |
| 初始化时钟 | 40 个周期 |
| 抽取因子 d | 19 |
| 输出率 | 1 比特/时钟 |
二、有限域 GF(2⁸)
2.1 域的定义
WG-8 工作在 GF(2⁸) 上,即包含 256 个元素的有限域。域中的元素可以表示为 0x00–0xFF 的字节。
不可约多项式:p(x) = x⁸ + x⁴ + x³ + x + 1 = 0x11B
本原元:ω = 0x02(即多项式 x)
2.2 加法
GF(2⁸) 中的加法即为按位异或(XOR):
def gf256_add(a: int, b: int) -> int:
return a ^ b
2.3 乘法
乘法使用标准的「移位加」算法,当左移产生进位(x⁸ 项)时,通过异或 0x1B(不可约多项式的低 8 位)进行模约减:
def gf256_mul(a: int, b: int) -> int:
result = 0
for _ in range(8):
if b & 1:
result ^= a
carry = a & 0x80
a = (a << 1) & 0xFF
if carry:
a ^= 0x1B # x⁴ + x³ + x + 1
b >>= 1
return result
原理:当 a 的最高位(x⁷)为 1 时,左移一位会产生 x⁸ 项。根据不可约多项式 x⁸ = x⁴ + x³ + x + 1,将 0x1B 异或回去完成约减。
2.4 幂运算
使用快速幂(指数平方)算法:
def gf256_pow(a: int, exp: int) -> int:
if a == 0:
return 0 if exp > 0 else 1
result = 1
base = a
while exp > 0:
if exp & 1:
result = gf256_mul(result, base)
base = gf256_mul(base, base)
exp >>= 1
return result
在 GF(2⁸) 中,对所有非零元素有 x²⁵⁵ = 1(费马小定理),但快速幂算法自然兼容大指数。
2.5 迹函数(Trace)
迹函数将 GF(2⁸) 中的元素映射到 GF(2)(即 0 或 1):
Tr(x) = x + x² + x⁴ + x⁸ + x¹⁶ + x³² + x⁶⁴ + x¹²⁸
def gf256_trace(a: int) -> int:
result = a
val = a
for _ in range(7):
val = gf256_mul(val, val) # 重复平方
result ^= val
return result & 1
由于迹函数的结果属于 GF(2),返回值仅为 0 或 1。
三、WGP-8(Welch-Gong 置换)
3.1 定义
WGP-8 使用抽取因子 d=19,定义为:
WGP-8(x) = x¹⁹
由于 gcd(19, 255) = 1,映射 x → x¹⁹ 是 GF(2⁸) 上的一个置换(双射),即 256 个输入值对应 256 个互不相同的输出值。
3.2 查表实现
为了高效实现,预先计算 256 字节的查找表(LUT):
WGP8_LUT = [gf256_pow(x, 19) for x in range(256)]
def wgp8(x: int) -> int:
return WGP8_LUT[x]
预计算只需执行一次(模块加载时),后续查询为 O(1)。
3.3 置换验证
排序后检查 LUT 是否恰好包含 [0, 1, 2, ..., 255]:
sorted_lut = sorted(WGP8_LUT)
assert sorted_lut == list(range(256)) # 确认为置换
四、WGT-8(Welch-Gong 变换)
WGT-8 将 WGP-8 的结果通过迹函数映射为 1 个比特:
WGT-8(x) = Tr(WGP-8(x)) = Tr(x¹⁹)
def wgt8(x: int) -> int:
return gf256_trace(WGP8_LUT[x])
这一比特就是最终的密钥流输出。
五、LFSR(线性反馈移位寄存器)
5.1 结构
WG-8 使用 20 级 Fibonacci 型 LFSR,每级存储 8 比特:
S₀, S₁, ..., S₁₉ 每个 Sᵢ ∈ GF(2⁸)
5.2 反馈多项式
l(x) = x²⁰ + x⁹ + x⁸ + x⁷ + x⁴ + x³ + x² + x + ω
对应的线性反馈函数:
feedback = ω·S₀ ⊕ S₁ ⊕ S₂ ⊕ S₃ ⊕ S₄ ⊕ S₇ ⊕ S₈ ⊕ S₉
注意 S₅、S₆ 及其他级不在反馈中,这是由多项式的系数决定的。
5.3 运行阶段时钟
运行阶段每时钟执行:
- 计算线性反馈值
- 状态左移:
[S₁, S₂, ..., S₁₉, feedback] - 将 WGT-8(S₁₉) 作为密钥流输出
def clock_run(self):
fb = self._linear_feedback()
self.state.pop(0)
self.state.append(fb)
# 密钥流比特
bit = wgt8(self.state[19])
5.4 初始化阶段时钟
初始化阶段的反馈包含非线性项 WGP-8(S₁₉):
def clock_init(self):
fb = self._linear_feedback() ^ wgp8(self.state[19])
self.state.pop(0)
self.state.append(fb)
这 40 个初始化时钟周期将密钥和 IV 充分混合到 LFSR 状态中。
六、密钥/IV 加载
80 比特密钥 K 和 80 比特 IV 分别表示为 10 字节数组:
K = K₀, K₁, ..., K₉ (每字节 8 比特)
IV = IV₀, IV₁, ..., IV₉
加载方式为半字节交错:
S₂ᵢ = (Kᵢ & 0x0F) << 4 | (IVᵢ & 0x0F)
S₂ᵢ₊₁ = (Kᵢ & 0xF0) | ((IVᵢ >> 4) & 0x0F)
直观理解:每个 S 字节的高半字节来自密钥,低半字节来自 IV。
示例:K₀ = 0xAB, IV₀ = 0xCD
S₀ = 0xB0 | 0x0D = 0xBD (K的低4位 || IV的低4位)
S₁ = 0xA0 | 0x0C = 0xAC (K的高4位 || IV的高4位)
七、加密与解密
7.1 密钥流生成
初始化 40 时钟后,WG-8 进入运行阶段。对于每个需要输出的比特:
clock_run()—— 更新 LFSR 状态wgt8(S[19])—— 从最后一级提取 1 比特密钥流
生成指定比特数的密钥流,打包为字节(MSB 优先):
def generate_keystream(self, num_bits):
num_bytes = (num_bits + 7) // 8
result = bytearray(num_bytes)
for i in range(num_bits):
bit = self._generate_bit() # clock_run + wgt8
byte_idx = i // 8
bit_idx = 7 - (i % 8)
result[byte_idx] |= bit << bit_idx
return bytes(result)
7.2 加密/解密
WG-8 是对称流密码,加密和解密均为 XOR 操作:
def encrypt(self, plaintext):
keystream = self.generate_keystream(len(plaintext) * 8)
return bytes(p ^ k for p, k in zip(plaintext, keystream))
def decrypt(self, ciphertext):
return self.encrypt(ciphertext) # XOR 对称性
八、完整流程图
密钥 K(80 bit) ─┐
├──→ 密钥/IV加载 ──→ LFSR (S₀...S₁₉)
IV (80 bit) ───┘ │
│
┌─────────────────┘
▼
┌──────────────────────┐
│ 初始化 (40 时钟) │
│ 反馈 ⊕ WGP-8(S₁₉) │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 运行阶段 │
│ 线性反馈 │
│ 每时钟: wgt8(S₁₉) │──→ 密钥流比特
└──────────────────────┘
│
▼
明文 ──→ ⊕ ──→ 密文
九、安全性说明
-
全零密钥/IV 弱密钥:LFSR 的固有数学性质导致全零输入产生全零状态。这是因为
ω·0 = 0且0 ⊕ 0 = 0,状态永远无法脱离全零状态。实际使用中应避免。 -
WGP-8 置换:
x¹⁹是 GF(2⁸) 上的置换,确保了输出的均匀分布。 -
迹函数的非线性:迹函数将 GF(2⁸) 压缩到 1 比特,提供了密码所需的非线性特性。
-
80 比特安全性:密钥长度为 80 比特,提供 80 比特的安全强度,适用于轻量级应用场景。

浙公网安备 33010602011771号