LED Block Cipher — 算法原理、硬件与软件实现
LED Block Cipher — 算法原理、硬件与软件实现
原著: Jian Guo, Thomas Peyrin, Axel Poschmann, Matt Robshaw(CHES 2011)
本项目: LED-64 / LED-80 / LED-128 的 Verilog HDL 实现与 Python 参考实现,含完整加解密验证。
**开源链接:**https://github.com/inwpu/LED-Block-Cipher/LED Block Cipher
一、背景与算法参数
随着 RFID 标签、无线传感器和嵌入式控制器的大规模普及,如何在极端受限的硬件资源下提供密码保护成为一个现实工程问题。这类设备的可用门电路往往不足 2000 GE,而传统 AES 的最小实现已需要约 3400 GE,其密钥扩展算法本身就占去相当比例。
LED(Light Encryption Device)的核心设计取舍是:完全取消密钥扩展算法,让原始密钥以周期性复用的方式直接参与每一步的密钥异或。这不仅将硬件面积压缩到 966 GE(LED-64),更带来了关键的安全分析优势——由于轮函数结构高度规整,可以在单密钥和相关密钥两种攻击模型下都推导出精确的安全界。
轮函数的设计延续 AES 的 SPN(置换-替换网络)框架,以 PRESENT 密码中经过广泛验证的 S 盒作为非线性层,并采用专为串行硬件实现优化的 MixColumnsSerial 结构。
下表列出三个变种的参数对比。“步”(step)是 LED 特有的结构单元,每步包含 4 轮内部变换和 1 次密钥注入,是安全性证明的基本分析单位。密钥注入次数 = 步数 + 1,因为加密开始前有一次初始注入,每步结束后有一次注入。
| 版本 | 块大小 | 密钥长度 | 步数 s s s | 总轮数 | 密钥注入次数 | 运算域 | 硬件面积(可变密钥) |
|---|---|---|---|---|---|---|---|
| LED-64 | 64 bit | 64 bit | 8 | 32 | 9 | GF ( 2 4 ) \text{GF}(2^4) GF(24) | 966 GE |
| LED-80 | 64 bit | 80 bit | 12 | 48 | 13 | GF ( 2 4 ) \text{GF}(2^4) GF(24) | 1,040 GE(估算) |
| LED-128 | 64 bit | 128 bit | 12 | 48 | 13 | GF ( 2 4 ) \text{GF}(2^4) GF(24) | 1,265 GE |
面积数据来自原论文 Table 2(Flexible Keys 列,UMC 0.18 μm 工艺)。LED-80 标注估算值(*)。LED-64 若使用硬连线密钥可降至 688 GE,LED-128 可降至 700 GE。
本项目基于官方规范(ePrint 2012/600)及 Jian Guo 于 2014 年公开的字节级参考实现 led-bytes.c,完成了:
- Verilog HDL:LED-64、LED-80、LED-128 各提供时序逻辑(每时钟周期完成一轮)和组合逻辑(单周期)两种架构,均支持加解密;
- Python:
led.py单文件实现三个变种的完整加解密,90 项测试全部通过; - 交叉验证:所有实现的输出均与官方 C 参考逐字节比对一致。
二、算法结构与轮操作
2.1 状态矩阵
LED 将 64 位数据块解释为一个 4 行 × 4 列的 nibble 矩阵,每个格子存储一个 GF ( 2 4 ) \text{GF}(2^4) GF(24) 元素(4 比特)。与 AES 按列优先填充不同,LED 按行优先、高位优先的顺序将明文字节填入,这是面向硬件串行实现的设计选择——串行电路每次只处理一个 nibble,行优先与高位先出的比特流顺序一致。

格子 a [ i ] [ j ] a[i][j] a[i][j] 对应 64 位字的位域:
a [ i ] [ j ] ⟷ bits [ 63 − 4 ( 4 i + j ) : 60 − 4 ( 4 i + j ) ] a[i][j] \;\longleftrightarrow\; \text{bits}\bigl[63-4(4i+j)\;:\;60-4(4i+j)\bigr] a[i][j]⟷bits[63−4(4i+j):60−4(4i+j)]
例如 a [ 0 ] [ 0 ] a[0][0] a[0][0] 取最高 4 位(bits[63:60]), a [ 3 ] [ 3 ] a[3][3] a[3][3] 取最低 4 位(bits[3:0])。子密钥 SK n \text{SK}^n SKn 以完全相同的 4 × 4 4\times4 4×4 格式组织,其格位 ( i , j ) (i,j) (i,j) 的值由密钥 nibble 公式 k n [ ( 4 i + j + n × 16 ) m o d ( key_bits / 4 ) ] kn[(4i+j+n\times16)\bmod(\text{key\_bits}/4)] kn[(4i+j+n×16)mod(key_bits/4)] 确定(详见第三章)。
2.2 加密整体架构
加密过程由 s s s 个**步(step)**串联而成,每步开始前先对状态 XOR 一个子密钥,随后执行 4 轮内部变换;所有步结束后再做最后一次密钥注入(收尾 XOR)。图 2 展示了这一"密钥—步—密钥—步—…—密钥"的交替结构。

