0%

1 预备知识

1.1 困难问题

ECDL 问题
椭圆曲线上的循环加法群 GG 由无穷远点 OO 和曲线 EE 上的其他点组成,PPqq 为生成元和阶。给定群 GG 中已知两个点 PPQQ,且 Q=xPQ = xP,其中 xZqx \in \mathbb{Z}_q^*。敌手 AA 在 PPT 时间内计算 xx 是困难的,即解决 ECDL 问题的概率 ϵ\epsilon 是可忽略的。
* 注:然而,本文方案实际并未使用到椭圆曲线,故基于的困难问题应为离散对数问题
RSA 问题
一个 PPT 敌手 AA 尝试计算一个整数 uu,使得 uec(modn)u^e \equiv c \pmod{n},其中 (n,e,c)(n,e,c) 是已知的,且 nn 是两个不同奇素数 ppqq 的乘积,满足最大公约数 gcd(e,(p1)(q1))=1\gcd(e, (p - 1)(q - 1)) = 1AA 解决 RSA 问题的概率 ϵRSAA=Pr[A(n,e,c)u]\epsilon_{\text{RSA}}^A = \Pr[A(n, e, c) \to u] 是可忽略的。
变种 RSA 问题
一个 PPT 敌手 AA 尝试计算两个整数 (w,u)(w,u),使得 ueawz(modn)u^e \equiv a w^z \pmod{n}。其中 (n,e,a,z)(n, e, a, z) 是已知的,且 nn 是两个不同奇素数 ppqq 的乘积,满足 gcd(e,(p1)(q1))=1\gcd(e, (p - 1)(q - 1)) = 1AA 解决 VRSA 问题的概率 ϵVRSAA=Pr[A(n,e,a,z)(w,u)]\epsilon_{\text{VRSA}}^A = \Pr[A(n, e, a, z) \to (w, u)] 是可忽略的。

1.2 Shamir 秘密共享

Shamir 秘密共享方案通过将一个秘密值 ss 拆分为 nn 个片段 s1,...,sns_1, ..., s_n​,每位参与者 P1,...,PnP_1, ..., P_n 分别持有一个片段。核心原理是:当群体中至少有 tt 个成员时,能够恢复秘密值 ss;否则无法恢复。

  • 秘密分发

    • 随机选择 sZqs \in Z_q^* 作为共享的秘密值,随机选取一个满足 f(0)=sf(0) = st1t-1 次多项式 f(x)=s+j=1t1ajxj mod qf(x)= s + \sum_{j=1}^{t-1} a_jx^j \ mod \ q
    • 随机选择 αiZq\alpha_i \in Z_q^*​,计算 f(αi)=sif(\alpha_i) = s_i,其中 i{1,...,n}i \in \{1, ..., n\}
    • 将第 ii 个片段 {αi,f(αi)}\{\alpha_i, f(\alpha_i) \} 分发给对应的参与者 PiP_i
  • 秘密恢复:对包含至少 tt 个参与者的群体 SS,这些参与者通过以下等式恢复秘密值 s=f(αi)s=f(\alpha_i),其中 Δαi,S(x)\Delta_{\alpha_i,S}(x) 为拉格朗日基本多项式:

    f(x)=PiSΔαi,S(x)f(αi)f(x) = \sum_{P_i \in S} \Delta_{\alpha_i,S}(x) f(\alpha_i)

    Δαi,S(x)=PkS,kixαkαiαkmodq\Delta_{\alpha_i,S}(x) = \prod_{P_k \in S, k \neq i} \frac{x - \alpha_k}{\alpha_i - \alpha_k} \mod q

1.3 汉明距离

汉明距离(Hamming Distance)最早用于数据传输纠错码,是两个字符串或向量中对应位置位不同的数目。给定两个等长的字符串或向量 x=(x1,x2,,xn)x = (x_1, x_2, \dots, x_n)y=(y1,y2,,yn)y = (y_1, y_2, \dots, y_n),其汉明距离 dH(x,y)d_H(x, y) 定义为:

dH(x,y)=i=1nδ(xi,yi), 其中 δ(xi,yi)={1 当 xiyi0 当 xi=yid_H (x, y) = \sum_{i=1}^{n} \delta (x_i, y_i), \ \text {其中} \ \delta (x_i, y_i) = \begin {cases} 1 & \text {当 } x_i \neq y_i \\ 0 & \text {当 } x_i = y_i \end {cases}

2 认证方案流程

  • SetupSetup:系统初始化,由 TA 执行,输入安全参数 λλ,TA 与 KGC 共同输出系统主私钥 ss,并发布系统参数 ParaPara

  • Registration and PseudoRegistration \ and \ Pseudo-identity Generationidentity \ Generation:注册与假名生成,每辆车辆 VjV_j 向 TA 申请注册,TA 运行本算法输入车辆的生物特征 biojbio_j​,输出生物身份 BIDjBID_j。随后车辆为 VjV_j 创建假名 PIDjPID_j​,并通过安全信道发送给车辆

  • Partial Private Key ExtractPartial \ Private \ Key \ Extract:部分密钥生成,由 KGC 执行,输入 VjV_j 的假名 PIDjPID_j​、系统主密钥 ss 和系统参数 ParaPara​,输出 VjV_j​ 的部分私钥 PSPIDPS_{PID}

  • Set Secret ValueSet \ Secret \ Value:设置秘密值,由 VjV_j 执行,输入其假名 PIDjPID_j 和系统参数 ParaPara​,生成其秘密值 xPIDx_{PID}

  • Set Private KeySet \ Private \ Key:设置私钥,由 VjV_j 执行,输入假名 PIDjPID_j​、部分私钥 PSPIDPS_{PID}、系统参数 ParaPara​ 和秘密值 xPIDx_{PID},生成其完整私钥 SKPIDSK_{PID}

  • Set Public KeySet \ Public \ Key:设置公钥,由 VjV_j 执行,给定车辆 VjV_j​ 的秘密值 xPIDjx_{PID_j}​,生成 VjV_j 的公钥 PKPIDjPK_{PID_j}

  • SignSign:签名,由 VjV_j 执行,输入 VjV_j 的假名 PIDjPID_j、系统参数 ParaPara、消息 mm 和完整私钥 SKPIDSK_{PID},输出与 PIDjPID_j 和消息 mm 关联的签名 σ\sigma

  • VerifyVerify:验证,给定车辆 VjV_j 的假名 PIDjPID_j​、系统参数 ParaPara、公钥 PKPIDjPK_{PID_j}​、消息 mm 和签名 σ\sigma,返回 1100

2.1 系统初始化


在此阶段,TA 生成系统主密钥并公布参数列表:

  • 给定安全参数 λ\lambda,随机选取大素数 ppqq,计算 ϕ(N)=(p1)(q1)ϕ(N)=(p−1)(q−1)N=pqN=pq,并将 ppqqϕ(N)ϕ(N) 保密

  • 另选一组大素数 pp'qq',使得 ppqqp' \neq p、q' \neq q、且 q(p1)q' \mid (p'-1)。同时,选取 gZpg \in \mathbb{Z}^*_{p'}g1g \neq 1,满足 gq1(modp)g^{q'} \equiv 1 \pmod{p'}

  • TA 随机选取一个整数 ee,满足 1<e<ϕ(N)1 < e < \phi(N)gcd(e,ϕ(N))=1\text{gcd}(e, \phi(N)) = 1。TA 根据方程 es1(modϕ(N))e \cdot s \equiv 1 \pmod{\phi(N)} 计算出主私钥 ss

  • 定义一个安全的对称密钥加密方案 Encκ()/Decκ()\text{Enc}_\kappa(\cdot)/\text{Dec}_\kappa(\cdot)κ\kappa 为对称密钥

  • TA 与 KGC 选择三个密码学哈希函数:

    • H1:{0,1}ZNH_1:\{0, 1\}^* \to\mathbb{Z}^*_{N}
    • H2:{0,1}{0,1}N/4H_2 : \{0, 1\}^* \to \{0, 1\}^{|N|/4}
    • H3:{0,1}×{0,1}×Zp×{0,1}πZqH_3 : \{0, 1\}^* \times \{0, 1\}^* \times \mathbb{Z}^*_{p'} \times \{0, 1\}^\pi \to \mathbb{Z}^*_{q'}
  • 公开参数列表 Para=(p,q,N,e,g,H1,H2,H3)Para=(p',q',N,e,g,H_1,H_2,H_3)

2.2 注册和假名生成


车辆在进入车联网前需要向 TA 注册:

  • VjV_j 通过安全信道向 TA 提供其真实的生物特征 biobio

  • TA 生成生物特征标识 BIDj=IdGen(bio)BID_j = \text{IdGen}(bio)IdGen()\text{IdGen}(\cdot) 是一种身份提取函数

  • TA 为 VjV_j 创建假名 PIDj=Encκ(BIDjnPID)TjPID_j = \text{Enc}_\kappa(BID_j \| n_{PID}) \| T_j,其中 nPIDn_{PID} 是请求的假名数量,TjT_j 为假名有效期

  • TA 通过安全信道向 VjV_j 发送 {BIDj,PIDj}\{BID_j, PID_j\}


这一步还考虑了恶意车辆冒充 RSU 的情况,作者声称的解决方案是:

  • 定义另一个安全签名方案,由 TA 将方案交给 RSU

  • RSU 定期广播自己的公钥、私钥签名后的真实身份、验签方法 Verpk(.)Ver_{pk}(.)

  • 车辆用 RSU 公钥验签;若验证失败,表明为假冒 RSU,向 TA 上报

  • TA 追溯此假冒 RSU 的真实身份

但这样做实际上是把系统的安全性建立在这个签名方案的保密性上,这并不能解决实际问题;而如果方案公开,对于一个正确的签名方案,伪装成 RSU 的恶意车辆总能自行选取一个 RIDRID',对 RIDRID' 生成一个合法签名并通过其他车辆的验证。

2.3 完整密钥生成

KGC 获取车辆 VjV_j 假名 PIDjPID_j,生物特征相关属性集 ω=(ωi)i=1n\omega = (\omega_i)_{i=1}^n,主私钥 ss,为 VjV_j 生成部分私钥:

  • 随机选取阶数为 d1d-1 的多项式 p(x)p(x),满足 p(0)=sp(0) = s

  • 计算 VjV_j​ 的部分私钥 PSPIDj=(PSi,j)i=1nPS_{PID_j}=(PS_{i,j})_{i=1}^n,其中 PSi,j=H1(PIDj)p(ωi) mod NPS_{i,j} = H_1(PID_j)^{p(\omega_i)} \ mod \ N

  • 将部分私钥 PSPIDjPS_{PID_j} 经安全信道交给 VjV_j
    车辆 VjV_j 计算完整的公私钥对:

    • 随机选取 xPIDjZqx_{PID_j} \in \mathbb{Z}^*_{q'} 和阶数为 d1d-1 的多项式 f(x)f(x),满足 f(0)=xPIDj={xi,PIDj}i=1nf(0) = x_{PID_j}=\{x_{i, PID_j}\}_{i=1}^n,其中 xi,PIDj=f(ωi)x_{i, PID_j} = f(\omega_i)
    • 私钥 SKPIDj=(PSPIDj,xPIDj)SK_{PID_j} = (PS_{PID_j}, x_{PID_j}),公钥 PKPIDj=gxPIDj mod pPK_{PID_j} = g^{x_{PID_j}} \ mod \ p'

2.4 签名


车辆 VjV_j 对消息 mjm_j 签名:

  • 随机选取 ljZNl_j \in \mathbb{Z}^*_N​ 和阶数为 d1d−1 的多项式 g(x)g(x),满足 g(0)=ljg(0) = l_j。对于 i{1,,n}i \in \{1, \dots, n\},计算:

    • yi,j=li,je mod Ny_{i,j} = l_{i,j}^e \ mod \ N,其中 li,j=g(ωi)l_{i,j} = g(\omega_i)
    • ui,j=PSi,jljH2(mj) mod Nu_{i,j} = P\text{S}_{i,j} \cdot l_{j}^{H_2(m_j)} \ mod \ N
  • 随机选取 kjZNk_j \in \mathbb{Z}^*_N​ 和阶数为 d1d−1 的多项式 q(x)q(x),满足 q(0)=kjq(0) = k_j。对于 i{1,,n}i \in \{1, \dots, n\},计算:

    • rj=gkj mod pr_j = g^{k_j} \ mod \ p'
    • vi,j=ki,jxPIDjhj mod qv_{i,j} = k_{i,j} - x_{PID_j} \cdot h_j \ mod \ q',其中 ki,j=q(ωi)k_{i,j} = q(\omega_i)hj=H3(mj,PIDj,rj,Tj)h_j = H_3(m_j, PID_j, r_j, T_j)TjT_j 为时间戳
  • 得到签名 σj=(uj,vj,yj,rj,hj)\sigma_j = (u_j, v_j, y_j, r_j, h_j),其中 yj=(yi,j)i=1ny_j = (y_{i,j})_{i=1}^n, uj=(ui,j)i=1nu_j = (u_{i,j})_{i=1}^n, vj=(vi,j)i=1nv_j = (v_{i,j})_{i=1}^n

2.5 验证

验证者接收消息 - 签名对 (mj,σj)(m_j, \sigma_j) 和车辆 VjV_j 公钥 PKPIDjPK_{PID_j},生物特征相关属性集 ω=(ωi)i=1n\omega = (\omega_i)_{i=1}^nω=(ωi)i=1n\omega' = (\omega'_i)_{i=1}^n,其满足 ωωd|\omega \cap \omega'| \geq d,验证签名:

  • ωω\omega \cap \omega' 中随机选取一个包含 dd 个元素的子集 SS,验证等式

    (ωiSui,jΔωi,S(0))e=H1(PIDj)(ωiSyi,jΔωi,S(0)H2(mj)edΔωi,S(0))modN\left( \prod_{\omega_i \in S} u_{i,j}^{\Delta_{\omega_i, S(0)}} \right)^e = H_1(PID_j) \cdot \left( \sum_{\omega_i \in S} y_{i,j}{\Delta_{\omega_i, S(0)}} ^{H_2(m_j)ed \Delta_{\omega_i, S(0)}} \right) \mod N

    其中 Δωi,S(0)\Delta_{\omega_i, S(0)} 为拉格朗日基本多项式。若上述等式成立,进入下一步验证

  • 计算 hj=H3(mj,PIDj,rj,Tj)h_j' = H_3(m_j, PID_j, r_j', T_j),验证等式