图中每个 ⊕ \oplus ⊕ 节点表示一次子密钥 XOR(AddRoundKey)。 SK 0 \text{SK}^0 SK0 注入 step 0 之前, SK 1 \text{SK}^1 SK1 注入 step 0 之后(step 1 之前),以此类推; SK s \text{SK}^s SKs 是最后一次注入(step s − 1 s-1 s−1 之后),也称"output whitening"。没有这次最终 XOR,最后一个 MixColumnsSerial 的输出就直接暴露,攻击者可以跳过最后一轮分析整个结构,因此收尾 XOR 是构造完整性的必要组成。
每步(step)由 4 轮(round)顺序执行,每轮依次完成以下 4 个操作(图 3):

四个操作的排列顺序遵循 SPN 设计原则:AddConstants 在 SubCells 之前注入,避免 S 盒输入具有可预测的对称性;SubCells 提供非线性(混淆);ShiftRows + MixColumnsSerial 共同提供扩散(雪崩)。理论上,经过 4 轮(一步)之后,每个输出 nibble 依赖所有 16 个输入 nibble(全扩散),这是 LED 步结构作为安全分析基本单元的原因。
2.3 AddConstants — 轮常数注入
每轮注入的作用有两个:一是在每轮引入轮差异打破状态的对称性,防止出现固定点或滑动攻击;二是将密钥长度信息编码进状态,使 LED-64 / LED-80 / LED-128 三个变种即使面对相同的明文和密钥也产生完全不同的密文(抵御跨变种的通用攻击)。
每轮使用一个 6 位常数 RC [ r ] \text{RC}[r] RC[r],由 6 位仿射 LFSR 生成,递推规则为:
r c 0 ′ = r c 5 ⊕ r c 4 ⊕ 1 \mathrm{rc}_{0}' = \mathrm{rc}_5 \oplus \mathrm{rc}_4 \oplus 1 rc0′=rc5⊕rc4⊕1
即寄存器左移一位,新的最低位由旧 r c 5 \mathrm{rc}_5 rc5、 r c 4 \mathrm{rc}_4 rc4 和常数 1 异或得到。LFSR 从全零初始化,每轮使用前更新一次,故 RC [ 0 ] = 0x01 \text{RC}[0]=\texttt{0x01} RC[0]=0x01。序列前 8 项验证如下:
初始:000001 = 0x01
步1:新b0 = 0⊕0⊕1=1 → 000011 = 0x03 ✓
步2:新b0 = 0⊕0⊕1=1 → 000111 = 0x07 ✓
步3:新b0 = 0⊕0⊕1=1 → 001111 = 0x0F ✓
步4:新b0 = 0⊕0⊕1=1 → 011111 = 0x1F ✓
步5:新b0 = 0⊕1⊕1=0 → 111110 = 0x3E ✓
步6:新b0 = 1⊕1⊕1=1 → 111101 = 0x3D ✓
步7:新b0 = 1⊕1⊕1=1 → 111011 = 0x3B ✓
全部 48 个 RC 值(LED-80 / LED-128 使用全部 48 个,LED-64 使用前 32 个):
RC[0..47] = {
01 03 07 0F 1F 3E 3D 3B 37 2F 1E 3C 39 33 27 0E
1D 3A 35 2B 16 2C 18 30 21 02 05 0B 17 2E 1C 38
31 23 06 0D 1B 36 2D 1A 34 29 12 24 08 11 22 04
}
注入只作用于状态矩阵的第 0 列和第 1 列,第 2、3 列完全不变。Col 0 注入"行索引与密钥长度编码的组合"固定常数(所有轮相同),Col 1 注入 RC [ r ] \text{RC}[r] RC[r] 的高 3 位和低 3 位(每轮不同):
- Col 0:设 $ks_hi = (key_bits >> 4) & 0xF
,ks_lo = key_bits & 0xF`,则行 i i i 注入 i ⊕ ks_hi i \oplus \text{ks\_hi} i⊕ks_hi( i = 0 , 1 i=0,1 i=0,1)或 i ⊕ ks_lo i \oplus \text{ks\_lo} i⊕ks_lo( i = 2 , 3 i=2,3 i=2,3)。该值在同一 LED 变种内的所有轮中固定不变,在不同变种间取值不同,以此让三个变种产生不同的常数域。 - Col 1:
RC_hi = (RC[r] >> 3) & 0x7(RC 的高 3 位)注入偶数行(行 0、行 2);RC_lo = RC[r] & 0x7(RC 的低 3 位)注入奇数行(行 1、行 3)。每轮 RC [ r ] \text{RC}[r] RC[r] 不同,确保每轮的注入图案唯一。

三个变种在 Col 0 注入的固定值如下表。注意 ( 2 , 0 ) (2,0) (2,0) 和 ( 3 , 0 ) (3,0) (3,0) 对所有变种均为 2 和 3:这是因为 64、80、128 这三个数值的低 4 位( ks_lo \text{ks\_lo} ks_lo)均为 0,导致 2 ⊕ ks_lo = 2 2\oplus\text{ks\_lo}=2 2⊕ks_lo=2、 3 ⊕ ks_lo = 3 3\oplus\text{ks\_lo}=3 3⊕ks_lo=3。
| 格位 (row, col) | LED-64 ( key_bits = 0x40 \text{key\_bits}=\texttt{0x40} key_bits=0x40) | LED-80 ( key_bits = 0x50 \text{key\_bits}=\texttt{0x50} key_bits=0x50) | LED-128 ( key_bits = 0x80 \text{key\_bits}=\texttt{0x80} key_bits=0x80) |
|---|---|---|---|
| (0, 0) | ks_hi = 4 \text{ks\_hi} = 4 ks_hi=4 | ks_hi = 5 \text{ks\_hi} = 5 ks_hi=5 | ks_hi = 8 \text{ks\_hi} = 8 ks_hi=8 |
| (1, 0) | 1 ⊕ ks_hi = 5 1\oplus\text{ks\_hi} = 5 1⊕ks_hi=5 | 1 ⊕ ks_hi = 4 1\oplus\text{ks\_hi} = 4 1⊕ks_hi=4 | 1 ⊕ ks_hi = 9 1\oplus\text{ks\_hi} = 9 1⊕ks_hi=9 |
| (2, 0) | 2 ⊕ ks_lo = 2 2\oplus\text{ks\_lo} = 2 2⊕ks_lo=2 | 2 ⊕ ks_lo = 2 2\oplus\text{ks\_lo} = 2 2⊕ks_lo=2 | 2 ⊕ ks_lo = 2 2\oplus\text{ks\_lo} = 2 2⊕ks_lo=2 |
| (3, 0) | 3 ⊕ ks_lo = 3 3\oplus\text{ks\_lo} = 3 3⊕ks_lo=3 | 3 ⊕ ks_lo = 3 3\oplus\text{ks\_lo} = 3 3⊕ks_lo=3 | 3 ⊕ ks_lo = 3 3\oplus\text{ks\_lo} = 3 3⊕ks_lo=3 |
2.4 SubCells — 非线性替换
SubCells 对状态矩阵中的全部 16 个 nibble 独立并行地做 S 盒查表替换,是整个轮函数中唯一的非线性操作(混淆层)。LED 复用了 PRESENT 密码的 S 盒,该 S 盒基于 GF ( 2 4 ) \text{GF}(2^4) GF(24) 上的仿射变换构造,最大差分概率为 2 − 2 2^{-2} 2−2,最大线性近似概率为 2 − 2 2^{-2} 2−2(均为 4 位 S 盒的理论最优值之一)。
正向 S 盒(加密用, S [ x ] S[x] S[x]):
| x x x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S [ x ] S[x] S[x] | C | 5 | 6 | B | 9 | 0 | A | D | 3 | E | F | 8 | 4 | 7 | 1 | 2 |
逆向 S − 1 S^{-1} S−1 盒(解密用,查逆映射):
| x x x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S − 1 [ x ] S^{-1}[x] S−1[x] | 5 | E | F | 8 | C | 1 | 2 | D | B | 4 | 6 | 3 | 0 | 7 | 9 | A |
可以验证 S − 1 [ S [ x ] ] = x S^{-1}[S[x]] = x S−1[S[x]]=x,例如 S [ 0 ] = C S[0]=\texttt{C} S[0]=C, S − 1 [ C ] = 0 S^{-1}[\texttt{C}]=0 S−1[C]=0 ✓; S [ 5 ] = 0 S[5]=0 S[5]=0, S − 1 [ 0 ] = 5 S^{-1}[0]=5 S−1[0]=5 ✓。SubCells 在解密时直接替换为查 S − 1 S^{-1} S−1 盒,操作结构完全对称,硬件实现可共用查表逻辑。
2.5 ShiftRows — 行移位
ShiftRows 将第 i i i 行向左循环移动 i i i 个 nibble( i = 0 , 1 , 2 , 3 i = 0,1,2,3 i=0,1,2,3),第 0 行不动。该操作本身不增加混淆,其目的是为后续的 MixColumnsSerial 准备跨行的扩散条件:ShiftRows 之后,同一列中来自不同原始行的 nibble 被重新排布,MixColumnsSerial 对列做矩阵乘法时就能将多个行的信息混合,实现全状态的雪崩效应。

ShiftRows 的等价公式为:
a ′ [ r ] [ c ] = a [ r ] [ ( c + r ) m o d 4 ] (行 r 左移 r 位) a'[r][c] = a[r][(c+r) \bmod 4] \qquad \text{(行 } r \text{ 左移 } r \text{ 位)} a′[r][c]=a[r][(c+r)mod4](行 r 左移 r 位)
解密逆操作 InvShiftRows:
a [ r ] [ c ] = a ′ [ r ] [ ( c − r + 4 ) m o d 4 ] (行 r 右移 r 位) a[r][c] = a'[r][(c-r+4) \bmod 4] \qquad \text{(行 } r \text{ 右移 } r \text{ 位)} a[r][c]=a′[r][(c−r+4)mod4](行 r 右移 r 位)
以 Row 1 为例:原来位于 ( 1 , 0 ) (1,0) (1,0) 的元素 a [ 1 ] [ 0 ] a[1][0] a[1][0] 左移 1 位后落到列位置 3,即 a ′ [ 1 ] [ 3 ] = a [ 1 ] [ 0 ] a'[1][3] = a[1][0] a′[1][3]=a[1][0]。MixColumnsSerial 作用于列 3 时,会将来自行 0、行 1(移位后)、行 2(移位后)、行 3(移位后)的四个元素全部混合,这正是跨行扩散的机制。
2.6 MixColumnsSerial 与 GF ( 2 4 ) \text{GF}(2^4) GF(24) 域运算
MixColumnsSerial 对状态矩阵的每一列独立执行一次 4 × 4 4\times4 4×4 矩阵乘法:将该列的 4 个 nibble 视为 GF ( 2 4 ) \text{GF}(2^4) GF(24) 上的列向量,乘以 MDS 矩阵 M M M,结果写回该列。图 6 展示了这一过程。
矩阵 M M M 与串行步骤矩阵 A A A 的关系(原论文式 ( A ) 4 = M (A)^4 = M (A)4=M):
A = ( 0 1 0 0 0 0 1 0 0 0 0 1 4 1 2 2 ) , M = A 4 = ( 4 1 2 2 8 6 5 6 B E A 9 2 2 F B ) A = \begin{pmatrix} 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 4 & 1 & 2 & 2 \end{pmatrix}, \qquad M = A^4 = \begin{pmatrix} 4 & 1 & 2 & 2 \\ 8 & 6 & 5 & 6 \\ \mathrm{B} & \mathrm{E} & \mathrm{A} & 9 \\ 2 & 2 & \mathrm{F} & \mathrm{B} \end{pmatrix} A= 0004100101020012 ,M=A4= 48B216E225AF269B
(所有元素均在 GF ( 2 4 ) \text{GF}(2^4) GF(24) 中,以十六进制表示)
矩阵 A A A 对应单次串行移位混合步骤——硬件上每拍将当前列向量 v \mathbf{v} v 更新为 A v A\mathbf{v} Av,连续执行 4 拍即完成 M a M\mathbf{a} Ma,这是 MixColumnsSerial 命名的由来,也使其在逐 nibble 串行硬件中极易实现。展开后的矩阵方程为:
b 0 = 4 ⋅ a 0 ⊕ 1 ⋅ a 1 ⊕ 2 ⋅ a 2 ⊕ 2 ⋅ a 3 b 1 = 8 ⋅ a 0 ⊕ 6 ⋅ a 1 ⊕ 5 ⋅ a 2 ⊕ 6 ⋅ a 3 b 2 = B ⋅ a 0 ⊕ E ⋅ a 1 ⊕ A ⋅ a 2 ⊕ 9 ⋅ a 3 b 3 = 2 ⋅ a 0 ⊕ 2 ⋅ a 1 ⊕ F ⋅ a 2 ⊕ B ⋅ a 3 \begin{aligned} b_0 &= 4\cdot a_0 \oplus 1\cdot a_1 \oplus 2\cdot a_2 \oplus 2\cdot a_3 \\ b_1 &= 8\cdot a_0 \oplus 6\cdot a_1 \oplus 5\cdot a_2 \oplus 6\cdot a_3 \\ b_2 &= \mathrm{B}\cdot a_0 \oplus \mathrm{E}\cdot a_1 \oplus \mathrm{A}\cdot a_2 \oplus 9\cdot a_3 \\ b_3 &= 2\cdot a_0 \oplus 2\cdot a_1 \oplus \mathrm{F}\cdot a_2 \oplus \mathrm{B}\cdot a_3 \end{aligned} b0b1b2b3=4⋅a0⊕1⋅a1⊕2⋅a2⊕2⋅a3=8⋅a0⊕6⋅a1⊕5⋅a2⊕6⋅a3=B⋅a0⊕E⋅a1⊕A⋅a2⊕9⋅a3=2⋅a0⊕2⋅a1⊕F⋅a2⊕B⋅a3
M M M 是一个 MDS(最大距离可分)矩阵,分支数(Branch Number) = 5 = 5 =5。分支数的含义:对于任意非零输入差分向量,输入与输出中被激活(非零差分)的 nibble 数之和至少为 5。换言之,若输入只有 1 个 nibble 发生变化,输出中至少 4 个 nibble 会发生变化,实现强扩散。
GF ( 2 4 ) \text{GF}(2^4) GF(24) 域运算:矩阵系数的乘法运算在有限域 GF ( 2 4 ) \text{GF}(2^4) GF(24) 中进行,该域由不可约多项式 p ( x ) = x 4 + x + 1 p(x) = x^4 + x + 1 p(x)=x4+x+1 定义。 GF ( 2 4 ) \text{GF}(2^4) GF(24) 加法即按位异或( ⊕ \oplus ⊕),乘法是多项式乘法后模 p ( x ) p(x) p(x) 归约,因此 x 4 ≡ x + 1 ( m o d p ( x ) ) x^4 \equiv x+1 \pmod{p(x)} x4≡x+1(modp(x))。实现上采用"移位-累加"循环:
gf4_mul(a, b):
r ← 0
重复 4 次:
若 b[0] = 1 :r ← r ⊕ a ← 当前最低位为 1 时累加
b ← b >> 1
若 a[3] = 1 :a ← (a << 1) ⊕ 0x3 ← 溢出:x⁴ ≡ x+1,XOR 归约多项式余项 (x+1) = 0x3
否则 :a ← a << 1
返回 r(取低4位)
0x3 对应多项式 x + 1 x+1 x+1,即 p ( x ) = x 4 + x + 1 p(x)=x^4+x+1 p(x)=x4+x+1 去掉最高次 x 4 x^4 x4 后的余项。每次 a a a 溢出( a [ 3 ] = 1 a[3]=1 a[3]=1),左移后产生 x 4 x^4 x4,按 x 4 ≡ x + 1 x^4 \equiv x+1 x4≡x+1 替换,相当于 XOR 0x3 并丢弃溢出位。
三、密钥方案与解密
3.1 统一密钥取用公式
LED 没有独立的密钥扩展算法。第 n n n 步的子密钥 SK n \text{SK}^n SKn 的格位 ( i , j ) (i,j) (i,j) 处的 nibble,直接按下式从原始密钥取出:
SK n [ i ] [ j ] = k n [ ( 4 i + j + 16 n ) m o d key_bits 4 ] \text{SK}^n[i][j] = kn\!\left[(4i + j + 16n) \bmod \frac{\text{key\_bits}}{4}\right] SKn[i][j]=kn[(4i+j+16n)mod4key_bits]
其中 k n [ ] kn[\,] kn[] 是原始密钥按高位优先展开的 nibble 数组(共 key_bits / 4 \text{key\_bits}/4 key_bits/4 个元素)。 ( 16 n ) m o d ( key_bits / 4 ) (16n) \bmod (\text{key\_bits}/4) (16n)mod(key_bits/4) 给出了第 n n n 步的"起始偏移",三种密钥长度对应不同的取用规律:
| 变种 | key nibbles | 偏移公式 | 规律 |
|---|---|---|---|
| LED-64 | 16 | ( 16 n ) m o d 16 = 0 (16n) \bmod 16 = 0 (16n)mod16=0 | 所有步偏移为 0,子密钥永远等于原始密钥 |
| LED-80 | 20 | ( 16 n ) m o d 20 (16n) \bmod 20 (16n)mod20 | 每 5 步一周期,窗口在 20 个 nibble 上循环滑动 |
| LED-128 | 32 | ( 16 n ) m o d 32 (16n) \bmod 32 (16n)mod32 | 0 与 16 严格交替,对应高/低 64 位两个子密钥 |
3.2 LED-64 密钥方案
密钥共 16 个 nibble。步偏移 ( 16 n ) m o d 16 = 0 (16n) \bmod 16 = 0 (16n)mod16=0 对所有步恒成立,因此全部 9 个子密钥( SK 0 … SK 8 \text{SK}^0\ldots\text{SK}^8 SK0…SK8)均等于原始密钥 K K K 本身。

子密钥完全相同表面上看似削弱了安全性,但 LED 的安全论证依赖的是轮函数本身的扩散强度:8 步(32 轮)的 AC+SC+SR+MCS 链提供了足够的混淆和扩散,即使攻击者知道密钥被重复使用,也无法利用这一规律在限定计算量内进行区分攻击。原论文证明,任意差分路径在 LED-64 单密钥场景下至少激活 200 个活跃 S 盒,差分路径概率上界 2 − 400 2^{-400} 2−400,这也是 LED-64 需要 8 步而非更少步数的原因。
3.3 LED-80 密钥方案
密钥共 20 个 nibble。步偏移序列 { ( 16 n ) m o d 20 } = { 0 , 16 , 12 , 8 , 4 , 0 , 16 , … } \{(16n) \bmod 20\} = \{0, 16, 12, 8, 4, 0, 16, \ldots\} {(16n)mod20}={0,16,12,8,4,0,16,…},每 5 步一周期,子密钥窗口在 20 个 nibble 上循环滑动。LED-80 的 12 步 + 1 次末尾注入共 13 个子密钥( SK 0 … SK 12 \text{SK}^0\ldots\text{SK}^{12} SK0…SK12),在 5 种取法( P 0 … P 4 P_0\ldots P_4 P0…P4)中完成 2 个完整周期后再取前 3 种。

每种取法( P 0 … P 4 P_0\ldots P_4 P0…P4)是密钥 20 个 nibble 的一个长度为 16 的环形窗口,五个窗口覆盖不同的起始位置,相邻取法之间偏移 4 个 nibble。这种滑动设计引入了有限的子密钥多样性,而不需要任何密钥扩展电路。
3.4 LED-128 密钥方案
密钥共 32 个 nibble。步偏移 ( 16 n ) m o d 32 (16n) \bmod 32 (16n)mod32 在 0 0 0(偶数步)和 16 16 16(奇数步)之间严格交替,自然产生两个固定子密钥: K 0 K^0 K0(nibbles k [ 0 … 15 ] k[0\ldots15] k[0…15],对应 key [ 127 : 64 ] \text{key}[127:64] key[127:64])和 K 1 K^1 K1(nibbles k [ 16 … 31 ] k[16\ldots31] k[16…31],对应 key [ 63 : 0 ] \text{key}[63:0] key[63:0])。

LED-128 的安全设计意图:由于初始注入( SK 0 \text{SK}^0 SK0)和末尾注入( SK 12 \text{SK}^{12} SK12)均使用 K 0 K^0 K0,在相关密钥攻击场景下,即使攻击者完全控制 K 0 K^0 K0,他也只能"剥离"头尾共两次 K 0 K^0 K0 注入。中间仍有 11 次注入( SK 1 … SK 11 \text{SK}^1\ldots\text{SK}^{11} SK1…SK11)完整地交替引入 K 0 K^0 K0 和 K 1 K^1 K1,相关密钥差分路径无法贯穿整个密码,原论文证明相关密钥场景下至少激活 150 个活跃 S 盒,差分路径概率上界 2 − 300 2^{-300} 2−300。
3.5 解密流程
解密是加密的严格逆过程:使用完全相同的密钥方案,但步索引逆序,四个轮操作各自替换为其逆。

对比加密(图 2)与解密(图 10)可以看出:两者的密钥注入位置完全对称。加密中 SK n \text{SK}^n SKn 注入在 step n n n 之前;解密中 SK n \text{SK}^n SKn 注入在 inv-step n n n 之后(即处理完 inv-step n n n 后才 XOR SK n \text{SK}^n SKn,然后进入 inv-step n − 1 n-1 n−1)。这使得每次 XOR 都精确地撤销了加密时对应的 XOR。

解密轮函数顺序 InvMCS → InvSR → InvSC → AC 是加密顺序 AC → SC → SR → MCS 的严格逆。由于 XOR(AddConstants)是自逆运算( a ⊕ c ⊕ c = a a \oplus c \oplus c = a a⊕c⊕c=a),解密时不需要单独的"逆 AddConstants"——只需用相同 RC [ r ] \text{RC}[r] RC[r] 再 XOR 一次即可撤销。需要注意的是,解密时 AddConstants 放在最后(对应加密时它在最前),轮编号从大到小递减(最后一轮先处理)。
四、实现与验证
本项目的文件结构如下:
LED/
├── README.md ← 本文件
├── 2012-600.pdf ← 官方论文(Guo et al., CHES 2011)
├── led-cipher.pdf / led-full.pdf ← 规范文档
│
├── Reference-LED-ePrint/ ← 官方 C 参考实现
│ ├── led-bytes.c ← 核心加密函数(Jian Guo, 2014)
│ ├── led-bytes.h
│ ├── gen_vectors.c
│ └── LED2-byte-TestVectors.txt ← 官方规范测试向量(27 条)
│
├── LED-v2-opt/ ← 官方优化版 C 实现
│
├── python/ ← Python 参考实现
│ ├── led.py ← LED-64/80/128 加解密核心
│ ├── example.py ← 使用示例
│ ├── test_led.py ← 90 项测试(Phase 1–4)
│ └── README.md
│
└── verilog/
├── LED64/
│ ├── led64_seq.v ← 时序逻辑(32 周期/块,enc/dec)
│ ├── led64_comb.v ← 组合逻辑(单周期,enc/dec)
│ ├── led64_*_tb.v ← 各类测试台
│ └── README_LED64.md
├── LED80/
│ ├── led80_seq.v / led80_comb.v
│ ├── led80_*_tb.v
│ └── README_LED80.md
└── LED128/
├── led128_seq.v / led128_comb.v
├── led128_*_tb.v
└── README_LED128.md
4.1 Verilog 实现
每个变种提供两种架构:
时序逻辑(*_seq.v):每个时钟周期完成一轮的全部四个操作。加密方向(AC→SC→SR→MCS)和解密方向(InvMCS→InvSR→InvSC→AC)的组合逻辑链同时展开,由启动时锁存的 dec_mode 信号在每拍选择写回哪条路径。每 4 拍(round_cnt[1:0] == 2'b11)触发一次子密钥 XOR,完成一个 step。
注:原论文的串行硬件实现(每拍处理 4 bits)每轮需要 39 个时钟周期,LED-64 总延迟 1,248 周期,LED-80/128 为 1,872 周期。本项目 Verilog 实现每拍完成整轮并行计算,LED-64 仅需 32 个时钟周期,LED-80/128 需 48 个时钟周期,属于不同的实现权衡。

状态机中密钥注入公式的说明:加密时每完成 4 轮注入 SK ⌊ round_cnt / 4 ⌋ + 1 \text{SK}^{\lfloor\text{round\_cnt}/4\rfloor+1} SK⌊round_cnt/4⌋+1,从 SK 1 \text{SK}^1 SK1 递增到 SK s \text{SK}^s SKs;解密时每完成 4 轮注入 SK s − 1 − ⌊ round_cnt / 4 ⌋ \text{SK}^{s-1-\lfloor\text{round\_cnt}/4\rfloor} SKs−1−⌊round_cnt/4⌋,从 SK s − 1 \text{SK}^{s-1} SKs−1 递减到 SK 0 \text{SK}^0 SK0。两者都利用同一套密钥取用公式,只是索引方向相反。
组合逻辑(*_comb.v):在 always @(*) 块中用 integer 循环变量展开全部轮次,综合工具将中间 reg 型变量识别为组合逻辑线网,实现单周期完成全部变换:
always @(*) begin : comb_body
integer r;
reg [63:0] st;
st = encrypt ? (plaintext ^ subkey(0)) : (ciphertext ^ subkey(steps));
for (r = 0; r < ROUNDS; r = r + 1) begin
if (encrypt) begin
st = ac_f(st, r); st = sc_f(st);
st = sr_f(st); st = mc_f(st);
if (r[1:0] == 2'b11) st = st ^ subkey(r/4 + 1);
end else begin
st = imc_f(st); st = isr_f(st);
st = isc_f(st); st = iac_f(st, ROUNDS-1-r);
if (r[1:0] == 2'b11) st = st ^ subkey(steps-1 - r/4);
end
end
result = st;
end
解密路径中 iac_f(st, ROUNDS-1-r) 将轮编号逆向传入 AddConstants,使 RC 序列从 RC [ RN − 1 ] \text{RC}[\text{RN}-1] RC[RN−1] 倒序到 RC [ 0 ] \text{RC}[0] RC[0],精确对应加密时各轮所注入的常数。
4.2 Python 实现
led.py 以清晰可读为目标,直接对应算法规范。核心是统一的密钥取用公式,单函数兼容三种密钥长度:
def add_key(state, key_nibbles, step, key_bits):
n = key_bits // 4 # 总 nibble 数:16 / 20 / 32
for i in range(4):
for j in range(4):
idx = (4*i + j + step*16) % n # 环形取 nibble
state[i][j] ^= key_nibbles[idx]
- n = 16 n=16 n=16(LED-64): ( 16 ⋅ step ) m o d 16 = 0 (16\cdot\text{step}) \bmod 16 = 0 (16⋅step)mod16=0,所有步偏移为 0,始终取同一组 16 个 nibble
- n = 20 n=20 n=20(LED-80):5 步一周期, { 0 , 16 , 12 , 8 , 4 } \{0,16,12,8,4\} {0,16,12,8,4} 循环
- n = 32 n=32 n=32(LED-128): ( 16 ⋅ step ) m o d 32 (16\cdot\text{step}) \bmod 32 (16⋅step)mod32 在 0 / 16 0/16 0/16 严格交替
4.3 验证方案
本项目采用三层交叉验证:官方 C 实现生成期望密文 → 所有实现的输出与期望密文逐字节比对。图 13 展示了完整的验证链路。

图中"期望密文"来自官方 led-bytes.c(Jian Guo 2014 年发布的参考实现),它是唯一的可信基准。Verilog 测试台将期望密文硬编码为 expected 参数,仿真结束后逐 bit 比对;Python test_led.py 同时检验加密(Phase 1/4)、解密还原(Phase 2)和往返一致性(Phase 3)。所有测试均已通过:
| 实现 | 测试项数 | 覆盖内容 | 结果 |
|---|---|---|---|
| Python LED-64/80/128 | 90 | 规范向量 enc/dec、自选明文、往返测试 | 全 PASS |
| Verilog LED-64 时序/组合 | 各 18 | 9 组规范向量 enc + dec | 全 PASS |
| Verilog LED-80 时序/组合 | 各 18 | 9 组规范向量 enc + dec | 全 PASS |
| Verilog LED-128 时序/组合 | 各 18 | 9 组规范向量 enc + dec | 全 PASS |
| C 交叉验证(3 变种) | 各 13 | 9 组规范 + 4 组自选,与官方 C 逐字节比对 | 全 PASS |
五、参考文献
原始论文:
Jian Guo, Thomas Peyrin, Axel Poschmann, and Matt Robshaw.
“The LED Block Cipher.”
In Cryptographic Hardware and Embedded Systems – CHES 2011,
Lecture Notes in Computer Science, vol. 6917, pp. 326–341.
Springer, Berlin, Heidelberg, 2011.
ePrint: https://eprint.iacr.org/2012/600.pdf(链接有效)
官方参考实现:
Jian Guo.
LED Reference Implementation (led-bytes.c), 2014.
Copyright © 2014 Jian Guo. All rights reserved.
注:论文作者页面:https://sites.google.com/site/ledblockcipher/
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)