rj=(ωiSgjvi,j)(PKPIDj)hjd mod pr'_j=\left(\prod_{\omega_i \in S} g_j^{v'_{i,j}} \right) \cdot \left(PK_{PID_j} \right)^{h'_j d} \ mod \ p'

3 安全性分析

3.1 安全规约回顾

安全规约中涉及的三类实体:

  • 敌手(Adversary):意图攻破密码学方案的实体;

  • 挑战者(Challenger):当敌手与真实方案(Real Scheme)交互时,敌手实际上是在与挑战者交互,由挑战者生成真实方案并应答敌手的询问请求。挑战者仅出现在安全模型和安全描述中;

  • 模拟器(Simulator):当敌手与模拟方案(Simulated Scheme)进行交互时,敌手实际上是在与模拟器进行交互,由模拟器生成模拟方案并应答来自敌手的询问请求。模拟器仅出现在安全归约中,作为运行归约算法的一方。

3.2 无证书签名的安全模型

  • I 型敌手:外部攻击者,可随意替换任意实体的公钥,但无法获知主密钥

  • II 型敌手:恶意的 KGC,可获知系统主密钥,但无法替换用户公钥

3.3 本文模拟方案

底层困难问题

  • DL 问题:已知 {x,y  y=gx, xZq}\{x, y \ | \ y=g^x, \ x \in Z_q^∗ \},求解 xx 是困难的。

  • VRSA 问题:已知 {n,e,a,z   n=pq, gcd(e,(p1)(q1))=1,ueawz(modn), u,wZq}\{n, e, a, z \ | \ \ n = pq, \ \gcd(e, (p-1)(q-1)) = 1, u^e \equiv a w^z \pmod{n}, \ u, w \in Z_q^∗ \},求解 uuww 是困难的。

3.4 求解困难问题

Type I 型敌手

I 型敌手伪造对于 (PID^,m^)(\hat{PID} , \hat{m} ) 的签名 (u^,v^,y^,r^,h^)(\hat{u} ,\hat{v} ,\hat{y} ,\hat{r} ,\hat{h} ),满足

(ωiSy^iΔωi,S(0),ωiSu^iΔωi,S(0))\left(\sum_{\omega_i \in S} \hat{y}_i{\Delta_{\omega_i, S(0)}}, \prod_{\omega_i \in S} \hat{u}_i^{\Delta_{\omega_i, S(0)}}\right) 为困难问题的解

然而,这与 VRSA 问题的难度相矛盾,故方案是安全的。

Type II 型敌手

在询问 Public Key QueryPublic \ Key \ Query 时,若 PIDPIDπd|PID \cap PID_{\pi}| \geq d,则令 PKPID=βP K_{PID} = \beta
在求解推导中,通过控制 H3H_3 的不同,得到对同一条消息的两条签名,满足
(ωiSgv^)PKPIDπh^d=r^ mod p\left( \prod_{\omega_i \in S} g^{\hat{v}} \right) PK_{P ID_\pi}^{\hat{h}d} = \hat{r} \ mod \ p'
(ωiSgv^)PKPIDπh^d=r^ mod p\left( \prod_{\omega_i \in S} g^{\hat{v'}} \right) PK_{P ID_\pi}^{\hat{h'}d} = \hat{r} \ mod \ p'
①-②loggβ=v^v^(h^h^)d\log_g \beta = \frac{\hat{v} - \hat{v}'}{(\hat{h}' - \hat{h})d} 为困难问题的解

然而,这与 DL 问题的难度相矛盾,故方案是安全的。

3.5 非形式化安全性证明

  • 消息认证:根据证明,本方案在 ECDLP 和变种 RSA 问题难以解决的假设下是抗自适应选择消息攻击的,所提方案可以保证消息的完整性、认证性和不可否认性。

  • 条件隐私保护:车辆 ViV_i 使用假名 PIDjP ID_j​ 保护其真实身份,假名基于安全对称加密方案 Encκ()/Decκ()\text{Enc}_\kappa(\cdot)/\text{Dec}_\kappa(\cdot) 生成,在不知道对称密钥 κ\kappa 的情况下,任何实体都无法恢复 ViV_i 的真实身份。仅 TA 拥有密钥,具备恢复 ViV_i 的真实身份 BIDjBID_j 的能力。

  • 容错性:方案基于秘密共享将系统主私钥 ss 和车辆 VjV_j 的秘密值 xPIDjx_{PID_j} 分别分成 nn 份,使得车辆 VjV_j 的部分私钥、完整私钥及签名均可以被构造为 nn 份的形式。任何包含至少 dd 个属性的属性集均可验证 VjV_j 的签名,因此方案具有容错性。

  • 可追溯性:当恶意车辆发送错误信息时,TA 可通过下述公式提取车辆 VjV_j​ 的生物特征身份 BIDjBID_j​ 并追踪恶意车辆:

  • 不可链接性:假名生成时用到的随机数 ljl_j​ 和 kjk_j​ 是不重复的,每个 PIDPID 是随机且唯一的。因此,攻击者无法关联由同一签名者生成的多个签名。

4 实验评估

4.1 计算开销

本文采用 MIRACL 密码学库计算了不同基本操作的执行时间。选取的参考方案 [19~25] 均为基于双线性配对的方案,因此与作者选取的这些方案相比,本文无配对的方案具有更低的计算开销。

  • TbpT_{bp}:执行双线性映射操作的时间

  • Tbp.mT_{bp.m}:执行基于双线性映射的标量乘法操作的时间

  • Tbp.smT_{bp.sm}:执行基于双线性映射的小指数测试的时间

  • Tbp.aT_{bp.a}:执行基于双线性映射的点加操作的时间

  • Te.mT_{e.m}:执行椭圆曲线上标量乘法操作的时间

  • Te.smT_{e.sm}:执行椭圆曲线上小指数测试的时间

  • Te.aT_{e.a}:执行椭圆曲线上点加操作的时间

  • Te.exT_{e.ex}:执行模幂运算所需的时间

  • TmtpT_{mtp}:执行映射到点的哈希时间

4.2 通信开销

对 I 型双线性配对,为达到 80bit 安全长度,需要 g11024(bits)|g_1 |≥ 1024(bits),故 G1\mathbb{G}_1 的群元素大小为 1024÷8=1281024\div 8=128 字节。对比表明,本文方案在签名长度方面具有更低的通信开销。

  • lZql_{Z^*_{q}}:20 字节,ZqZ^*_{q}​ 中的元素长度

  • lG1l_{G_1}:128 字节, G1\mathbb{G}_1 中的元素长度

  • lGl_{G}:40 字节,G\mathbb{G} 中的元素长度

  • 时间戳和哈希函数的输出分别设置为 4 字节和 20 字节

1 Class 类文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

def Class 文件是一组以 8 个字节为基础单位的二进制流,存储内容几乎全部是程序运行的必要数据,各数据项严格按照顺序紧凑排列,中间无任何分隔符。根据《Java 虚拟机规范》,Class 文件由一个 ClassFile 结构组成,采用的是一种类似于 C 语言结构体的伪结构来存储数据,仅包含下述两种数据类型:

  • 无符号数:基本数据类型,用 u1、u2、u4、u8 表示 1~8 个字节的无符号数,可表示数字、索引引用、数量值或是以 UTF-8 格式编码的字符串

  • :包含多个无符号数,用于描述有层次关系的复合结构的数据

    • 为便于区分,所有表命名均以 “_info” 结尾
    • 整个 Class 文件本质上也是一张表
 点击折叠

Q:对占用 8 个字节以上空间的数据项,Class 文件是如何存储的?

A:按照大端序拆分存储。即将数据项分割成若干个 8 个字节,按照高位字节在地址最低位,最低字节在地址最高位进行存储

1.1 全限定名、简单名称和描述符

在 Class 文件中,这三类特殊字符串的出现频率很高:

  • 全限定名:类的全限定名是将类全名中的 “.” 用 “/” 替换,并在最后加入一个 “;” 标志结束的字符串

    e.g. Object 类的全限定名为 Ljava/lang/Object;

  • 简单名称:没有类型和参数修饰的方法或字段名称

    e.g. 假设当前的 Class 文件中包含了一个 hello () 方法,则 hello () 方法的简单名称为 hello

标识字符 含义
B 基本类型 byte
C 基本类型 char
D 基本类型 double
F 基本类型 float
I 基本类型 int
J 基本类型 long
S 基本类型 short
Z 基本类型 boolean
V 特殊类型 void
L 对象类型,如 Ljava/lang/Object;
  • 方法和字段的描述符

    • 描述字段的数据类型:基本数据类型以及 void 类型均用一个大写字符表示,对象类型用字符 L 加对象的全限定名表示
    • 描述方法的参数列表(包括数量、类型以及顺序)及其返回值:按照先参数列表、后返回值的顺序描述,参数列表按照参数的严格顺序置于 “()” 内

    e.g. 方法 void hello () 的描述符为 “() V”

 点击折叠

Q:一个 java.lang.String[][] 类型二维数组字段的字节码应如何描述?

A:每一维对应一个前置的 [字符,即 [[Ljava/lang/String;

1.2 魔数和版本号

图1-1 魔数和版本号

  • 魔数(Magic Number):为每个 Class 文件的头 4 个字节,唯一作用是确定文件是否为一个能被虚拟机接受的 Class 文件

  • 次版本号(Minor Version):第 5、第 6 个字节,JDK1.2 后置 0

  • 主版本号(Major Version):第 7、第 8 个字节

    e.g. 52(0x0034)代表 JDK8 版本下编译产生的字节码文件

 点击折叠

* 注 1:据说早期 Class 文件使用 “0xCAFEBABE” 作为魔数象征着著名咖啡品牌 Peet’s Coffee 深受欢迎的 Baristas 咖啡,这也和日后 Java 的商标不谋而合

* 注 2:根据《Java 虚拟机规范》4.1 节可知,次版本号(minor version)曾在早期版本使用。但在实际的 Java 演化中,JVM 的兼容性几乎完全通过主版本号(major version)来管理:

“For a class file whose major_version is 56 or above, the minor_version must be 0 or 65535”

对于 major_version 为 56 或以上的类文件,minor_version 必须为 0 或 65535

“For a class file whose major_version is between 45 and 55 inclusive, the minor_version may be any value”

对于 major_version 在 45 至 55 之间(含 55)的类文件,minor_version 可以是任何值

“A class file is said to depend on the preview features of Java SE N (N ≥ 12) if it has a major_version that corresponds to Java SE N and a minor_version of 65535”

如果一个类文件的 major_version 与 Java SE N 对应,且 minor_version 为 65535,则该类文件被称为依赖于 Java SE N 的预览功能(N ≥ 12)

1.3 常量池

def 常量池(constant pool)可理解为 Class 文件的资源仓库,入口处由常量池容量计数值(constant_pool_count)从 1 开始记录了常量池中的常量数目。主要存放下述两类常量:

  • 字面量:文本字符串、被声明为 final 的常量值等

  • 符号引用

    • 被模块导出或者开放的包
    • 类和接口的全限定名
    • 字段、方法的名称和描述符
    • 方法句柄和方法类型
    • 动态调用点和动态常量

以 JDK13 为例,常量表包含了 17 种不同类型的常量,彼此数据结构完全独立(建议在有需要时查表)

 点击折叠

Q:为什么 Class 文件中,只有常量池容量计数值不是从 0 开始的?

A:人为设计,将 0 保留并用于表示 “不引用任何一个常量池项目” 的索引值数据

1.4 访问标志

图1-2 访问标志

def 访问标志(access_flags)是一个标志掩码,用于表示类或接口的访问权限和属性。一共有 16 个标志位可以使用,截止 JDK9 定义了 9 个。Class 文件中访问标志的 2 个字节紧跟在常量池之后,值按照按位取或的方式(压缩状态)计算

e.g. 假设当前有一个 Main 类,是一个访问权限为 public 的普通 Class,且未被声明为 final 或 abstract,则有 ACC_PUBLIC | ACC_SUPER = 0x0001 | 0x0020 = 0x0021

1.5 类索引、父类索引和接口索引集合

图1-3 类索引查找全限定名

Class 文件中由这三项数据确定继承关系:

  • 类索引(this_class):2 个字节,用于确定类的全限定名,指向一个类型为 CONSTANT_Class_info 的类描述符常量,通过 CONSTANT_Class_info 类型的常量中的索引值可以找到定义在 CONSTANT_Utf8_info 类型的常量中的全限定名字符串

  • 父类索引(super_class):2 个字节,用于确定类的父类的全限定名

图1-4 类索引、父类索引和接口计数器

  • 接口索引集合(interfaces []):一组 u2 类型数据的集合,描述类实现的接口

    • 由接口计数器(interfaces_count)表示索引表的容量
    • 按照 implements/extends 关键字后的接口顺序排列
 点击折叠

Q:Object 类的父类索引应如何表示?

A: Object 作为唯一没有父类的类,其父类索引规定置 0

“If the value of the super_class item is zero, then this class file must represent the class Object, the only class or interface without a direct superclass”

如果 super_class 项的值为零,那么此类文件必须表示类 Object,这是唯一没有直接超类的类或接口

1.6 字段表集合

1
2
3
4
5
6
7
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

def 字段表(field_info)用于描述接口或者类中声明的变量

图1-5 字段表的字段访问标志

  • 字段访问标志(access_flags):类比类的访问标志

  • 字段的简单名称对常量池项的引用(name_index)

  • 字段的描述符对常量池项的引用(descriptor_index)

  • 属性计数器(attributes_count)

  • 属性表集合(attribute_info):存储额外信息

    e.g. 对字段声明 final static int m=520; 存储的额外信息为常量 520

1.7 方法表集合

1
2
3
4
5
6
7
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

def 字段表(method_info)用于描述接口或者类中声明的方法

图1-6 方法表的方法访问标志

  • 方法访问标志(access_flags):类比类的访问标志

  • 方法的简单名称对常量池项的引用(name_index)

  • 方法的描述符对常量池项的引用(descriptor_index)

  • 属性计数器(attributes_count)

  • 属性表集合(attribute_info)

Javac 编译器会自动添加方法,最常见的是类构造器 <clinit>() 方法和实例构造器 <init>() 方法

图1-7 Javac编译器自动添加的方法

1.8 属性表集合

def 属性表(attribute_info)用于描述信息,从 JVM 实现必须包含的属性到任何人实现的编译器写入的自定义属性均可,JVM 运行时将忽略未知属性

  • 属性名称为从常量池中引用的 CONSTANT_Utf8_info 类型的常量

  • 属性值的结构是完全自定义的,以 u4 长度的属性说明属性值所占用的位数

1.8.1 Code 属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

def Code 属性是 Class 文件中最重要的一个属性,Java 程序方法体中的代码在编译后以字节码指令的形式存储在 Code 属性内

  • 抽象类或接口中的方法不存在 Code 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
public Fundamentals.BinarySearch.Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LFundamentals/BinarySearch/Main;

使用 Javap 反编译一个字节码文件,可知 Code 属性中包含以下主要信息:

  • 最大操作数栈(stack,对应 max_stack):JVM 运行时根据该值分配栈帧(Stack Frame)中的操作栈深度

  • 局部变量表所需存储空间(locals,对应 max_locals)

    • 单位是变量槽(Slot),占用 4 个字节,是虚拟机为局部变量分配内存所使用的最小单位
  • 方法的参数数目(args_size)

  • 方法体内容(attribute_info)

    • 将第一个引用类型本地变量推送至栈顶
    • 执行该类型的实例方法,即常量池存放的第一个变量 java/lang/Object."<init>":()V
    • 执行返回语句
  • 行号表(LineNumberTable):描述源码行号与字节码行号(字节码偏移量)之间的对应关系

  • 局部变量表(LocalVariableTable):描述源码中定义的变量与栈帧中局部变量之间的关系

 点击折叠

Q:这里 Main () 方法并没有入参,为什么方法的参数数目(args_size)为 1?

A:因为实例方法的局部变量表中会存在至少一个指向当前对象实例的局部变量,局部变量表预留出第一个变量槽存放对象实例的引用。具体来说, Javac 编译器在编译时将对 this 关键字的访问转变为对一个普通方法参数的访问,并在虚拟机调用实例方法时自动传入,从而使得实例方法可通过 this 关键字访问到此方法所属的对象。而对于 static 关键字修饰的静态方法,其方法的参数数目为 0

2 字节码指令

def 字节码指令是代表某种特定含义的操作码

  • 指令长度只有一个字节

  • JVM 面向操作数栈而非寄存器架构,大多数指令不带参数

  • 操作码助记符:l 代表 long,s 代表 short,b 代表 byte,c 代表 char,f 代表 float,d 代表 double,a 代表 reference

大部分指令都不支持整数类型 byte、char 和 short,且没有任何指令支持 boolean 类型。实际上在大多数情况下,这四种类型均使用 int 作为运算类型。故以下主要以 int 类型列举部分常见指令:

  • 加载和存储指令

    • 将一个局部变量加载到操作数栈:iloadiload_<n>
    • 将一个数值从操作数栈存储到局部变量表:istoreistore_<n>
    • 将一个常量加载到操作数栈:bipushldciconst_<i>
  • 运算指令

    • 四则运算:iaddisubimulidiv
    • 按位运算:iandiorixor
    • 局部变量自增指令:iinc
  • 对象创建与访问指令

    • 创建类实例:new
    • 创建数组:newarray
    • 访问实例字段和类字段:getfieldputfieldgetstaticputstatic
    • 把一个数组元素加载到操作数栈:iaload
    • 将一个操作数栈的值储存到数组元素中:iastore
  • 操作数栈管理指令

    • 将操作数栈栈顶一个或两个元素出栈:poppop2
    • 复制栈顶数值并复制值入栈:dupdup_x1
    • 将栈最顶端的两个数值互换:swap
  • 控制转移指令

    • 条件分支:ifeqifnonnull
    • 复合条件分支:tableswitchlookupswitch
    • 无条件分支:gotojsrret
  • 方法调用和返回指令

    • 调用对象的实例方法:invokevirtual
    • 调用接口方法:invokeinterface
    • 调用一些需要特殊处理(实例初始化、私有和父类方法)的实例方法:invokespecial
    • 调用类静态方法:invokestatic

3 JVM 类加载机制

3.1 类的生命周期

图3-1 类的生命周期

def 类加载过程包含加载、验证、准备、解析和初始化五个部分,是一个类型从被加载到虚拟机内存中到完成初始化的全过程

  • 验证、准备、解析三个部分统称为连接

  • 第 1~4 阶段的顺序是确定的:指按顺序开始,而不是按顺序依次执行

  • 为支持运行时绑定特性,解析阶段可以在初始化阶段之后开始

3.1.1 加载

在加载阶段,JVM 完成以下步骤:

  • 通过一个类的全限定名获取定义此类的二进制字节流

  • 将该字节流代表的静态存储结构转化为方法区的运行时数据结构

  • 在内存中生成一个代表类的 java.lang.Class 对象,作为方法区该类数据的访问入口

3.1.2 验证

验证阶段旨在确保 Class 文件的字节流中包含的信息符合约束:

  • 文件格式验证:从魔数和版本号的格式开始检查直至属性表

  • 元数据验证:对字节码描述的信息进行语义分析,保证元数据信息中的数据类型符合 Java 语言规范

  • 字节码验证:验证中最复杂的步骤,对类的方法体(Code 属性)进行校验分析

  • 符号引用验证:对常量池中的各种符号引用进行匹配性校验,确保能够正常解析

3.1.3 准备

在准备阶段,正式为静态变量分配内存并设置初始值

  • 准备阶段分配内存的仅包括类变量,而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在 Java 堆中

  • 一般地,设置的初始值是数据类型默认的零值;但如果类字段的字段属性表中存在 ConstantValue 属性,则准备阶段变量值将初始化为 ConstantValue 属性指定的初始值

    e.g. 语句 public static int a = 520; 对应准备阶段 a 的初始值为 0

图3-2 基本数据类型的零值

3.1.4 解析

解析阶段将常量池内的符号引用替换为直接引用,解析动作主要针对接口字段类方法接口方法方法类型方法句柄调用点限定符 7 类符号引用进行

  • 符号引用(Symbolic References):以一组符号来描述所引用的目标,可为任意形式的字面量,仅要求能无歧义地定位到目标

  • 直接引用(Direct References):直接指向目标的指针、相对偏移量或能间接定位到目标的句柄

3.1.5 初始化

初始化阶段执行类中编写的 Java 程序代码。《Java 虚拟机规范》严格规定有且只有六种情况必须立即对类进行初始化,类的初始化时机如下:

  • 遇到 newgetstaticputstaticinvokestatic 字节码指令时

  • 使用 java.lang.reflect 包的方法对类型进行反射调用时

  • 加载一个类的子类时

  • 虚拟机启动时,需初始化包含 main () 方法的主类

  • (JDK7+)一个 java.lang.invoke.MethodHandle 实例最后的解析结果为 REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial 四种类型的方法句柄,且该方法句柄对应的类未初始化时

  • (JDK8+)一个接口包含有 default 关键字修饰的方法,且该接口的实现类已初始化时

3.1.6 使用

类访问方法区内数据结构的接口, 对象是 Java 堆的数据

3.1.7 卸载

出现以下情况 JVM 将结束生命周期:

  • 执行 System.exit () 方法

  • 程序正常执行结束

  • 程序异常终止

  • 操作系统出错导致 JVM 进程终止

3.2 类加载器

def 类加载器用于实现类的加载动作

  • 每个类加载器,都拥有一个独立的类名称空间

    e.g. 两个类来源于同一个 Class,被同一个 Java 虚拟机加载,如果用于加载的类加载器不同,则两个类必定不相等

3.2.1 双亲委派模型

从开发人员的角度,类加载器可划分为以下类型:

  • 启动类加载器(Bootstrap Class Loader):负责加载存放在 <JAVA_HOME>\lib 目录,或在 -Xbootclasspath 参数指定路径下的,并且能被虚拟机识别的类库(如 rt.jar、tools.jar,所有的 java.* 开头的类均被启动类加载器加载)

    • 启动类加载器无法被 Java 程序直接引用,如果需要向其委派加载请求,可直接使用 null 代替
  • 扩展类加载器(Extension Class Loader):负责加载 <JAVA_HOME>\lib\ext 目录中,或由 java.ext.dirs 系统变量指定路径下的所有类库(如 javax.* 开头的类)

    • sun.misc.Launcher$ExtClassLoader 类实现
    • 由于扩展类加载器是由 Java 代码实现的,开发者可直接在程序中使用扩展类加载器加载类
  • 应用程序类加载器(Application Class Loader):负责加载用户类路径(ClassPath)下的所有类库

    • sun.misc.Launcher$AppClassLoader 类实现
    • 一般情况下作为程序默认的类加载器,开发者可以直接使用

图3-3 类加载器双亲委派模型

def 双亲委派模型体现为三层类加载器、双亲委派的类加载架构

  • 要求除顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器

  • 父类加载器是采用组合而非继承关系实现

 点击折叠

Q1:介绍一下双亲委派模型的工作过程?

A:当类加载器收到类加载的请求时,它首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,每一个层次的类加载器都是如此,直到最终传送到最顶层的启动类加载器;只有当父加载器反馈无法完成加载请求时,即它的搜索范围中没有找到所需的类,此时子加载器才会尝试自己去完成类的加载

Q2:使用双亲委派模型能带来哪些好处?

A:双亲委派模型使得类随类加载器一起具备了带有优先级的层次关系,保证一个类在程序的各种类加载器环境中均加载为同一个类,防止内存中出现多份相同的字节码,保证 Java 程序能够稳定运行



参考

[1] 深入理解 Java 虚拟机:JVM 高级特性与最佳实践(第 3 版)

[2] Java JVM 虚拟机 已完结(IDEA 2021 版本)4K 蓝光画质

[3] 柏码知识库 | JVM 笔记(三)类与类加载

[4] Java 全栈知识体系

[5] Java Virtual Machine Specification

1 方案介绍

1.1 无证书签名方案 CLSS

  • Setup(k)Setup(k):系统初始化

  • PPKE(UIDi,s)PPKE(UID_i, s):部分密钥生成

  • SPRK(UIDi,di)SPRK(UID_i, d_i):设置用户完整私钥

  • SPK(UIDi,svi)SPK(UID_i, sv_i):设置用户公钥

  • Sign(Mi,ski,UIDi,pki)Sign(M_i, sk_i, UID_i, pk_i):签名

  • Verify(Mi,σi,UIDi,pki)Verify(M_i, σ_i, UID_i, pk_i):单次验证

  • BatchVerify({Mi,σi,UIDi,pki}i=1n)BatchVerify(\{M_i, σ_i, UID_i, pk_i\}^n_{i=1}):批量验证

1.1.1 系统初始化

Setup(k)Setup(k):由 KGCKGC 执行,根据安全参数生成主密钥和参数列表

  • 给定安全参数 kk,生成参数集合 G1,G2,ψ,GT,e,q,P,P\langle G_1, G_2, \psi, G_T, e, q, P, P' \rangle

  • 随机选取 sZqs \in \mathbb{Z}_{q}^* 作为主私钥,计算主公钥 P0=sP,P0=sPP_0 = sP, P'_0 = sP'

  • 选择三个密码学哈希函数 H0:{0,1}G1H_0 : \{0, 1\}^* \rightarrow G_1^*, H1:{0,1}ZqH_1 : \{0, 1\}^* \rightarrow \mathbb{Z}_{q}^*, H2:{0,1}G2H_2 : \{0, 1\}^* \rightarrow G_2^*

  • 公开参数列表 paramList={G1,G2,ψ,GT,e,q,P,P,P0,P0,H0,H1,H2}\text{paramList} = \{G_1, G_2, \psi, G_T, e, q, P, P', P_0, P'_0, H_0, H_1, H_2\}

1.1.2 部分密钥生成

PPKE(UIDi,s)PPKE(UID_i, s):由 KGCKGC 执行,接受用户身份 UIDi{0,1}UID_i \in \{0, 1\}^* 和主私钥 ss 作为输入,生成用户部分私钥 did_i

  • 计算 di=sQid_i = sQ_i,其中 Qi=H0(UIDi)Q_i = H_0(U ID_i)

1.1.3 设置完整私钥

SPRK(UIDi,di)SPRK(UID_i, d_i):由具有 UIDiUID_i 身份的用户执行,输入身份 UIDiUID_i 和部分私钥 did_i,生成其完整私钥 skisk_{i}

  • 选择随机数 sviZqsv_{i} \in \mathbb{Z}_{q}^*​ 作为其秘密值

  • 设置完整私钥 ski=(svi,di)sk_{i} = (sv_{i}, d_i)

1.1.4 设置公钥

SPK(UIDi,svi)SPK(UID_i, sv_i):由具有 UIDiUID_i 身份的用户执行,输入用户身份 UIDiUID_i 和秘密值 svisv_i,生成用户公钥 pkipk_i

  • 计算 pki=sviPpk_i=sv_iP

1.1.5 签名

Sign(Mi,ski,UIDi,pki)Sign(M_i, sk_i, UID_i, pk_i):由具有 UIDiUID_i 身份、完整私钥 skisk_i 和公钥 pkipk_i签名者执行,输入消息 MiM_i​、skisk_{i}UIDiUID_i​ 和 pkipk_i,生成对消息 MiM_i 的签名 σiσ_i

  • 随机选取 riZqr_i \in \mathbb{Z}_{q}^*​,设置 Ri=riPR_i = r_iP

  • 计算 ui=H1(UIDiMipkiRiΔ)u_i = H_1(UID_i || M_i || pk_i || R_i || \Delta)W=H2(Δ)W = H_2(\Delta),其中 Δ\Delta 是基于时间戳生成的一次性消息

  • 计算 Vi=uisviψ(W)+uidi+ri(ψ(W)+P0)V_i = u_isv_{i}\psi(W) + u_id_i + r_i(\psi(W) + P_0)

  • 设置签名 σi=(Ri,Vi)\sigma_i = (R_i, V_i)

1.1.6 验证

Verify(Mi,σi,UIDi,pki)Verify(M_i, σ_i, UID_i, pk_i):输入消息 MiM_i、签名 σiσ_i、用户身份 UIDiUID_i 和用户公钥 pkipk_i验证者验证签名 σiσ_i 的有效性

  • 计算 Qi=H0(UIDi)Q_i = H_0(U ID_i)ui=H1(UIDiMipkiRiΔ)u_i = H_1(UID_i || M_i || pk_i || R_i || \Delta)W=H2(Δ)W = H_2(\Delta)

  • 如果 e(Vi,P)=e(uipki+Ri,W)e(uiQi+Ri,P0)e(V_i, P') = e(u_ipk_i + R_i, W)e(u_iQ_i + R_i, P'_0) 成立,则输出 11;否则输出 00

正确性证明:代入 Vi=uisviψ(W)+uidi+ri(ψ(W)+P0)V_i = u_isv_{i}\psi(W) + u_id_i + r_i(\psi(W) + P_0)di=sQid_i = sQ_i​,P0=sPP_0 = sPP0=sPP'_0 = sP'pki=sviPpk_i=sv_iPRi=riPR_i = r_iP,有
e(Vi,P)=e(uisviψ(W)+uidi+ri(ψ(W)+P0),P)e(V_i, P') = e(u_isv_{i}\psi(W) + u_id_i + r_i(\psi(W) + P_0), P')
=e(uisviψ(W),P)e(uidi,P)e(riψ(W),P)e(riP0,P)=e(u_isv_{i}\psi(W), P') \cdot e(u_id_i , P') \cdot e(r_i\psi(W),P') \cdot e(r_iP_0,P')
=e(uisviP,W)e(uisQi,P)e(riP,W)e(riP,P0)=e(u_isv_{i}P,W) \cdot e(u_isQ_i,P') \cdot e(r_iP,W)\cdot e(r_iP,P_0')
=e(uipki,W)e(uiQi,sP)e(Ri,W)e(Ri,P0)=e(u_ipk_i,W)\cdot e(u_iQ_i,sP')\cdot e(R_i,W)\cdot e(R_i,P_0')
=e(uipki+Ri,W)e(uiQi+Ri,P0)=e(u_ipk_i + R_i, W)e(u_iQ_i + R_i, P'_0)

1.1.7 批量验证

BatchVerify({Mi,σi,UIDi,pki}i=1n)BatchVerify(\{M_i, σ_i, UID_i, pk_i\}^n_{i=1})验证者批量验证消息 - 签名对 (Mi,σi)(M_i, σ_i)

  • 随机选取 θ=(θ1,θ2,...,θn)\theta = (\theta_1, \theta_2, ..., \theta_n),其中 θi{0,1}l\theta_i \in \{0, 1\}^lll 为小整数

  • 计算 Qi=H0(UIDi)Q_i = H_0(U ID_i)ui=H1(UIDiMipkiRiΔ)u_i = H_1(UID_i || M_i || pk_i || R_i || \Delta)W=H2(Δ)W = H_2(\Delta)

  • 如果 e(i=1nθiVi,P)e(\sum_{i=1}^{n} \theta_i V_i, P') = e(i=1nθi(uipki+Ri),W)e(\sum_{i=1}^{n} \theta_i(u_i pk_i + R_i), W)e(i=1nθi(uiQi+Ri),P0)e(\sum_{i=1}^{n} \theta_i(u_i Q_i + R_i), P'_0) 成立,则输出 11;否则输出 00

正确性证明:代入 Vi=uisviψ(W)+uidi+ri(ψ(W)+P0)V_i = u_isv_{i}\psi(W) + u_id_i + r_i(\psi(W) + P_0)di=sQid_i = sQ_i​,P0=sPP_0 = sPP0=sPP'_0 = sP'pki=sviPpk_i=sv_iPRi=riPR_i = r_iP,有
e(i=1nθiVi,P)=e(i=1nθi(uisviψ(W)+uidi+ri(ψ(W)+P0)),P)e(\sum_{i=1}^{n} \theta_i V_i, P') =e(\sum_{i=1}^{n} \theta_i (u_isv_{i}\psi(W) + u_id_i + r_i(\psi(W) + P_0)), P')
=e((i=1nθiuisvi)ψ(W),P)e(i=1nθiuidi,P)=e((\sum_{i=1}^{n} \theta_iu_isv_{i}) \cdot\psi(W), P') \cdot e(\sum_{i=1}^{n} \theta_iu_id_i , P') e((i=1nθiri)ψ(W),P)e((i=1nθiri)P0,P)\cdot e((\sum_{i=1}^{n} \theta_ir_i) \cdot \psi(W),P') \cdot e((\sum_{i=1}^{n} \theta_ir_i) \cdot P_0,P')
=e((i=1nθiuisvi)P,W)e(i=1nθiuisQi,P)=e((\sum_{i=1}^{n} \theta_iu_isv_{i}) \cdot P,W) \cdot e(\sum_{i=1}^{n} \theta_iu_isQ_i,P')e((i=1nθiri)P,W)e((i=1nθiri)P,P0)\cdot e((\sum_{i=1}^{n} \theta_ir_i) \cdot P,W)\cdot e((\sum_{i=1}^{n} \theta_ir_i) \cdot P,P_0')
=e(i=1nθiuipki,W)e((i=1nθiuiQi,sP)=e(\sum_{i=1}^{n} \theta_iu_ipk_i,W)\cdot e((\sum_{i=1}^{n} \theta_iu_iQ_i,sP')e(i=1nθiRi,W)e(i=1nθiRi,P0)\cdot e(\sum_{i=1}^{n} \theta_iR_i,W)\cdot e(\sum_{i=1}^{n} \theta_iR_i,P_0')
=e(i=1nθi(uipki+Ri),W)=e(\sum_{i=1}^{n} \theta_i(u_i pk_i + R_i), W)e(i=1nθi(uiQi+Ri),P0)e(\sum_{i=1}^{n} \theta_i(u_i Q_i + R_i), P'_0)

1.2 车对车通信方案 ES&PPS

1.2.1 系统初始化阶段

在此阶段,KGCKGC 生成系统主密钥并公布参数列表

  • 给定安全参数 kk,运行 Setup(k)Setup(k) 算法,生成主密钥 ss 和参数列表 paramList={G1,G2,ψ,GT,e,q,P,P,P0,P0,H0,H1,H2}\text{paramList} = \{G_1, G_2, \psi, G_T, e, q, P, P', P_0, P'_0, H_0, H_1, H_2\}

  • 选择一个安全的对称加密方案 Ekey()/Dkey()E_{\text{key}}(\cdot) / D_{\text{key}}(\cdot) 及其密钥 key\text{key}

  • 设置系统主密钥为 (key,s)(\text{key}, s)

  • 公开参数列表 paramList={paramList,Ekey()/Dkey()}\text{paramList}' = \{\text{paramList}, E_{\text{key}}(\cdot) / D_{\text{key}}(\cdot)\}

1.2.2 车辆注册阶段

车辆需要向 KGCKGC 注册,KGCKGC 会为每辆车生成部分私钥和假名,并通过安全信道发送给每辆车;车辆收到后,生成完整私钥及对应公钥

  • 车辆 ViV_i 首先通过安全信道向 KGCKGC 提交注册请求 (UIDi,m~)(UID_i, \tilde{m}),其中 UIDiUID_i 是车辆的真实身份,m~\tilde{m} 是请求的新假名数目

  • 收到来自 ViV_i​ 的注册请求后,KGCKGC 执行以下步骤:

    • 计算 PIDi,j=Ekey(UIDij)tiPID_{i,j} = E_{\text{key}}(U ID_i || j) || t_i 生成一组假名,其中 tit_i 是假名有效期,j{1,,m~}j \in \{1, \ldots, \tilde{m}\}
    • 运行 PPKE(PIDi,j,s)PPKE(P ID_{i,j}, s) 算法,获得与 PIDi,jP ID_{i,j}​ 对应的部分私钥 di,jd_{i,j}
    • 通过安全信道向 ViV_i​ 发送 {(PIDi,j,di,j)}j=1m~\{(P ID_{i,j}, d_{i,j})\}_{j=1}^{\tilde{m}}
  • 车辆 ViV_i​ 分别运行 SPRK(PIDi,j,di,j)SPRK(PID_{i,j}, d_{i,j})SPK(PIDi,j,svi,j)SPK(P ID_{i,j}, sv_{i,j}) 算法,生成相应的完整私钥 ski,j=(svi,j,di,j)sk_{i,j} = (sv_{i,j}, d_{i,j}) 和公钥 pki,jpk_{i,j}

1.2.3 签名生成阶段

在车载自组网中,车辆需要定期广播交通相关信息 TRM。每辆车首先使用自己的完整私钥对 TRM 签名,再将签名后的 TRM 广播给附近车辆

  • 运行 Sign(Mi,ski,j,PIDi,j,pki,j)\text{Sign}(M_i, sk_{i,j}, P ID_{i,j}, pk_{i,j}) 算法生成对 MiM_i 的签名 σi,j\sigma_{i,j}

  • ViV_i 广播 {PIDi,j,pki,j,Mi,σi,j}\{P ID_{i,j}, pk_{i,j}, M_i, \sigma_{i,j}\} 为签名后的 TRM

1.2.4 验证阶段

车辆可能在短时间内收到许多 TRM,可批量验证一组 TRM 的有效性。假设 ViV_i 需要广播的 TRM 为 MiM_i,其中包含时间戳 TsiTs_{i},则

  • 车辆运行 BatchVerify({Mi,σi,j,PIDi,j,pki,j}i=1n)\text{BatchVerify}(\{M_i, \sigma_{i,j}, P ID_{i,j}, pk_{i,j}\}_{i=1}^{n}) 算法验证这些已签名 TRM 的有效性。如果输出 11,则接受这些 TRM

1.2.5 追踪阶段

如果车辆发现了使用伪造签名的 TRM,可以请求 KGCKGC 披露签名者的真实身份

  • KGC 计算 Dkey(PIDi,j)=Dkey(Ekey(UIDij))D_{\text{key}}(P ID_{i,j}) = D_{\text{key}}(E_{\text{key}}(U ID_{i}||j)) 得到 UIDijUID_{i}||j,从而获知其真实身份 UIDiUID_{i}

2 安全性分析

2.1 安全规约回顾

安全规约中涉及的三类实体:

  • 敌手(Adversary):意图攻破密码学方案的实体;

  • 挑战者(Challenger):当敌手与真实方案(Real Scheme)交互时,敌手实际上是在与挑战者交互,由挑战者生成真实方案并应答敌手的询问请求。挑战者仅出现在安全模型和安全描述中;

  • 模拟器(Simulator):当敌手与模拟方案(Simulated Scheme)进行交互时,敌手实际上是在与模拟器进行交互,由模拟器生成模拟方案并应答来自敌手的询问请求。模拟器仅出现在安全归约中,作为运行归约算法的一方。

2.2 无证书签名的安全模型

  • I 型敌手:外部攻击者,可随意替换任意实体的公钥,但无法获知主密钥

  • II 型敌手:恶意的 KGC,可获知系统主密钥,但无法替换用户公钥

2.3 本文 CLSS 的模拟方案

底层困难问题 co-CDHP:已知 {P,aP,P,bPa,bZq}\{P, aP, P', bP' | a,b \in Z_q^∗ \},求解 abPabP 是困难的。模拟方案包含以下步骤:

  • SetupSetup

  • PPK(UIDi)PPK(UID_i) queryquery

  • SVE(UIDi)SVE(UID_i) queryquery

  • PK(UIDi)PK(UID_i) queryquery

  • PKR(UIDi,pki)PKR(UID_i, pk'_i) queryquery

  • S(Mi,UIDi,pki)S(M_i,UID_i, pk'_i) queryquery

  • ForgeryForgery

注:本文在规约时全程使用了 Challenger 同敌手进行交互,这是不严谨的。由于挑战者只会如实地回答敌手的询问,这就导致无法将方案规约到困难问题上

2.4 求解困难问题

e(Vi,P)=e(uipki+Ri,Wi)e(uiQi+Ri,P0)e(V^{*}_i, P') = e(u^{*}_i pk^*_i + R^*_i, W^*_i) e(u^{*}_i Q^*_i + R^*_i, P'_0)

e(Vi,P)=e(uipki+Ri,Wi)e(uiQi+Ri,P0)e(V^{*'}_i, P) = e(u^{*'}_i pk^*_i + R^*_i, W^*_i) e(u^{*'}_i Q^*_i + R^*_i, P'_0)

Type I:由 P0=aPP'_0 = aP'Qi=αibPQ^*_i = \alpha^*_i bP,①-②得

abP=αi1[(uiui)1(ViVi)γipki]abP = {α^∗_i }^{−1} [{(u^∗_i − u^{∗'}_i)}^{−1}(V ^∗_i − V^{∗'}_i ) − γ ^∗_i pk ^∗_i ] 为困难问题的解

Type II:由 Wi=βiaPW_i^*=\beta_i^* aP^{'}pk=svibPpk^*={sv}_i^* bP,①-②得

abP=svi1βi1[(uiui)1(ViVi)sQi]abP={sv^*_i}^{-1}{\beta^*_i}^{-1}[(u^*_i-u^{*'}_i)^{-1}(V^*_i-V^{*'}_i)-sQ^*_i] 为困难问题的解

2.5 非形式化安全性证明

消息认证:车辆 ViV_i 在广播包含时间戳 TsiTs_{i} 的交通相关消息(TRM)MiM_i 前,首先运行 Sign(Mi,ski,j,PIDi,j,pki,j)\text{Sign}(M_i, sk_{i,j}, P ID_{i,j}, pk_{i,j}) 算法生成 {PIDi,j,pki,j,Mi,σi,j}\{PID_{i,j}, pk_{i,j}, M_i, \sigma_{i,j}\} 为签名后的 TRM。当车辆 VjV_j 接收到 n 个消息 - 签名对时,使用算法 BatchVerify({Mi,σi,j,PIDi,j,pki,j}i=1n)\text{BatchVerify}(\{M_i, \sigma_{i,j}, P ID_{i,j}, pk_{i,j}\}_{i=1}^n) 验证其有效性。根据定理 1 和 2,已签名的 TRM 是不可伪造的。

条件隐私:车辆 ViV_i 使用假名 PIDi,jP ID_{i,j}​ 保护其真实身份,假名基于安全对称加密方案 Ekey()/Dkey()E_{\text{key}}(·)/D_{\text{key}}(·) 生成,在不知道对称密钥的情况下,任何实体都无法恢复 ViV_i 的真实身份 UIDiUID_i。仅 KGCKGC 拥有密钥,具备恢复 ViV_i 的真实身份 UIDiUID_i 的能力。

3 实验评估

3.1 计算开销

  • TbT_b:执行双线性映射操作的时间

  • Tm1T_{m1}:执行 G1\mathbb{G}_1 上标量乘法操作的时间

  • TmT_m:执行椭圆曲线上标量乘法操作的时间

  • THT_H:执行映射到点的哈希时间

  • Ts1T_{s1}:执行 G1\mathbb{G}_1 上小指数测试的时间

本文此处援引了 Yang et al. 一文,意在说明:I 型双线性映射操作要比 II 型更为昂贵,使用 I 型双线性映射的 TbT_bTm1T_{m1}THT_HTs1T_{s1} 值显著高于使用 II 型双线性映射设计的方案(译)


按照逻辑,为呼应本文 “方案计算开销低于其他支持批量验证、安全的无证书签名方案” 的主要贡献,此处应当着重比较文献 [35][35] 等,但原文图例标注有误导致无法一一对应。ES&PPS 的批量验证效率仍低于无配对的四种方案([32],[33],[36],[37][32],[33],[36],[37]),但这些方案是不安全的,或缺少安全性证明。

3.2 通信开销

  • lZpl_{Z^*_{p}}:32 字节,ZpZ^*_{p}​ 中的元素长度

  • lG1sspl_{G^{\text{ssp}}_{1}}:192 字节,SSP 曲线上 G1\mathbb{G}_1 中的元素长度

  • lG1bnl_{G^{\text{bn}}_{1}}:32 字节,BN 曲线上 G1\mathbb{G}_1 中的元素长度

  • lGeccl_{G_{\text{ecc}}}​​:32 字节,BN 曲线上任意群的元素长度

对 II 型双线性配对,已知采用的曲线为 BN256,则为达到 128bit 安全长度,需要 g1256(bits)|g_1 |≥ 256(bits),故群元素的大小为 256÷8=32256\div 8=32 字节。对比表明,本文方案在签名和公钥长度方面具有相同或更低的传输开销。

Info

文章出处:CRYSTALS-Dilithium: A Lattice-Based Digital Signature Scheme

CRYSTALS-Dilithium 是 NIST 第四轮 Finalists 中唯二基于格的数字签名方案,另一方案 Falcon 基于 NTRU 格

1 引入

基于 An improved compression technique for signatures based on learning with errors 一文的简化版本,介绍此类签名方案的基本框架:

1.1 密钥生成

KeyGen()KeyGen()

  • 生成一个大小为 k×k \times \ell 的矩阵 AA,其中每个元素在多项式环 Rq=Zq[X]/(Xn+1)R_q = \mathbb{Z}_q[X]/(X^n + 1) 上,其中 q=223213+1q = 2^{23} - 2^{13} + 1, n=256n = 256

  • 从随机分布中抽取两个秘密密钥向量 s1s_1s2s_2,这些向量的系数属于环 RqR_q,且大小不超过 η\eta(一个小的上限)

  • 计算公钥的第二部分 t=As1+s2t = A s_1 + s_2

  • 输出密钥对 pk=(A,t)pk = (A, t), sk=(A,t,s1,s2)sk = (A, t, s_1, s_2)

1.2 签名

Sign(sk,M)Sign(sk, M):接受私钥 sksk、消息 MM 作为输入

  • 初始化 z=z = \bot,当 z=z = \bot 时重复下述签名过程,直到生成有效的签名

  • 生成掩码向量 yy:签名者从集合 Sγ11S_{\gamma_1 - 1}^{\ell} 中随机生成一个多项式向量 yy,其中 yy 的每个系数的大小小于 γ1\gamma_1γ1\gamma_1 需要足够大,以确保签名不会泄露秘密密钥,但也足够小,使得签名不会被轻易伪造

  • 计算 w1w_1:计算 AyAy,将 AyAy 的每个系数拆分为高位和低位部分,依照 w=w12γ2+w0w = w_1 \cdot 2\gamma_2 + w_0 提取其高位部分 w1w_1,其中 w0γ2|w_0| \leq \gamma_2

  • 生成挑战值 cc:挑战值 cc 由消息 MMw1w_1 的哈希值生成,其中 cc 是环 RqR_q 中的多项式,具有 60 个 ±1\pm 1 的系数,其他系数为 00。这样做是为了确保 cc 的范数较小,且来自于一个大于 22562^{256} 的域

  • 计算初始签名值 zz:若直接输出 zz,则会泄露秘密密钥。因此,使用拒绝采样来确保安全性

  • 拒绝采样和低位校验:(1)设置参数 β\beta,其值为 cs1c s_1 的最大可能系数。由于 cc 只有 60 个 ±1\pm 1 的系数,且 s1s_1 的最大系数为 η\eta,因此有 β60η\beta \leq 60\eta;(2)检查 Aycs2Ay - cs_2 的低位部分。如果 zz 的任何系数大于 γ1β\gamma_1 - \beta,或是 AzctAz - ct 低位部分的任何系数大于 γ2β\gamma_2 - \beta,则拒绝签名并重新开始签名过程

  • 输出签名 σ=(z,c)\sigma = (z, c)

1.3 验签

Verify(pk,M,σ)Verify(pk,M,\sigma):接受公钥 pkpk、消息 MM 和签名 σ\sigma 作为输入

  • 计算 w1w'_1AzctAz - ct 实际上等于 Aycs2Ay - cs_2,这是因为将 z=y+cs1z = y + cs_1 代入得到 Azct=A(y+cs1)ct=Ay+Acs1ct=Ay+c(As1t)=Aycs2Az - ct = A(y + cs_1) - ct = Ay + Acs_1 - ct = Ay+c(As_1-t)=Ay - cs_2

  • 验证:(1)zz 的所有系数是否小于 γ1β\gamma_1 - \beta;(2)cc 是否等于 H(Mw1)H(M || w'_1)

2 Dilithium 方案

与 1 的方案对比:公钥大小减少了约 2.5 倍,但签名大小有一个增加 150 字节左右的 tradeoff,这一改动主要涉及方案的第 6 步,这样并不公开完整的 tt,而是只有 tt 的高位部分 t1t_1;即公钥中只包含其高位部分 t1t_1,而低位部分 t0t_0 保留在私钥中

2.1 密钥生成

KeyGen()KeyGen()

  • 生成两个 256 位的随机数 ρ,K\rho, K

  • 从随机分布中抽取两个秘密密钥向量 s1s_1s2s_2,这些向量的系数属于环 RqR_q,且大小不超过 η\eta

  • 矩阵扩展:将种子 ρ\rho 扩展成一个大小为 k×k \times \ell 的矩阵 AA,其中每个元素在多项式环 Rq=Zq[X]/(Xn+1)R_q = \mathbb{Z}_q[X]/(X^n + 1) 上,其中 q=223213+1q = 2^{23} - 2^{13} + 1, n=256n = 256。但为了更快的实现考虑,矩阵 AA 实际上是以系数在 Zq256\mathbb{Z}^{256}_q 中的矩阵格式输出并存储的

  • 计算 t=As1+s2t = A s_1 + s_2

  • tt 分解为高位 t1t_1 和低位 t0t_0 两个部分。本方案中公钥的第二部分为 t1t_1 而非 tt,使得此时的公钥只需要 logqd\lceil \log q \rceil − d 字节,而非 logq\lceil \log q \rceil 字节

  • ρ\rhot1t_1 打包并使用 SHAKE-256 哈希,得到 384 位的 trtr,用于签名时的消息摘要

  • 输出密钥对 pk=(ρ,t1)pk = (\rho, t_1), sk=(ρ,K,tr,s1,s2,t0)sk = (\rho, K, tr, s_1, s_2, t_0)

2.2 签名

Sign(sk,M)Sign(sk, M)

  • 由种子 ρ\rho 生成矩阵 AA

  • trtr 和消息 MM 打包并使用 SHAKE-256 哈希,得到 384 位的消息摘要 μ\mu

  • 初始化 κ=0,(z,h)=\kappa=0,(z, h)=\bot,当 (z,h)=(z, h)=\bot 时重复下述签名过程并累加计数器 κ\kappa,直到生成有效签名

  • 生成掩码向量 yy:扩展 KμκK \|\mu \|\kappa 生成多项式向量 yy,其中 ySγ11y \in S_{\gamma_1 - 1}^{\ell}。由于签名可能需要重复尝试多次,每次尝试时附加的计数器 κ\kappa 可以确保相同消息的多次签名尝试会输出不同的随机数

  • 计算 w=Ayw = Ay

  • 计算 w1w_1:将 ww 的每个系数拆分为高位和低位部分,依照 w=w12γ2+w0w = w_1 \cdot 2\gamma_2 + w_0 提取其高位部分 w1w_1,其中 w0γ2|w_0| \leq \gamma_2

  • 生成挑战值 cc:挑战值 cc 由消息 MMw1w_1 的哈希值生成,cc 是环 RqR_q 中的多项式,具有 60 个 ±1\pm 1 的系数,其他系数为 00

  • 计算初始签名值 zz

  • wcs2w - cs_2 分解为高位 r1r_1 和低位 r0r_0,以进一步检查签名的有效性

  • 拒绝采样、高低位校验:(1)设置参数 β\beta,其值为 cs1c s_1 的最大可能系数。由于 cc 只有 60 个 ±1\pm 1 的系数,且 s1s_1 的最大系数为 η\eta,因此有 β60η\beta \leq 60\eta;(2)检查 Aycs2Ay - cs_2 的低位部分;(3)检查 Aycs2Ay - cs_2 的高位部分。如果 zz 的任何系数大于 γ1β\gamma_1 - \betaAycs2Ay - cs_2 低位部分的任何系数大于 γ2β\gamma_2 - \betaAycs2Ay - cs_2 高位部分不为 w1w_1 中的任意一项成立,则拒绝此签名

  • 生成附加提示 hh 用于验证,确保验证者可以正确恢复出高位信息。由于公钥只包含高位部分 t1t_1,验证时无法直接计算 AzctAz - ct 的完整值,而是只能计算 Azct12d=Azct+ct0Az - ct_1 \cdot 2^d = Az - ct + ct_0。为了弥补这一点,签名者需要发送提示 hh,告知验证者 ct0ct_0 导致进位的位置,从而能够正确恢复 AzctAz - ct 的高位部分。此时,如果 ct0ct_0 的任何系数大于 γ2\gamma_2,或是提示 hh 中的 1 的数目超出限制 ω\omega,则同样拒绝此签名

  • 输出签名 σ=(z,h,c)\sigma = (z, h, c)

2.3 验签

Verify(pk,M,σ)Verify(pk,M,\sigma)

  • 由种子 ρ\rho 生成矩阵 AA

  • ρ\rhot1t_1 打包并使用 SHAKE-256 哈希后,整体再和 MM 哈希得到 384 位的消息摘要 μ\mu

  • 计算 w1w'_1:使用提示 hh 恢复 Azct1A z - c t_1 的高位部分 w1w'_1。验证者计算 Azct12dAz - ct_1 \cdot 2^d,这只包含 AzAzct1ct_1 的高位部分,并使用 hh 中包含的进位信息恢复 w1w'_1

  • 验证:(1)zz 的所有系数是否小于 γ1β\gamma_1 - \beta;(2)cc 是否等于 H(Mw1)H(M || w'_1);(3)提示 hh 中的 1 的数目是否超出限制 ω\omega



参考
[1] CRYSTALS-Dilithium: A Lattice-Based Digital Signature Scheme
[2] An improved compression technique for signatures based on learning with errors

1 格 Point Lattices

def 欧氏空间中 Rn\mathbb{R}^n 上的一个离散加法子群,通过在整数格 Zn\mathbb{Z}_n 上作单射线性变换(injective linear transformation)得到。令 B=[b1,...,bn]Rd×nB=[b_1, ..., b_n] \in \mathbb{R}^{d×n}Rd\mathbb{R}^d 上一组线性无关的向量,则由 BB 生成的格为集合

L(B)={Bx:xZn={i=1nxibi:i.xiZ}}\mathcal{L}(B)=\{Bx:x \in \mathbb{Z}^n =\{\sum_{i=1}^n{x_i} \cdot b_i:\forall i.x_i \in \mathbb{Z}\}\}

  • RnR^n:实数域上的 n 维矢量空间
  • BB:格 L(B)\mathcal{L}(B) 的基矩阵(basis matrix),是一组线性无关的矩阵,能用来生成一个向量空间
  • b1,b2,...,bnb_1,b_2,...,b_n:格基,同一个格可以由多组不同的格基生成。
    • i.e. 格基 (1,0)T(1,0)^T (0,1)T(0,1)^T 可以生成二维空间的所有整数格,还可以为:(1,1)T(1,1)^T (2,1)T(2,1)^T
  • nn:格 L(B)\mathcal{L}(B) 的秩(rank)/ 维度(dimension),若 n=dn=d 成立,则称格 L(B)\mathcal{L}(B) 是满秩的

Info

BB 张成的向量空间(格的延展空间) span(B)span(B) 和格 L(B)\mathcal{L}(B) 的区别:(1)前者可以同任意的实数系数相乘,后者仅包含整数系数;(2)若 BB 是格 L(B)\mathcal{L}(B) 的基,则它也是由格张成的向量空间 span(B)span(B) 的基;反之不一定成立。

span(B)={Bx:xRn}span(B)=\{Bx:x \in \mathbb{R}^n\}

1.1 子格 sublattice

def 对任意格 Λ=L(B)\Lambda=\mathcal{L}(B),一个子格 Λ\Lambda^{\prime} 是格 Λ\Lambda 的子集,满足 ΛΛ\Lambda^{\prime} \subseteq \Lambda

2 基 Bases

def 若存在其他的矩阵 VZn×nV \in \mathbb{Z}^{n\times n} 使得 VU=UV=IVU=UV=I,则称整数方阵 UZn×nU \in \mathbb{Z}^{n\times n} 是可逆(invertible)的。

  • U1U^{-1}:对于每一个矩阵 VV,可逆矩阵 U1U^{-1} 必须是唯一的

  • GL(n,Z)GL(n, \mathbb{Z}):一般线性群(general linear group),表示矩阵乘法下的一个群,包含了形如 U1U^{-1} 的可逆整数矩阵。

Note

论文中经常出现的 bases,其实是 basis 的复数形式。即当提到 “bases” 时,通常是指多组基。i.e. 两个不同的格 L(B)\mathcal{L}(B)L(C)\mathcal{L}(C),每个格都有各自的基,那么这两组基可统称为 “bases”。

  • 因而,能够通过整数矩阵 UU 将格的基 BB 转换为对同一个格的任意一个其他的基。

  • 在实现时,这一部分操作通常是在本地用较简单的方式完成的。

def 对矩阵 BRd×nB \in \mathbb{R}^{d \times n} 上的基本(整数)列操作,为以下操作之一:(1)SWAP(i,jSWAP(i, j): 对于任意 iji \neq j,交换任意两个基向量 (bi,bj)(bj,bi)(b_i, b_j) \leftarrow (b_j, b_i);(2)INVERT(i)INVERT(i): 对于任意 ii ,改变基向量 bi(bi)b_i \leftarrow (-b_i) 的符号;(3)ADD(i,c,j)ADD(i, c, j): 对于任意 iji \neq jcZc \in \mathbb{Z},将一个基向量的整数倍加到另一个基向量 bi(bi+cbj)b_i \leftarrow (b_i + c \cdot b_j) 中。

  • 这里对矩阵的基本列操作 σ\sigma 均作用在右侧的矩阵,因此对于任意矩阵 BBAA,有 σ(BA)=Bσ(A)\sigma(B \cdot A) = B - \sigma(A)

  • 特别地,任意的基本列操作 σ\sigma 均对应于整数矩阵 σ(I)Zn×n\sigma(I) \in \mathbb{Z}^{n \times n} 的右乘,因为

σ(B)=σ(BI)=Bσ(I)\sigma(B)=\sigma(B \cdot I)=B \cdot \sigma(I)

由于单位矩阵 II 是可逆的,这样的基本列操作不会改变由 BB 生成的格。而对于更多的一系列列操作 σ=[σ1,...,σk]\sigma = [ \sigma_1, . . . , \sigma_k],同样可以表示为可逆矩阵的右乘 σ(I)=σ1(I)σ2(I)...σk(I)GL(n,Z)\sigma(I) = \sigma_1(I) \cdot \sigma_2(I) ... \sigma_k(I) \in GL(n, \mathbb{Z})。再结合上述定理可知,对同一个格有 L(B)=L(σ(B))\mathcal{L}(B) = \mathcal{L}(\sigma(B)),即可通过任意的列操作序列将原先格的基 BB 转化为等价的基 σ(B)\sigma(B)。换言之,任意的可逆矩阵 UGL(n,Z)U \in GL(n, \mathbb{Z}) 均可表示为一系列基本列操作的形式,也总能够通过对基 BB 的一系列基本列操作得到新的一组格基。

def 若det(B)=1\left|det(B)\right|=1,则矩阵 BZn×nB \in \mathbb{Z}^{n \times n} 是一个幺模(unimodular)矩阵。

  • 幺模矩阵:所有非零 r×rr \times r 子式等于 1 或 - 1 的整数矩阵

lem 任意 UGL(n,Z)U \in GL(n, \mathbb{Z}) 均为幺模矩阵。

  • 埃尔米特形式(Hermite normal form, HNF)的整数矩阵:i.e. 一个上三角矩阵,其中正对角元素 hi,i>0h_{i,i} > 0,所有其他非零元素 0hi,j<hi,i0 ≤ h_{i,j} < h_{i,i} 均为模同一行上的对应对角元素 hi,ih_{i,i} 后得到的。

theo 对任意一个满秩(nonsingular)的整数方阵 BZn×nB \in \mathbb{Z}^{n \times n} ,存在一系列基本整数列操作 σ\sigma,使得 σ(B)\sigma(B) 在 HNF 中。

  • 此操作基于扩展欧几里得算法

coro 对任意矩阵 UZn×nU \in \mathbb{Z}^{n \times n},下述条件是等价的:(1)对于一些基本列操作 σ\sigma,有 U=σ(I)U = \sigma(I);(2)UU 是可逆的,有 UGL(n,Z)U \in GL(n, \mathbb{Z}) ;(3)UU 是满秩的,有 det(U)=±1det(U)=\pm1

3 施密特正交化 Gram-Schmidt orthogonalization

def 通过将每一个向量投影其他向量的空间维度上,使得这组线性无关的向量 b1,b2,...,bnb_1,b_2,...,b_n转化为正交向量 b1,b2,...,bnb_1^*,b_2^*,...,b_n^*,即

bi=bi[b1,...,bi1]b_i^*=b_i\bot[b_1,...,b_{i-1}]

  • πi\pi_i:常用于表示第 ii 个向量向前 i1i-1 个基向量投影的映射关系,有 bi=πi(bi)b_i^*=\pi_i(b_i)
    coro
    (1)一般地,BB^* 不是格 L(B)\mathcal{L} (B) 的基,这是因为这组正交向量 BB^* 通常不属于格;(2)需要注意正交化中基向量的先后顺序,b1,b2,...,bnb_1,b_2,...,b_n的向量顺序不同,得到的正交向量 b1,b2,...,bnb_1^*,b_2^*,...,b_n^*也不同。
    i.e. 对向量 b1=(2,0)b_1=(2,0)b2=(1,2)b_2=(1,2),关于 [b1,b2][b_1,b_2] 的施密特正交化为 b1=b1,b2=b2b1=(1,2)b_1^*=b_1, b_2^*=b_2 \bot b_1=(1,2)。如图所示,此时正交向量 b2b_2^* 是不属于格 L(B)\mathcal{L}(B) 的。而反转顺序后,对 [b2,b1][b_2,b_1] 的施密特正交化为 b2=b2,b1=b1b2=(85,45)b_2^*=b_2, b_1^*=b_1 \bot b_2=(\frac{8}{5},-\frac{4}{5})


lem 对 B=[b1,b2,...,bn]B=[b_1,b_2,...,b_n] 的施密特正交化可由下述等式计算而得:

bi=bij<iμi,jbjwhereμi,j=bi,bjbj,bjb_i^*=b_i-\sum_{j < i}{\mu_{i, j}b_j^* \: where \: \mu_{i, j}=\frac{\langle b_i, b_j^*\rangle}{\langle b_j^*,b_j^*\rangle}}

  • BB 及其正交化矩阵 BB^* 满足 B=BTB=B^*T,其中 T=[1μ2,1μn,1 1μn,n11]T=\begin{bmatrix} 1 & \mu_{2,1} & \cdots & \mu_{n,1} \\ & \ddots & & \vdots\\ & \ & 1 & \mu_{n,n-1} \\ & & & 1\end{bmatrix}

4 格的行列式 The determinant

def 给定一个基 B=[b1,,bn]Rd×nB = [b_1, \dots, b_n] \in \mathbb{R}^{d \times n},与基 B 相关的基本平行多面体(fundamental parallelepiped)是集合 P(B)=BTn={i=1nxibii,0xi<1}P(B) = B \mathbb{T}^n = \left\{ \sum_{i=1}^{n} x_i \cdot b_i \mid \forall i, 0 \leq x_i < 1 \right\},其中 T=[0,1)\mathbb{T}= [0, 1) 是半开单位区间。

  • P(B)P(B):一组格基在 [0,1)[0,1) 中实系数组合生成的空间,是格的基本区(fundamental region):给定格 Λ\Lambda,在其生成空间 span(Λ)\text{span}(\Lambda) 中,如果通过格点 xΛx \in \LambdaSS 进行平移后的区域集合 {x+S:xΛ}\{x + S : x \in \Lambda\} 构成了 span(Λ)\text{span}(\Lambda) 的一个分割(partition),则该区域 Sspan(Λ)S \subset \text{span}(\Lambda) 称为格的基本区。

    • 分割(partition):SS 和它通过格点的所有平移 x+Sx + S 可以无重叠且无间隙地覆盖整个生成空间 span(Λ)\text{span}(\Lambda)
      coro 不同的基定义了不同的平行多面体,但不同平行多面体的体积总是相同的。

Note

格基本区的其他分割方式:

  • 正交(orthogonalized)平行多面体 P(B)P(B^*):由正交化基向量生成的平行多面体

  • 中心(centered)平行多面体 C(B)C(B):以原点为中心的平行多面体,将 P(B)P(B) 平移 12i=1nbi-\frac{1}{2} \sum_{i=1}^n b_i 单位后得到,满足

    C(B)=B[12,12)n=12i=1nbi+P(B)C(B) = B \cdot \left[-\frac{1}{2}, \frac{1}{2}\right)^n = -\frac{1}{2} \sum_{i=1}^n b_i + P(B)

  • 正交中心平行多面体 C(B)C(B^*):同样以原点为中心,将 P(B) 平移12i=1nbiP (B^*) 平移 -\frac {1}{2} \sum_{i=1}^n b_i^* 单位后得到,满足

    C(B)=B[12,12)n=12i=1nbi+P(B)C(B^*) = B^* \cdot \left[-\frac{1}{2}, \frac{1}{2}\right)^n = -\frac{1}{2} \sum_{i=1}^n b_i^* + P(B^*)

def 给定一个基 BRd×nB\in R^{d \times n} 及其施密特正交化 BB^*,格 Λ=L(B)\Lambda = \mathcal{L}(B) 的行列式(determinant)定义为与基 BB 相关联的基本平行多面体的 n 维体积,形如

det(Λ)=vol(P(B))=ibi\det(\Lambda) = \text{vol}(P(B)) = \prod_i \|b^*_i\|

  • 格的行列式等于格的基本区体积,且与所选择的基无关。即无论选择哪个基 BB,计算出的行列式 det(Λ)\det(\Lambda) 都是相同的。i.e. 如果两个基是由同一个格生成的,那么它们的格的行列式的值是相同的。

  • 行列式可以看作是空间中格点密度的倒数。对格 Λ\Lambda 和它的行列式 det(Λ)\det(\Lambda),在一个足够大的规则区域 AA 中,格点数目大约等于 AA 的体积除以行列式。
    i.e. 正交向量 b1,b2R2b_1,b_2 \in \mathbb{R}^2b1=2\|b_1\| = 2b2=3\|b_2\| = 3R2\mathbb{R}^2 上的格 Λ\Lambda 的行列式 det(Λ)=2×3=6\det(\Lambda)=2 \times 3=6,假设区域 AA 的面积为 60,则 AA 内大约有 606=10\frac{60}{6} = 10 个格点。

theo 阿达马不等式(Hadamard Inequality)对于任何格 Λ=L(B)\Lambda = \mathcal{L}(B),行列式 det(Λ)\det(\Lambda) 满足以下不等式:

det(Λ)ibi\det(\Lambda) \leq \prod_{i} \|b_i\|

  • 上界 bibi\|b_i^*\| \leq \|b_i\|:正交化后的基向量 bib_i^* 长度总是小于或等于原基向量 bib_i 的长度。这是因为 bib_i^* 仅保留了与先前的基向量正交的部分。

  • 正交基的平行多面体体积最大,因此行列式 det(Λ)\det(\Lambda) 在正交情况下达到最大值;对于非正交基,行列式(体积)会变小。

lem 对于任何格基 BRd×nB \in \mathbb{R}^{d \times n},格 Λ=L(B)\Lambda = \mathcal{L}(B) 的行列式可以通过以下方式计算:

det(Λ)=det(BTB)\det(\Lambda) = \sqrt{\det(B^T B)}

特别地,如果 BB 是一个 n×nn \times n 的满秩方阵,那么

det(Λ)=det(B)\det(\Lambda) = |\det(B)|

  • 为了在 PPTPPT 内计算格的行列式,还可使用上述更为简单的方法,其不涉及施密特正交化。具体计算是利用模运算和中国剩余定理完成的:先选择一些小的质数 p1,p2,,pkp_1, p_2, \dots, p_k,分别计算 det(B)\det(B) 在这些质数模数下的值。即对于每个质数 pip_i,计算 det(B)modpi\det(B)\mod p_i;再利用 CRT 将这些结果组合起来,恢复出 det(B)\det(B) 在更大整数模数下的值,并恢复出完整的行列式值。

  • 对基 BB 的格拉姆矩阵(Gram matrix)BTBB^TB:通过计算格拉姆矩阵的行列式并取平方根,能够得到基本平行多面体的体积。

  • BB 为一个方阵时,行列式直接反映了基向量生成的 n 维平行多面体的体积。因此,行列式的绝对值直接给出了格的行列式。

theo 假设 BBCC 是同一个格 Λ\Lambda 的两个基,即 Λ(B)=Λ(C)\Lambda(B) = \Lambda(C),那么有 vol(P(B))=vol(P(C))vol(P(B))=vol(P(C))

  • 两个不同基生成的同一个格的基本区体积相等。


注:
def - definition,定义
theo - theorem,定理
lem - lemma,引理
coro - corollary,推论



参考
[1] CSE206A Lec1, Daniele Micciancio
[2] 格密码的基础概念(1)
[3] 如何通俗地理解施密特正交化|马同学图解线性代数