NTRU 是目前据我所知的最快的抗量子加密算法(当然NTRU也有也有签名算法)。
关于算法的Introduction我就不多说了,如果你之前了解过NTRU,那么我写的不一定会比你所了解的多;如果没了解过,可以先去谷歌或维基了解一下,也可以参考其官网 上的文章。
NTRU到目前为止已经有很多版本,我参考的是[HPS14] 7.10 节的教科书版本,顺带一题,作者也是提出NTRU的三人(https://ntru.org/f/hps96.pdf)
参考:
[HPS14] Hoffstein J, Pipher J, Silverman J H, et al. An introduction to mathematical cryptography[M]. New York: springer, 2008.
PS:第一版好像是08年的,但我参考的是14年的第二版。
[HPS17] Hoffstein J, Pipher J, Schanck J M, et al. Choosing parameters for NTRUEncrypt[C]//Topics in Cryptology–CT-RSA 2017: The Cryptographers’ Track at the RSA Conference 2017, San Francisco, CA, USA, February 14–17, 2017, Proceedings. Springer International Publishing, 2017: 3-18.
PS:这篇主要讲的是参数设置。
要看懂下面的内容你可能需要:
数论知识(特别群论、环论);
线性代数知识,多项式运算等;
基础的密码学知识(起码你得知道加密算法是干什么的吧);
Sagemath代码的读写经验;
足够的耐心。
理论知识·
多项式环和参数选取·
首先[HPS14]的7.10.1节一开始就扔出了三个卷积多项式环(Convolution Polynomial Rings),R R R 、R p R_p R p 和R q R_q R q ,理解这三个环其实是理解NTRU的关键,接下来细说。
首先看R R R ,分子(姑且先叫分子吧)的Z [ x ] \mathbb{Z}[x] Z [ x ] 指的是整数域 上的多项式,以符号x x x 作为多项式的未知数,实际上也就是小学/初中开始接触的多项,比如x 2 + x + 1 x^2+x+1 x 2 + x + 1 、− 2 x 3 − x -2x^3-x − 2 x 3 − x 等。
然后,横线其实不是指除法,比起除法其实更像一个取余,或者叫商环(Quotient Ring,可以参考[HPS14]的2.10),大概意思是,“分子”上的多项式模上x N − 1 x^N-1 x N − 1 后就会落在R R R 上,其中N是NTRU的参数。其实跟RSA在Z n ∗ \mathbb{Z}_n^* Z n ∗ 中运算所以要模n n n 类似,可以做个类比方便理解。
举个栗子,假设取N = 2 N=2 N = 2 ,那就是R = Z [ x ] x 2 − 1 R = \frac{\mathbb{Z}[x]}{x^2-1} R = x 2 − 1 Z [ x ] ,现在尝试把Z [ x ] \mathbb{Z}[x] Z [ x ] 上的x 2 + x + 1 x^2+x+1 x 2 + x + 1 转换到R R R 上,由于“模数”是x 2 − 1 x^2-1 x 2 − 1 ,所以有
x 2 − 1 ≡ 0 ( in R ) \begin{aligned}
x^2-1 &\equiv 0 \ (\text{in } R)
\end{aligned}
x 2 − 1 ≡ 0 ( in R )
把这个关系利用到x 2 + x + 1 x^2+x+1 x 2 + x + 1 上可以得到:
x 2 + x + 1 ≡ x 2 + x + 1 − 0 ≡ x 2 + x + 1 − ( x 2 − 1 ) ≡ x + 2 ( in R ) \begin{aligned}
x^2+x+1 &\equiv x^2+x+1 - 0 \\
&\equiv x^2+x+1 - (x^2-1) \\
&\equiv x + 2 \ (\text{in } R)
\end{aligned}
x 2 + x + 1 ≡ x 2 + x + 1 − 0 ≡ x 2 + x + 1 − ( x 2 − 1 ) ≡ x + 2 ( in R )
x + 2 x+2 x + 2 就是最终落在R R R 上的结果。
另一个栗子,− 2 x 3 − x -2x^3-x − 2 x 3 − x ,这里偷一下懒,对其作分解后可以得到:
− 2 x 3 − x = − 2 ( x 2 − 1 ) ⋅ x − 3 x -2x^3-x = -2(x^2-1)·x - 3x
− 2 x 3 − x = − 2 ( x 2 − 1 ) ⋅ x − 3 x
所以有:
− 2 x 3 − x ≡ − 2 ( x 2 − 1 ) ⋅ x − 3 x ≡ − 2 ⋅ 0 − 3 x ≡ − 3 x ( in R ) \begin{aligned}
-2x^3-x &\equiv -2(x^2-1)·x - 3x \\
&\equiv -2·0 - 3x \\
&\equiv -3x \ (\text{in } R)
\end{aligned}
− 2 x 3 − x ≡ − 2 ( x 2 − 1 ) ⋅ x − 3 x ≡ − 2 ⋅ 0 − 3 x ≡ − 3 x ( in R )
一般来说R R R 中的多项式最高项不会大于等于N N N 次,因为x N ≡ 1 ( in R ) x^N \equiv 1 \ (\text{in } R) x N ≡ 1 ( in R ) ,所以每出现x N x^N x N 都可以用1 1 1 代替,可以利用这个方法检验最终结果的正确性(虽然我都是直接用Sage算的,逃)。
R p R_p R p 其实类似,只不过其“分子”( Z / p Z ) [ x ] (\mathbb{Z}/p\mathbb{Z})[x] ( Z / p Z ) [ x ] 是系数模p p p 的多项式,也就是多项式的系数需要进行模p p p 操作,使其落在Z p \mathbb{Z}_p Z p 中(Z / p Z \mathbb{Z}/p\mathbb{Z} Z / p Z 其实就是Z p \mathbb{Z}_p Z p 的另一种写法)。
举个栗子,设p = 3 p=3 p = 3 ,下面尝试把− 2 x 3 − x -2x^3-x − 2 x 3 − x 转换到( Z / p Z ) [ x ] (\mathbb{Z}/p\mathbb{Z})[x] ( Z / p Z ) [ x ] 中:
− 2 x 3 − x ≡ ( − 2 ( m o d p ) ) x 3 + ( − 1 ( m o d p ) ) x ≡ ( − 2 ( m o d 3 ) ) x 3 + ( − 1 ( m o d 3 ) ) x ≡ x 3 + 2 x ( in ( Z / p Z ) [ x ] ) \begin{aligned}
-2x^3-x
&\equiv (-2 \pmod p)x^3 + (-1 \pmod p)x \\
&\equiv (-2 \pmod 3)x^3 + (-1 \pmod 3)x \\
&\equiv x^3 + 2x \ (\text{in } (\mathbb{Z}/p\mathbb{Z})[x])
\end{aligned}
− 2 x 3 − x ≡ ( − 2 ( mod p )) x 3 + ( − 1 ( mod p )) x ≡ ( − 2 ( mod 3 )) x 3 + ( − 1 ( mod 3 )) x ≡ x 3 + 2 x ( in ( Z / p Z ) [ x ])
其实只是系数模p p p 。
然后R p R_p R p 中的取余操作和R R R 的类似,不再累赘。R q R_q R q 和R p R_p R p 类似,只是模数不同。
以上的N N N 、p p p 和q q q 是NTRU的公开参数,在[HPS14]中的参数要求是,N N N 为素数,且
g c d ( N , q ) = g c d ( p , q ) = 1 \rm{gcd}(N, q) = \rm{gcd}(p, q) = 1
gcd ( N , q ) = gcd ( p , q ) = 1
以下更详细的参数设置建议摘抄自[HPS17],大概意思是:p p p 一般取p = 3 p=3 p = 3 ,q q q 为了加快运算一般取2 2 2 的幂次方(盲猜是二进制有利于计算机优化),N N N 同样取素数,不过某些特殊版本的基于理想格 的NTRU会取形如N = 2 n N=2^n N = 2 n ,然后模数取x N + 1 x^N+1 x N + 1 ,这里超纲了,略。
三元多项式和密钥生成·
接下来会说到一个叫T \mathcal{T} T 的函数:
T \mathcal{T} T 的输入为两个整数d 1 d_1 d 1 和d 2 d_2 d 2 ,输出为一个三元多项式(Ternary Polynomial),三元即( − 1 , 0 , 1 ) (-1, 0, 1) ( − 1 , 0 , 1 ) ,大概意思是,T \mathcal{T} T 函数会采样一个符合条件:有d 1 d_1 d 1 个项系数为1 1 1 、有d 2 d_2 d 2 个项系数为− 1 -1 − 1 ,其余项系数为0 0 0 (即没有)的多项式,且这个多项式落在R R R 上。
接下来利用T \mathcal{T} T 采样密钥,首先是私钥 ,我就直接上图不再码一遍了:
其中的d d d 也是公开参数(上面也有说了),f ( x ) f(x) f ( x ) 和g ( x ) g(x) g ( x ) 是两个主要的私钥(甚至可以把g ( x ) g(x) g ( x ) 看作一个随机数),落在R R R 中(因为T \mathcal{T} T 的返回值落在R R R 中,先记住,后面会用到),F q ( x ) F_q(x) F q ( x ) 和F q ( x ) F_q(x) F q ( x ) 分别是f ( x ) f(x) f ( x ) 在R q R_q R q 和R p R_p R p 上的逆元,这里写出来的意思是,把F q ( x ) F_q(x) F q ( x ) 和F q ( x ) F_q(x) F q ( x ) 存储起来可以加快运算速度,因为计算多项式环的逆元需要一段时间(虽然也不是很久)。
多嘴说一句,f ( x ) f(x) f ( x ) 取自T ( d + 1 , d ) \mathcal{T}(d+1, d) T ( d + 1 , d ) 是因为需要f ( x ) f(x) f ( x ) 可逆,书中有提到T ( d , d ) \mathcal{T}(d, d) T ( d , d ) 的不可逆,也可以自己推一遍。
这里隐藏的一个信息是,R R R 上的多项式可以转换到R q R_q R q 或R p R_p R p 中 ,系数模q q q 或者模p p p 而已,挺显然的,略。
然后计算公钥 :
换一种写法其实也就是:
h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q h(x) \equiv f(x)^{-1} · g(x) \ \text{in } R_q
h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q
Center-lift和加解密·
首先说Center-lift,上面说了,R R R 上的多项式可以转换到R q R_q R q 或R p R_p R p 中,而Center-lift则是把R q R_q R q 或R p R_p R p 中的多项式转换回R R R 中,而且使得多项式系数的绝对值最小(相比于其他的转换方式)。
Center-lift的定义可以看[HSP14]的7.9节,主要是针对多项式系数的操作,可以和补码类比。
上面假设是R q R_q R q 多项式的Center-lift,即R q R_q R q 转换到R R R 。上图的a ( x ) a(x) a ( x ) 为R q R_q R q 上的一个多项式,a ′ ( x ) a'(x) a ′ ( x ) 为其Center-lift到R R R 后的结果,a i a_i a i 为a ( x ) a(x) a ( x ) 的i i i 次项系数,a i ′ a_i' a i ′ 为a ′ ( x ) a'(x) a ′ ( x ) 的i i i 次项系数。
Center-lift后的结果是,所有的系数a i ′ a_i' a i ′ 会落在区间( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ,而且还能保证a i ′ ≡ a i ( m o d q ) a_i' \equiv a_i \pmod q a i ′ ≡ a i ( mod q ) 。
Center-lift的方法也不难,和转补码类似,在q 2 \frac{q}{2} 2 q 砍一半,小于等于q 2 \frac{q}{2} 2 q 的不动,大于q 2 \frac{q}{2} 2 q 的平移到( − q 2 , 0 ) (-\frac{q}{2}, 0) ( − 2 q , 0 ) ,也就是:
a i ′ = { a i , if 0 ≤ a i ≤ q 2 a i − q , if q 2 < a i < q a_i' =
\begin{cases}
a_i, & \text {if $0 \le a_i \le \frac{q}{2}$} \\
a_i - q, & \text {if $\frac{q}{2} < a_i < q $}
\end{cases}
a i ′ = { a i , a i − q , if 0 ≤ a i ≤ 2 q if 2 q < a i < q
检验一下,上面的划分可以覆盖整个Z q \mathbb{Z}_q Z q ,当0 ≤ a i ≤ q 2 0 \le a_i \le \frac{q}{2} 0 ≤ a i ≤ 2 q 时显然a i ′ ≡ a i ( m o d q ) a_i' \equiv a_i \pmod q a i ′ ≡ a i ( mod q ) ,而且落在( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ;q 2 < a i < q \frac{q}{2} < a_i < q 2 q < a i < q 时,a i ′ ≡ a i − q ≡ a i − 0 ≡ a i ( m o d q ) a_i' \equiv a_i - q \equiv a_i - 0 \equiv a_i \pmod q a i ′ ≡ a i − q ≡ a i − 0 ≡ a i ( mod q ) ,由于a i a_i a i 落在( q 2 , q ) (\frac{q}{2}, q) ( 2 q , q ) ,所以a i ′ ≡ a i − q a_i' \equiv a_i - q a i ′ ≡ a i − q 落在( q 2 − q , q − q ) (\frac{q}{2}-q, q-q) ( 2 q − q , q − q ) ,也即( − q 2 , 0 ) (-\frac{q}{2}, 0) ( − 2 q , 0 ) ,自然落在( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ,检验通过。
然后接着看加密,明文空间是R p R_p R p 做Center-lift后的空间,也即在R R R 上,系数取值落在( − p 2 , p 2 ] (-\frac{p}{2}, \frac{p}{2}] ( − 2 p , 2 p ] 的空间,加密使用的随机数r ( x ) r(x) r ( x ) 在T ( d , d ) \mathcal{T}(d, d) T ( d , d ) 中采样,然后加密操作就是下图的公式,密文是e ( x ) e(x) e ( x ) 。
在继续解密操作前,先分析一下密文的结构。
首先如果要解密的话,其实只用把p ⋅ h ( x ) ⋅ r ( x ) p·h(x)·r(x) p ⋅ h ( x ) ⋅ r ( x ) 这一项去除,先剧透一下,由于p ≡ 0 in R p p \equiv 0 \ \text{in } R_p p ≡ 0 in R p ,所以直观上把e ( x ) e(x) e ( x ) 放入R p R_p R p 中就可以把p ⋅ h ( x ) ⋅ r ( x ) p·h(x)·r(x) p ⋅ h ( x ) ⋅ r ( x ) 去除,而由于明文空间是R p R_p R p 做Center-lift后的空间,所以把m ( x ) in R q m(x) \ \text{in }R_q m ( x ) in R q 放入R p R_p R p 中并不会改变m ( x ) m(x) m ( x ) 的结构,即可以恢复明文。
剩下的问题是我其实并不能保证[ e ( x ) ( m o d q ) ] ≡ e ( x ) ( m o d p ) [e(x) \pmod q] \equiv e(x) \pmod p [ e ( x ) ( mod q )] ≡ e ( x ) ( mod p ) ,除非q = k p q = kp q = k p (这种情况在前几天讲OU98 时有讲过),但因为g c d ( p , q ) = 1 \rm{gcd}(p, q) = 1 gcd ( p , q ) = 1 ,所以这种情况并不存在。
这样的栗子可以举很多,可以直接看整数的栗子(反正也是模在多项式系数上),设e = 65537 e=65537 e = 65537 、q = 512 q=512 q = 512 、p = 3 p=3 p = 3 ,计算可得
( e ( m o d q ) ) ( m o d p ) = ( 65537 ( m o d 512 ) ) ( m o d 3 ) = 1 ( m o d 3 ) = 1 e ( m o d p ) = 65537 ( m o d 3 ) = 2 \begin{aligned}
(e \pmod q) \pmod p = (65537 \pmod {512}) \pmod 3 = 1 \pmod 3 &= 1 \\
e \pmod p = 65537 \pmod 3 &= 2
\end{aligned}
( e ( mod q )) ( mod p ) = ( 65537 ( mod 512 )) ( mod 3 ) = 1 ( mod 3 ) e ( mod p ) = 65537 ( mod 3 ) = 1 = 2
显然不等,也即R q R_q R q 不能直接转换到R p R_p R p 上。
但是前面说过,R R R 可以转换到R p R_p R p 上,所以可以考虑先把e ( x ) e(x) e ( x ) 转换(Center-lift)到R R R 上,然后再转到R p R_p R p 上。
但新的问题是,直接把R q R_q R q 上的e ( x ) e(x) e ( x ) 转到R R R 上,其结果不一定是原来R R R 上的e ( x ) e(x) e ( x ) ,举个整数域上的栗子即65537 ( m o d 512 ) = 1 ≠ 65537 65537 \pmod {512} = 1 \ne 65537 65537 ( mod 512 ) = 1 = 65537 ,除了一种情况,即把e ( x ) e(x) e ( x ) 放在R R R 上运算后的系数本来就落在( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ,也即R q R_q R q 上的元素做Center-lift后的区间。
在讲如何把e ( x ) e(x) e ( x ) 系数转化到( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] 前,可能先需要了解一下多项式的乘法。
多项式卷积乘法·
在继续讲解密思路前,先“简要”介绍一下多项式卷积。
在这篇 我曾经写过,多项式的卷积乘法可以看成一个矩阵操作,这里多嘴推导一下这个矩阵是怎么来的,如果不关心推导则可以跳过 。
下面假设f ( x ) f(x) f ( x ) 和g ( x ) g(x) g ( x ) 在R R R 中相乘(假设而已),先把多项式表述为:
f ( x ) ≡ ∑ i = 0 N − 1 f i x i g ( x ) ≡ ∑ i = 0 N − 1 g i x i f(x) \equiv \sum^{N-1}_{i=0} f_i x^i \\
g(x) \equiv \sum^{N-1}_{i=0} g_i x^i
f ( x ) ≡ i = 0 ∑ N − 1 f i x i g ( x ) ≡ i = 0 ∑ N − 1 g i x i
那么有(参考多项式乘法,用分配律推也行):
f ( x ) ⋅ g ( x ) ≡ ∑ i = 0 N − 1 ( f i x i ∑ j = 0 N − 1 g j x j ) ≡ ∑ i = 0 N − 1 ∑ j = 0 N − 1 f i x i g j x j ≡ ∑ i = 0 N − 1 ∑ j = 0 N − 1 f i g j x i + j (in R ) \begin{aligned}
f(x) · g(x)
&\equiv \sum^{N-1}_{i=0} (f_i x^i \sum^{N-1}_{j=0} g_j x^j) \\
&\equiv \sum^{N-1}_{i=0} \sum^{N-1}_{j=0} f_i x^i g_j x^j \\
&\equiv \sum^{N-1}_{i=0} \sum^{N-1}_{j=0} f_i g_j x^{i+j}
\ \text{(in $R$)}
\end{aligned}
f ( x ) ⋅ g ( x ) ≡ i = 0 ∑ N − 1 ( f i x i j = 0 ∑ N − 1 g j x j ) ≡ i = 0 ∑ N − 1 j = 0 ∑ N − 1 f i x i g j x j ≡ i = 0 ∑ N − 1 j = 0 ∑ N − 1 f i g j x i + j (in R )
由于f ( x ) ⋅ g ( x ) f(x) · g(x) f ( x ) ⋅ g ( x ) 的结果肯定也是个多项式(封闭性),所以先把上面结构调整到像一个多项式,即合并次数相同的项(注意f ( x ) f(x) f ( x ) 和g ( x ) g(x) g ( x ) 最高项只能是x N − 1 x^{N-1} x N − 1 ,所以不考虑模的时候乘起来最高项只能是x N − 1 ⋅ x N − 1 = x 2 ( N − 1 ) x^{N-1} · x^{N-1} = x^{2(N - 1)} x N − 1 ⋅ x N − 1 = x 2 ( N − 1 ) ,然后小于N N N 次的项和大于等于N N N 次的项分开处理):
f ( x ) ⋅ g ( x ) ≡ ∑ i = 0 N − 1 ∑ j = 0 N − 1 f i g j x i + j ≡ ∑ k = 0 N − 1 ( ( ∑ i = 0 k f i g k − i ) ⋅ x k ) + ∑ k = N 2 ( N − 1 ) ( ( ∑ i = k − ( N − 1 ) N − 1 f i g k − i ) ⋅ x k ) (in R ) \begin{aligned}
f(x) · g(x)
&\equiv \sum^{N-1}_{i=0} \sum^{N-1}_{j=0} f_i g_j x^{i+j} \\
\\
&\equiv \sum^{N-1}_{k=0} ((\sum^{k}_{i=0} f_{i} g_{k-i}) · x^k)
+ \sum^{2(N-1)}_{k=N} ((\sum^{N-1}_{i=k-(N-1)} f_{i} g_{k-i}) · x^k)
\ \text{(in $R$)}
\end{aligned}
f ( x ) ⋅ g ( x ) ≡ i = 0 ∑ N − 1 j = 0 ∑ N − 1 f i g j x i + j ≡ k = 0 ∑ N − 1 (( i = 0 ∑ k f i g k − i ) ⋅ x k ) + k = N ∑ 2 ( N − 1 ) (( i = k − ( N − 1 ) ∑ N − 1 f i g k − i ) ⋅ x k ) (in R )
最开始讲环的时候说到,R R R 是模x N − 1 x^N-1 x N − 1 的,所以x N ≡ 1 ≡ x 0 (in R ) x^N \equiv 1 \equiv x^0 \ \text{(in }R \text{)} x N ≡ 1 ≡ x 0 (in R ) ,所以有
x N + i ≡ x i (in R ) x^{N + i} \equiv x^i \ \text{(in $R$)}
x N + i ≡ x i (in R )
即未知数x x x 的指数部分需要模N N N ,所以可以继续化简:
f ( x ) ⋅ g ( x ) ≡ ∑ k = 0 N − 1 ( ( ∑ i = 0 k f i g k − i ) ⋅ x k ) + ∑ k = N 2 ( N − 1 ) ( ( ∑ i = k − ( N − 1 ) N − 1 f i g k − i ) ⋅ x k − N ) ≡ ∑ k = 0 N − 1 ( ( ∑ i = 0 k f i g k − i ) ⋅ x k ) + ∑ k = 0 N − 2 ( ( ∑ i = ( k + N ) − ( N − 1 ) N − 1 f i g ( k + N ) − i ) ⋅ x k ) ≡ ∑ k = 0 N − 1 ( ( ∑ i = 0 k f i g k − i ) ⋅ x k ) + ∑ k = 0 N − 1 ( ( ∑ i = k + 1 N − 1 f i g k + N − i ) ⋅ x k ) ≡ ∑ k = 0 N − 1 ( ∑ i = 0 k f i g k − i + ∑ i = k + 1 N − 1 f i g k + N − i ) ⋅ x k ≡ ∑ k = 0 N − 1 ( ∑ i = 0 N − 1 f i g k − i ( m o d N ) ) ⋅ x k (in R ) \begin{aligned}
f(x) · g(x)
&\equiv \sum^{N-1}_{k=0} ((\sum^{k}_{i=0} f_{i} g_{k-i}) · x^k)
+ \sum^{2(N-1)}_{k=N} ((\sum^{N-1}_{i=k-(N-1)} f_{i} g_{k-i}) · x^{k-N}) \\
&\equiv \sum^{N-1}_{k=0} ((\sum^{k}_{i=0} f_{i} g_{k-i}) · x^k)
+ \sum^{N-2}_{k=0} ((\sum^{N-1}_{i=(k+N)-(N-1)} f_{i} g_{(k+N)-i}) · x^k) \\
&\equiv \sum^{N-1}_{k=0} ((\sum^{k}_{i=0} f_{i} g_{k-i}) · x^k)
+ \sum^{N-1}_{k=0} ((\sum^{N-1}_{i=k+1} f_{i} g_{k+N-i}) · x^k) \\
&\equiv \sum^{N-1}_{k=0} (\sum^{k}_{i=0} f_{i} g_{k-i} + \sum^{N-1}_{i=k+1} f_{i} g_{k+N-i}) · x^k \\
&\equiv \sum^{N-1}_{k=0} (\sum^{N-1}_{i=0} f_{i} g_{k-i \pmod N}) · x^k
\ \text{(in $R$)}
\end{aligned}
f ( x ) ⋅ g ( x ) ≡ k = 0 ∑ N − 1 (( i = 0 ∑ k f i g k − i ) ⋅ x k ) + k = N ∑ 2 ( N − 1 ) (( i = k − ( N − 1 ) ∑ N − 1 f i g k − i ) ⋅ x k − N ) ≡ k = 0 ∑ N − 1 (( i = 0 ∑ k f i g k − i ) ⋅ x k ) + k = 0 ∑ N − 2 (( i = ( k + N ) − ( N − 1 ) ∑ N − 1 f i g ( k + N ) − i ) ⋅ x k ) ≡ k = 0 ∑ N − 1 (( i = 0 ∑ k f i g k − i ) ⋅ x k ) + k = 0 ∑ N − 1 (( i = k + 1 ∑ N − 1 f i g k + N − i ) ⋅ x k ) ≡ k = 0 ∑ N − 1 ( i = 0 ∑ k f i g k − i + i = k + 1 ∑ N − 1 f i g k + N − i ) ⋅ x k ≡ k = 0 ∑ N − 1 ( i = 0 ∑ N − 1 f i g k − i ( mod N ) ) ⋅ x k (in R )
其中的∑ i = 0 N − 1 f i g k − i ( m o d N ) \sum^{N-1}_{i=0} f_{i} g_{k-i \pmod N} ∑ i = 0 N − 1 f i g k − i ( mod N ) 即为f ( x ) ⋅ g ( x ) f(x) · g(x) f ( x ) ⋅ g ( x ) 的k k k 次项系数。
粗略检验一下正确性,设f ( x ) = x 2 + 2 x + 3 f(x)=x^2+2x + 3 f ( x ) = x 2 + 2 x + 3 、g ( x ) = 3 x 2 + 2 x + 1 g(x) = 3x^2 + 2x + 1 g ( x ) = 3 x 2 + 2 x + 1 、N = 3 N=3 N = 3 ,则:
f ( x ) ⋅ g ( x ) ≡ ( x 2 + 2 x + 3 ) ⋅ ( 3 x 2 + 2 x + 1 ) ≡ 3 x 4 + 8 x 3 + 14 x 2 + 8 x + 3 ≡ 3 x + 8 + 14 x 2 + 8 x + 3 ≡ 14 x 2 + 11 x + 11 (in R ) \begin{aligned}
f(x) · g(x)
&\equiv (x^2+2x + 3) · (3x^2 + 2x + 1) \\
&\equiv 3 x^4 + 8 x^3 + 14 x^2 + 8 x + 3 \\
&\equiv 3x + 8 + 14x^2 + 8x + 3 \\
&\equiv 14x^2 + 11x + 11
\ \text{(in $R$)}
\end{aligned}
f ( x ) ⋅ g ( x ) ≡ ( x 2 + 2 x + 3 ) ⋅ ( 3 x 2 + 2 x + 1 ) ≡ 3 x 4 + 8 x 3 + 14 x 2 + 8 x + 3 ≡ 3 x + 8 + 14 x 2 + 8 x + 3 ≡ 14 x 2 + 11 x + 11 (in R )
∑ k = 0 N − 1 ( ∑ i = 0 N − 1 f i g k − i ( m o d N ) ) ⋅ x k ≡ ∑ k = 0 2 ( ∑ i = 0 2 f i g k − i ( m o d 3 ) ) ⋅ x k ≡ ( ∑ i = 0 2 f i g 0 − i ( m o d 3 ) ) ⋅ x 0 + ( ∑ i = 0 2 f i g 1 − i ( m o d 3 ) ) ⋅ x 1 + ( ∑ i = 0 2 f i g 2 − i ( m o d 3 ) ) ⋅ x 2 ≡ ( f 0 g 0 + f 1 g 2 + f 2 g 1 ) ⋅ x 0 + ( f 0 g 1 + f 1 g 0 + f 2 g 2 ) ⋅ x 1 + ( f 0 g 2 + f 1 g 1 + f 2 g 0 ) ⋅ x 2 ≡ ( 3 ⋅ 1 + 2 ⋅ 3 + 1 ⋅ 2 ) ⋅ x 0 + ( 3 ⋅ 2 + 2 ⋅ 1 + 1 ⋅ 3 ) ⋅ x 1 + ( 3 ⋅ 3 + 2 ⋅ 2 + 1 ⋅ 1 ) ⋅ x 2 ≡ 14 x 2 + 11 x 1 + 11 x 0 ≡ 14 x 2 + 11 x + 11 (in R ) \begin{aligned}
&\sum^{N-1}_{k=0} (\sum^{N-1}_{i=0} f_{i} g_{k-i \pmod N}) · x^k \\
\equiv &\sum^{2}_{k=0} (\sum^{2}_{i=0} f_{i} g_{k-i \pmod 3}) · x^k \\
\equiv &(\sum^{2}_{i=0} f_{i} g_{0-i \pmod 3}) · x^0
+ (\sum^{2}_{i=0} f_{i} g_{1-i \pmod 3}) · x^1
+ (\sum^{2}_{i=0} f_{i} g_{2-i \pmod 3}) · x^2 \\
\equiv &(f_0 g_0 + f_1 g_2 + f_2 g_1) · x^0
+ (f_0 g_1 + f_1 g_0 + f_2 g_2) · x^1
+ (f_0 g_2 + f_1 g_1 + f_2 g_0) · x^2 \\
\equiv &(3·1 + 2·3 + 1·2) · x^0
+ (3·2 + 2·1 + 1·3) · x^1
+ (3·3 + 2·2 + 1·1) · x^2 \\
\equiv &14x^2 + 11x^1 + 11x^0 \\
\equiv &14x^2 + 11x + 11
\ \text{(in $R$)}
\end{aligned}
≡ ≡ ≡ ≡ ≡ ≡ k = 0 ∑ N − 1 ( i = 0 ∑ N − 1 f i g k − i ( mod N ) ) ⋅ x k k = 0 ∑ 2 ( i = 0 ∑ 2 f i g k − i ( mod 3 ) ) ⋅ x k ( i = 0 ∑ 2 f i g 0 − i ( mod 3 ) ) ⋅ x 0 + ( i = 0 ∑ 2 f i g 1 − i ( mod 3 ) ) ⋅ x 1 + ( i = 0 ∑ 2 f i g 2 − i ( mod 3 ) ) ⋅ x 2 ( f 0 g 0 + f 1 g 2 + f 2 g 1 ) ⋅ x 0 + ( f 0 g 1 + f 1 g 0 + f 2 g 2 ) ⋅ x 1 + ( f 0 g 2 + f 1 g 1 + f 2 g 0 ) ⋅ x 2 ( 3 ⋅ 1 + 2 ⋅ 3 + 1 ⋅ 2 ) ⋅ x 0 + ( 3 ⋅ 2 + 2 ⋅ 1 + 1 ⋅ 3 ) ⋅ x 1 + ( 3 ⋅ 3 + 2 ⋅ 2 + 1 ⋅ 1 ) ⋅ x 2 14 x 2 + 11 x 1 + 11 x 0 14 x 2 + 11 x + 11 (in R )
检验通过。
以下用矩阵的形式表达∑ k = 0 N − 1 ( ∑ i = 0 N − 1 f i g k − i ( m o d N ) ) ⋅ x k \sum^{N-1}_{k=0} (\sum^{N-1}_{i=0} f_{i} g_{k-i \pmod N}) · x^k ∑ k = 0 N − 1 ( ∑ i = 0 N − 1 f i g k − i ( mod N ) ) ⋅ x k ,姑且记f ( x ) ⋅ g ( x ) f(x)·g(x) f ( x ) ⋅ g ( x ) 的i i i 次项系数为λ i \lambda_i λ i ,即为
( f 0 , f 1 , . . . , f N − 1 ) ⋅ ( g 0 g 1 g 2 ⋯ g N − 1 g N − 1 g 0 g 1 ⋯ g N − 2 g N − 2 g N − 1 g 0 ⋯ g N − 3 ⋮ ⋮ ⋮ ⋱ ⋮ g 1 g 2 g 3 ⋯ g 0 ) = ( λ 0 , λ 1 , . . . , λ N − 1 ) (in R ) (f_0, f_1, ..., f_{N-1}) ·
\begin{pmatrix}
g_0 & g_1 & g_2 & \cdots & g_{N-1} \\
g_{N-1} & g_0 & g_1 & \cdots & g_{N-2} \\
g_{N-2} & g_{N-1} & g_0 & \cdots & g_{N-3} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
g_1 & g_2 & g_3 & \cdots & g_0 \\
\end{pmatrix} \\
= (\lambda_0, \lambda_1, ..., \lambda_{N-1})\ \ \text{(in $R$)}
( f 0 , f 1 , ... , f N − 1 ) ⋅ ⎝ ⎛ g 0 g N − 1 g N − 2 ⋮ g 1 g 1 g 0 g N − 1 ⋮ g 2 g 2 g 1 g 0 ⋮ g 3 ⋯ ⋯ ⋯ ⋱ ⋯ g N − 1 g N − 2 g N − 3 ⋮ g 0 ⎠ ⎞ = ( λ 0 , λ 1 , ... , λ N − 1 ) (in R )
解密与参数关系计算·
首先直接贴解密过程,
公式推导我也懒得再码一遍了,直接截图:
现在的目标是要把e ( x ) e(x) e ( x ) 的系数转化到( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] 区间,而观察e ( x ) e(x) e ( x ) 的结构可发现,要达成这个目标最大的阻碍是h ( x ) h(x) h ( x ) ,因为h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q h(x) \equiv f(x)^{-1} · g(x) \ \text{in } R_q h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q ,其中的f ( x ) − 1 f(x)^{-1} f ( x ) − 1 取逆操作会把系数“打乱”,从而产生很大(q q q 规模)的系数,所以需要想方法消去。
消去方法如上面a ( x ) a(x) a ( x ) 的推导,乘上一个f ( x ) f(x) f ( x ) ,把h ( x ) h(x) h ( x ) 转换成g ( x ) g(x) g ( x ) ,g ( x ) ∈ T ( d , d ) g(x) \in \mathcal{T}(d, d) g ( x ) ∈ T ( d , d ) ,其系数只会是小系数− 1 -1 − 1 、0 0 0 或1 1 1 。
虽然消去h ( x ) h(x) h ( x ) ,但其实还不能保证a ( x ) a(x) a ( x ) 的绝对值系数严格落在( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ,所以接下来需要先计算a ( x ) a(x) a ( x ) 的最大和最小系数,计算方法稍微引用下原文:
可以把a ( x ) a(x) a ( x ) 分成两部分,即“+”分割的p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) 和f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 。
首先看p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) 的最大和最小系数,由于p p p 是常数,所以可以先看g ( x ) ⋅ r ( x ) g(x) · r(x) g ( x ) ⋅ r ( x ) ,翻看上面内容,g ( x ) g(x) g ( x ) 和r ( x ) r(x) r ( x ) 都采样自T ( d , d ) \mathcal{T}(d, d) T ( d , d ) ,即只有d d d 个系数为1 1 1 的项和d d d 个系数为− 1 -1 − 1 的项,其余项系数为0 0 0 。
上一节已经推出了,∑ i = 0 N − 1 g i r k − i ( m o d N ) \sum^{N-1}_{i=0} g_{i} r_{k-i \pmod N} ∑ i = 0 N − 1 g i r k − i ( mod N ) 为g ( x ) ⋅ r ( x ) g(x) · r(x) g ( x ) ⋅ r ( x ) 的k k k 次项系数,由于g i r k − i ( m o d N ) g_{i} r_{k-i \pmod N} g i r k − i ( mod N ) 只会在g i g_{i} g i 和r k − i ( m o d N ) r_{k-i \pmod N} r k − i ( mod N ) 都取1 1 1 或者都取− 1 -1 − 1 时可以取得最大值1 1 1 ,所以在拥有最多的g i r k − i ( m o d N ) g_{i} r_{k-i \pmod N} g i r k − i ( mod N ) 出现最大值1 1 1 的情况下g ( x ) ⋅ r ( x ) g(x) · r(x) g ( x ) ⋅ r ( x ) 的k k k 次项系数出现最大值,这个情况即是:值为1 1 1 的g i g_{i} g i 刚好匹配上值为1 1 1 的r k − i ( m o d N ) r_{k-i \pmod N} r k − i ( mod N ) 、值为− 1 -1 − 1 的g i g_{i} g i 刚好匹配上值为− 1 -1 − 1 的r k − i ( m o d N ) r_{k-i \pmod N} r k − i ( mod N ) 、且值为0 0 0 的g i g_{i} g i 刚好匹配上值为0 0 0 的r k − i ( m o d N ) r_{k-i \pmod N} r k − i ( mod N ) 的情况,产生的最大值是2 d 2d 2 d 。
再把常数p p p 考虑进去,即p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) 的最大值是p ⋅ 2 d p·2d p ⋅ 2 d 。
类似地,当1 1 1 和− 1 -1 − 1 匹配上的时候,g i r k − i ( m o d N ) g_{i} r_{k-i \pmod N} g i r k − i ( mod N ) 出现最小值− 1 -1 − 1 ,即得p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) 的最小值是− p ⋅ 2 d -p·2d − p ⋅ 2 d 。
再来看f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 得最大和最小系数,f ( x ) f(x) f ( x ) 采样自T ( d + 1 , d ) \mathcal{T}(d+1, d) T ( d + 1 , d ) ,即有d + 1 d+1 d + 1 个项系数为1 1 1 、有d d d 个项系数为− 1 -1 − 1 、其余项为0 0 0 ;m ( x ) m(x) m ( x ) 的系数落在( − p 2 , p 2 ] (-\frac{p}{2}, \frac{p}{2}] ( − 2 p , 2 p ] ,即R p R_p R p 做Center-lift后的区间。
类似地,∑ i = 0 N − 1 f i m k − i ( m o d N ) \sum^{N-1}_{i=0} f_{i} m_{k-i \pmod N} ∑ i = 0 N − 1 f i m k − i ( mod N ) 为f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 的k k k 次项系数,f i m k − i ( m o d N ) f_{i} m_{k-i \pmod N} f i m k − i ( mod N ) 只会在f i f_{i} f i 取1 1 1 、m k − i ( m o d N ) m_{k-i \pmod N} m k − i ( mod N ) 取p 2 \frac{p}{2} 2 p 时和在f i f_{i} f i 取− 1 -1 − 1 、m k − i ( m o d N ) m_{k-i \pmod N} m k − i ( mod N ) 取− p 2 -\frac{p}{2} − 2 p (虽然取不到,但可以用来计算界)时取得最大值p 2 \frac{p}{2} 2 p ,这些情况总共可以出现( d + 1 ) + d (d+1)+d ( d + 1 ) + d 次(f ( x ) f(x) f ( x ) 中1 1 1 的个数加上− 1 -1 − 1 的个数),所以f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 的系数最大值是( 2 d + 1 ) ⋅ p 2 (2d+1) · \frac{p}{2} ( 2 d + 1 ) ⋅ 2 p 。
再类似地,在f i f_{i} f i 取1 1 1 、m k − i ( m o d N ) m_{k-i \pmod N} m k − i ( mod N ) 取− p 2 -\frac{p}{2} − 2 p 时和在f i f_{i} f i 取− 1 -1 − 1 、m k − i ( m o d N ) m_{k-i \pmod N} m k − i ( mod N ) 取p 2 \frac{p}{2} 2 p 时,f i m k − i ( m o d N ) f_{i} m_{k-i \pmod N} f i m k − i ( mod N ) 取得最小值− p 2 -\frac{p}{2} − 2 p ,总可出现( 2 d + 1 ) (2d+1) ( 2 d + 1 ) 次,所以所以f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 的系数最小值是− ( 2 d + 1 ) ⋅ p 2 -(2d+1) · \frac{p}{2} − ( 2 d + 1 ) ⋅ 2 p 。
最后a ( x ) a(x) a ( x ) 的最大系数就是p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) 和f ( x ) ⋅ m ( x ) f(x) · m(x) f ( x ) ⋅ m ( x ) 两部分的最大系数之和,即
p ⋅ 2 d + ( 2 d + 1 ) ⋅ p 2 = 3 d p + p 2 = ( 3 d + 1 2 ) ⋅ p p·2d + (2d+1) · \frac{p}{2} = 3dp + \frac{p}{2} = (3d + \frac{1}{2}) · p
p ⋅ 2 d + ( 2 d + 1 ) ⋅ 2 p = 3 d p + 2 p = ( 3 d + 2 1 ) ⋅ p
同理,最小系数是− ( 3 d + 1 2 ) ⋅ p -(3d + \frac{1}{2}) · p − ( 3 d + 2 1 ) ⋅ p 。(希望到这里还没看晕,逃)
接下来,要保证a ( x ) a(x) a ( x ) 的系数落在( − q 2 , q 2 ] (-\frac{q}{2}, \frac{q}{2}] ( − 2 q , 2 q ] ,只需要保证其最大系数严格小于q 2 \frac{q}{2} 2 q 且最小系数严格大于− q 2 -\frac{q}{2} − 2 q 即可,(经过上面计算可发现其实这两个是等价的,多了个负号而已),所以即需要保证:
( 3 d + 1 2 ) ⋅ p < q 2 (3d + \frac{1}{2}) · p < \frac{q}{2}
( 3 d + 2 1 ) ⋅ p < 2 q
化简也即:
( 6 d + 1 ) ⋅ p < q (6d+1)·p < q
( 6 d + 1 ) ⋅ p < q
即需要在设置四个公开参数时保证以上关系,才能让a ( x ) a(x) a ( x ) 正确地转换到R R R 上,保证解密的正确性。
接着按前文说的,现在a ( x ) a(x) a ( x ) 在R R R 上,可以转换到R p R_p R p 上以消除p ⋅ g ( x ) ⋅ r ( x ) p · g(x) · r(x) p ⋅ g ( x ) ⋅ r ( x ) :
a ( x ) ≡ p ⋅ g ( x ) ⋅ r ( x ) + f ( x ) ⋅ m ( x ) ≡ f ( x ) ⋅ m ( x ) (in R p ) a(x)
\equiv p · g(x) · r(x) + f(x) · m(x) \equiv f(x) · m(x) \ \text{(in $R_p$)}
a ( x ) ≡ p ⋅ g ( x ) ⋅ r ( x ) + f ( x ) ⋅ m ( x ) ≡ f ( x ) ⋅ m ( x ) (in R p )
为了恢复出m ( x ) m(x) m ( x ) 还需要消去f ( x ) f(x) f ( x ) ,这直接乘上f − 1 ( x ) f^{-1}(x) f − 1 ( x ) 即可:
b ( x ) ≡ F p ( x ) ⋅ a ( x ) ≡ f − 1 ( x ) ⋅ f ( x ) ⋅ m ( x ) ≡ m ( x ) (in R p ) b(x)
\equiv F_p(x) · a(x)
\equiv f^{-1}(x) · f(x) · m(x)
\equiv m(x)
\ \text{(in $R_p$)}
b ( x ) ≡ F p ( x ) ⋅ a ( x ) ≡ f − 1 ( x ) ⋅ f ( x ) ⋅ m ( x ) ≡ m ( x ) (in R p )
到这可以已经解密出m ( x ) m(x) m ( x ) ,但这个m ( x ) m(x) m ( x ) 落在R p R_p R p ,即系数取值在[ 0 , p ) [0, p) [ 0 , p ) ,而实际的m ( x ) m(x) m ( x ) 取值应该是在( − p 2 , p 2 ] (-\frac{p}{2}, \frac{p}{2}] ( − 2 p , 2 p ] ,所以最后还要把b ( x ) b(x) b ( x ) 做一次Center-lift才解出真正的m ( x ) m(x) m ( x ) 。
公开参数 :( N , p , q , d ) (N, p, q, d) ( N , p , q , d ) ,其中N N N 是素数、p p p 一般取3 3 3 、q q q 一般取2 2 2 的幂,还需要保证g c d ( N , q ) = g c d ( p , q ) = 1 \rm{gcd}(N, q) = \rm{gcd}(p, q) = 1 gcd ( N , q ) = gcd ( p , q ) = 1 ,和( 6 d + 1 ) ⋅ p < q (6d+1)·p < q ( 6 d + 1 ) ⋅ p < q ;
密钥生成 :采样f ( x ) ← $ T ( d + 1 , d ) f(x) \overset{\$}{\leftarrow} \mathcal{T}(d+1, d) f ( x ) ← $ T ( d + 1 , d ) 、g ( x ) ← $ T ( d , d ) g(x) \overset{\$}{\leftarrow} \mathcal{T}(d, d) g ( x ) ← $ T ( d , d ) ,计算F q ≡ f − 1 ( x ) (in R q ) F_q \equiv f^{-1}(x) \ \text{(in }R_q \text{)} F q ≡ f − 1 ( x ) (in R q ) 和F p ≡ f − 1 ( x ) (in R p ) F_p \equiv f^{-1}(x) \ \text{(in }R_p \text{)} F p ≡ f − 1 ( x ) (in R p ) ,计算公钥h ( x ) ≡ F q ( x ) g ( x ) (in R q ) h(x) \equiv F_q(x) g(x) \ \text{(in }R_q \text{)} h ( x ) ≡ F q ( x ) g ( x ) (in R q ) 。
私钥为:( f ( x ) , g ( x ) , F q ( x ) , F p ( x ) ) (f(x), g(x), F_q(x), F_p(x)) ( f ( x ) , g ( x ) , F q ( x ) , F p ( x ))
公钥为:h ( x ) h(x) h ( x )
加密 :明文m ( x ) m(x) m ( x ) 的系数需落在( − p 2 , p 2 ] (-\frac{p}{2}, \frac{p}{2}] ( − 2 p , 2 p ] (虽然很奇怪下面表中说明文取自R p R_p R p ),采样随机数r ( x ) ← $ T ( d , d ) r(x) \overset{\$}{\leftarrow} \mathcal{T}(d, d) r ( x ) ← $ T ( d , d ) ,密文为e ( x ) ≡ p h ( x ) r ( x ) + m ( x ) (in R q ) e(x)\equiv ph(x)r(x) + m(x) \ \text{(in }R_q \text{)} e ( x ) ≡ p h ( x ) r ( x ) + m ( x ) (in R q ) ;
解密 :计算a ( x ) ≡ f ( x ) e ( x ) (in R q ) a(x) \equiv f(x)e(x) \ \text{(in }R_q \text{)} a ( x ) ≡ f ( x ) e ( x ) (in R q ) 并做Center-lift到a ( x ) ∈ R a(x) \in R a ( x ) ∈ R ,计算m ( x ) ≡ F p ( x ) a ( x ) (in R q ) m(x) \equiv F_p(x) a(x) \ \text{(in }R_q \text{)} m ( x ) ≡ F p ( x ) a ( x ) (in R q ) ,最后把m ( x ) m(x) m ( x ) 做Center-lift到R R R (如果明文取自R p R_p R p 则不需要这一步)。
参考代码·
参照上面理论部分写了个代码,其实我在很久以前就写过一个NTRU的代码,但因为穷拿去投题了,所以有保密协议就不能发,这次代码的加了很多骚操作,整体来说也更美观,所以感觉还是值得发一下。
首先是三个环R R R 、R p R_p R p 和R q R_q R q ,需要先做出Z [ x ] \mathbb{Z}[x] Z [ x ] 、( Z / p Z ) [ x ] (\mathbb{Z}/p\mathbb{Z})[x] ( Z / p Z ) [ x ] 和( Z / q Z ) [ x ] (\mathbb{Z}/q\mathbb{Z})[x] ( Z / q Z ) [ x ] ,在Sage代码中写作:
1 2 3 R_ = PolynomialRing(ZZ,'x' ) Rp_ = PolynomialRing(Zmod(p),'xp' ) Rq_ = PolynomialRing(Zmod(q),'xq' )
其中为了防止混淆,( Z / p Z ) [ x ] (\mathbb{Z}/p\mathbb{Z})[x] ( Z / p Z ) [ x ] 和( Z / q Z ) [ x ] (\mathbb{Z}/q\mathbb{Z})[x] ( Z / q Z ) [ x ] 的未知数在代码中我称作xp
和xq
。
然后使用上面三个东西做商环(模x N − 1 x^N-1 x N − 1 )就得到三个环R R R 、R p R_p R p 和R q R_q R q :
1 2 3 R = R_.quotient(x^N - 1 , 'y' ) Rp = Rp_.quotient(xp^N - 1 , 'yp' ) Rq = Rq_.quotient(xq^N - 1 , 'yq' )
其中也是为了防混淆,我把R R R 、R p R_p R p 和R q R_q R q 上的未知数称作y
、yp
和yq
。
然后采样三元多项式的函数T \mathcal{T} T ,我选择先固定d 1 d_1 d 1 个系数1 1 1 和d 2 d_2 d 2 个系数− 1 -1 − 1 ,然后再用shuffle
将其打乱以获得随机的输出,然后要注意T \mathcal{T} T 的输出落在R R R (毕竟有负数):
1 2 3 4 5 def T (self, d1, d2 ): assert self.N >= d1+d2 t = [1 ]*d1 + [-1 ]*d2 + [0 ]*(self.N-d1-d2) shuffle(t) return self.R(t)
Center-lift函数基本照抄理论部分的公式就可以了,但由于作为函数我并不知道需要Lift的是R p R_p R p 环还是R q R_q R q 环,所以需要用“曲线救国”的方法在输入中提取模数(估计有更好的方法,懒):
1 2 3 def lift (self, fx ): mod = Integer(fx.base_ring()(-1 )) + 1 return self.R([Integer(x)-mod if x > mod//2 else x for x in list (fx)])
然后是密钥生成,首先f ( x ) f(x) f ( x ) 和g ( x ) g(x) g ( x ) 直接用T \mathcal{T} T 采样即可。F p F_p F p 的计算,由于在R p R_p R p 上,而p p p 是素数,所以用Sage可以很方便地求逆:
1 Fp = self.Rp(list (fx)) ^ (-1 )
上面需要先把fx
转换到Rp
上再做求逆,而由于前面设置的未知数名称不一致,不能直接用Rp(fx)
做转换,曲线救国,先用list(fx)
提取fx
的系数,然后用系数转到Rp
。
F q F_q F q 的计算则有点复杂,由于q q q 不为素数所以不能直接用Sage像上面那样求逆,目前网上查到的流行做法如这个教程 的invertmodpowerof2
做递归求逆,但是我后来想到了一种更美观的“曲线救国”方法。
参考整数域上的求逆,比如要求a − 1 ( m o d n ) a^{-1} \pmod n a − 1 ( mod n ) ,除了用egcd求逆外,还有一种方法是(借助欧拉定理):
a φ ( n ) − 1 ≡ a φ ( n ) a − 1 ≡ 1 ⋅ a − 1 ≡ a − 1 ( m o d n ) a^{\varphi(n)-1} \equiv a^{\varphi(n)} a^{-1} \equiv 1 · a^{-1} \equiv a^{-1} \pmod n
a φ ( n ) − 1 ≡ a φ ( n ) a − 1 ≡ 1 ⋅ a − 1 ≡ a − 1 ( mod n )
其中的φ ( n ) \varphi(n) φ ( n ) 即Z n ∗ \mathbb{Z}_n^* Z n ∗ 的阶。
所以只要求出F q F_q F q 的阶即可利用类似方法求逆,问题是如何求F q F_q F q 的阶。
经过计算加实验~~(原理未明,留坑)~~,发现f ( x ) f(x) f ( x ) 在F q F_q F q 的阶(q q q 为2 2 2 的幂次)为:
φ ( q ) = q N − q \varphi(q) = q^{N} - q
φ ( q ) = q N − q
的因子。
PS:这里我取了最大值,即以上不是真正符合阶的定义,但是阶的某个倍数,所以说其阶是上面式子的一个因子,如果有方法可以分解上式则可能可以找到真正的阶,但在q q q 不大的情况下找到真正的阶其实并不能显著加速求逆的效率,所以可以选择直接使用φ ( q ) \varphi(q) φ ( q ) 。
而f ( x ) f(x) f ( x ) 在F p F_p F p 的阶为(p p p 为素数):
φ ( p ) = p N − p \varphi(p) = p^{N} - p
φ ( p ) = p N − p
的因子。这个结果和之前求G L ( n , F p ) GL(n, \mathbb{F}_p) G L ( n , F p ) 阶的结果 类似,毕竟p p p 为素数时,两个东西同构(如果我没记错的话,逃)。
PS:(2024.01.03更新)这里求阶的方法其实和RSA中求φ \varphi φ 的方法类似,首先需要把所模的多项式分解为不可约的多项式,然后再分别求模这些不可约多项式的子环的阶,最后乘起来就是所求的真正的阶。但是这样算出来的阶会非常复杂,而p N − p p^{N} - p p N − p 又刚好阴差阳错地是这些阶的一个倍数,所以还是直接用p N − p p^{N} - p p N − p 为好(逃
另外,若p p p 和q q q 不按[HPS14]的说明选择,根据中国剩余定理(CRT),假设p = ∑ i p i k i p = \sum_i p_i^{k_i} p = ∑ i p i k i ,则f ( x ) f(x) f ( x ) 在F p F_p F p 的阶为:
∏ i ( p i k i N − p i k i ) \prod_i (p_i^{k_iN} - p_i^{k_i})
i ∏ ( p i k i N − p i k i )
综上,通过计算
F p ≡ f ( x ) φ ( p ) − 1 ≡ f − 1 ( x ) (in R p ) F q ≡ f ( x ) φ ( q ) − 1 ≡ f − 1 ( x ) (in R q ) F_p \equiv f(x)^{\varphi(p)-1} \equiv f^{-1}(x) \ \text{(in $R_p$)} \\
F_q \equiv f(x)^{\varphi(q)-1} \equiv f^{-1}(x) \ \text{(in $R_q$)}
F p ≡ f ( x ) φ ( p ) − 1 ≡ f − 1 ( x ) (in R p ) F q ≡ f ( x ) φ ( q ) − 1 ≡ f − 1 ( x ) (in R q )
即可算出F p F_p F p 和F q F_q F q 。
然后加密好像没啥可说的,只是为了统一,我把返回值转成字符串再输出,这样在输进解密函数时也不需要考虑类型问题。
解密函数也没啥好说,关注Center-lift的时机即可。
最后的参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 class NTRU : def __init__ (self, N, p, q, d ): self.debug = False assert q > (6 *d+1 )*p assert is_prime(N) assert gcd(N, q) == 1 and gcd(p, q) == 1 self.N = N self.p = p self.q = q self.d = d self.R_ = PolynomialRing(ZZ,'x' ) self.Rp_ = PolynomialRing(Zmod(p),'xp' ) self.Rq_ = PolynomialRing(Zmod(q),'xq' ) x = self.R_.gen() xp = self.Rp_.gen() xq = self.Rq_.gen() self.R = self.R_.quotient(x^N - 1 , 'y' ) self.Rp = self.Rp_.quotient(xp^N - 1 , 'yp' ) self.Rq = self.Rq_.quotient(xq^N - 1 , 'yq' ) self.RpOrder = self.p^self.N - self.p self.RqOrder = self.q^self.N - self.q self.sk, self.pk = self.keyGen() def test (self ): assert self.debug == True pass def T (self, d1, d2 ): assert self.N >= d1+d2 t = [1 ]*d1 + [-1 ]*d2 + [0 ]*(self.N-d1-d2) shuffle(t) return self.R(t) def lift (self, fx ): mod = Integer(fx.base_ring()(-1 )) + 1 return self.R([Integer(x)-mod if x > mod//2 else x for x in list (fx)]) def keyGen (self ): fx = self.T(self.d+1 , self.d) gx = self.T(self.d, self.d) Fp = self.Rp(list (fx)) ^ (-1 ) assert pow (self.Rp(list (fx)), self.RpOrder-1 ) == Fp assert self.Rp(list (fx)) * Fp == 1 Fq = pow (self.Rq(list (fx)), self.RqOrder - 1 ) assert self.Rq(list (fx)) * Fq == 1 hx = Fq * self.Rq(list (gx)) sk = (fx, gx, Fp, Fq, hx) pk = hx return sk, pk def setKey (self, fx, gx ): assert type (fx) == type ('x^2 + 1' ) assert type (gx) == type ('x^2 - 1' ) try : fx = self.R(fx) gx = self.R(gx) Fp = self.Rp(list (fx)) ^ (-1 ) Fq = pow (self.Rq(list (fx)), self.RqOrder - 1 ) hx = Fq * self.Rq(list (gx)) self.sk = (fx, gx, Fp, Fq, hx) self.pk = hx return True except : return False def getKey (self ): ssk = ( str (self.R_(list (self.sk[0 ]))), str (self.R_(list (self.sk[1 ]))) ) spk = str (self.Rq_(list (self.pk))) return ssk, spk def encrypt (self, m ): assert type (m) == type ('x^2 + 1' ) assert self.pk != None hx = self.pk mx = self.R(m) mx = self.Rp(list (mx)) mx = self.Rq(list (mx)) rx = self.T(self.d, self.d) rx = self.Rq(list (rx)) e = self.p * rx * hx + mx return str (self.Rq_(list (e))) def decrypt (self, e ): assert type (e) == type ('xq^2 - 1' ) assert self.sk != None fx, gx, Fp, Fq, hx = self.sk e = self.Rq(e) ax = self.Rq(list (fx)) * e a = self.lift(ax) bx = Fp * self.Rp(list (a)) b = self.lift(bx) return str (self.R_(list (b))) if __name__ == '__main__' : mm = '-x^2 + x + 1' ntru = NTRU(N=11 , p=3 , q=512 , d=3 ) print ('keyGen check:' ) sk, pk = ntru.getKey() print ("fx = '%s'" % sk[0 ]) print ("gx = '%s'" % sk[1 ]) print ("hx = '%s'" % pk) print ('\nencrypt/decrypt check:' ) e = ntru.encrypt(mm) print ("e = '%s'" % e) m = ntru.decrypt(e) print (m) assert m == mm print (m) print ('\ncheck setKey:' ) fx = 'x^10 + x^9 - x^8 - x^5 + x^4 + x - 1' gx = '-x^10 + x^9 - x^6 - x^5 + x^4 + 1' hx = '357*xq^10 + 156*xq^9 + 22*xq^8 + 467*xq^7 + 356*xq^6 + 23*xq^5 + 422*xq^4 + 490*xq^3 + 200*xq^2 + 201*xq + 378' e = '286*xq^10 + 336*xq^9 + 355*xq^8 + 220*xq^7 + 330*xq^6 + 198*xq^5 + 182*xq^4 + 443*xq^3 + 454*xq^2 + 45*xq + 227' ntru.setKey(fx, gx) m = ntru.decrypt(e) assert m == mm print (m)
攻击方法·
下面说一下[HPS14]里提到的两种攻击方法。
小密钥空间·
[HPS14]的7.10.2中提到:
即N N N 和d d d 的取值不合理的话,会导致f ( x ) f(x) f ( x ) 的取值空间过小,从而可以被攻击者枚举出密钥。
这个在参数设置上注意就好了,做题的话看见N N N 和d d d 过小可以考虑直接枚举。
格规约攻击·
这里参考[HPS14]的7.11的内容,主要关注公钥的生成:
h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q h(x) \equiv f(x)^{-1} · g(x) \ \text{in } R_q
h ( x ) ≡ f ( x ) − 1 ⋅ g ( x ) in R q
把模数去除,参考[HPS14]的写法即存在一个多项式u ( x ) u(x) u ( x ) 使得:
f ( x ) ⋅ h ( x ) − q ⋅ u ( x ) = g ( x ) f(x) · h(x) - q · u(x) = g(x)
f ( x ) ⋅ h ( x ) − q ⋅ u ( x ) = g ( x )
写成矩阵形式也即(如果熟悉格规约的话,会把已知的放进矩阵):
( f ( x ) , − u ( x ) ) [ 1 h ( x ) 0 q ] = ( f ( x ) , g ( x ) ) (f(x), -u(x))
\begin{bmatrix}
1 & h(x) \\
0 & q \\
\end{bmatrix} =
(f(x), g(x))
( f ( x ) , − u ( x )) [ 1 0 h ( x ) q ] = ( f ( x ) , g ( x ))
这个只是一个写着方便的表述,实际上f ( x ) f(x) f ( x ) 、g ( x ) g(x) g ( x ) 、h ( x ) h(x) h ( x ) 和u ( x ) u(x) u ( x ) 都是多项式,不能这样简单地占一个位置,应该
多项式相乘:用前面说的多项式卷积乘法的矩阵写法;
多项式数乘:用多项式的系数向量和对角线上为该常数的对角矩阵相乘;
这里我就直接抄书了:
用书中的简化写法是(为了混淆h ( x ) h(x) h ( x ) 我用了H H H ,I I I 是单位矩阵):
M h N T R U = [ I H 0 q I ] M_h^{\rm{NTRU}} =
\begin{bmatrix}
\begin{array}{l|l}
I & H \\
\hline
0 & qI
\end{array}
\end{bmatrix}
M h NTRU = [ I 0 H q I ]
存在关系(记f f f 为f ( x ) f(x) f ( x ) 的系数向量,记g g g 为g ( x ) g(x) g ( x ) 的系数向量):
( f ∣ − u ) ⋅ M h N T R U = ( f ∣ g ) (f | -u) · M_h^{\rm{NTRU}} = (f | g)
( f ∣ − u ) ⋅ M h NTRU = ( f ∣ g )
直观上f f f 和g g g 上元素的绝对值最大是1 1 1 ,所以( f ∣ g ) (f | g) ( f ∣ g ) 是“小”向量,用LLL对M h N T R U M_h^{\rm{NTRU}} M h NTRU 规约即可出( f ∣ g ) (f | g) ( f ∣ g ) ,这里先计算一下,我就直接借用[HPS14]的计算(懒):
但实际操作的情况是,LLL实际上解的是apprSVP,当矩阵规模变大时,求出( f ∣ g ) (f | g) ( f ∣ g ) 的能力会变小,所以只要设置足够大的N N N 即可防止这类攻击。
贴个攻击参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 def matrix_overview (BB ): for ii in range (BB.dimensions()[0 ]): a = ('%02d ' % ii) for jj in range (BB.dimensions()[1 ]): if BB[ii, jj] == 0 : a += ' ' else : a += 'X' if BB.dimensions()[0 ] < 60 : a += ' ' print (a) from NTRU import NTRUN = 11 q = 512 p = 3 d = 3 hx = '357*xq^10 + 156*xq^9 + 22*xq^8 + 467*xq^7 + 356*xq^6 + 23*xq^5 + 422*xq^4 + 490*xq^3 + 200*xq^2 + 201*xq + 378' e = '286*xq^10 + 336*xq^9 + 355*xq^8 + 220*xq^7 + 330*xq^6 + 198*xq^5 + 182*xq^4 + 443*xq^3 + 454*xq^2 + 45*xq + 227' Rq_ = PolynomialRing(Zmod(q),'xq' ) h = vector(list (Rq_(hx))) print (h)M = matrix(ZZ, 2 *N) for i in range (N): M[i, i] = 1 M[N+i, N+i] = q for j in range (N): M[i, N+j] = h[(j-i) % N] matrix_overview(M) L = M.LLL() def inT (f, d1, d2, N ): fl = list (f) c1 = fl.count(1 ) c_1 = fl.count(-1 ) c0 = fl.count(0 ) return c1==d1 and c_1==d2 and c1+c0+c_1 == N R_ = PolynomialRing(ZZ,'x' ) ntru = NTRU(N=N, p=p, q=q, d=d) for i in range (N): fg = L[i] f = vector(ZZ, fg[:N]) g = vector(ZZ, fg[N:]) if inT(f, d+1 , d, N): pass elif inT(-f, d+1 , d, N): f = -f else : continue if inT(g, d, d, N): pass elif inT(-g, d, d, N): g = -g else : continue print ('Trying in i = %d' % i) fx = str (R_(list (f))) gx = str (R_(list (g))) print ('f = %s' % fx) print ('g = %s' % gx) ntru.setKey(fx, gx) m = ntru.decrypt(e) print ('m = %s' % m) print ('----------------\n' )
有一个尴尬的情况是,M h N T R U M_h^{\rm{NTRU}} M h NTRU 是一个N-Gap的格,也即LLL/BKZ规约后的矩阵中,前N行向量的规模是相近的,这会导致LLL/BKZ规约后的第一行不一定是( f ∣ g ) (f | g) ( f ∣ g ) ,当然也会有( f ∣ g ) (f | g) ( f ∣ g ) 不是最短向量的情况。
曲线救国的方法是,把前N行向量都试一遍,先检测其是否落在T ( d + 1 , d ) \mathcal{T}(d+1, d) T ( d + 1 , d ) ,再尝试解密。
另外,实验测出有多个多个f ( x ) f(x) f ( x ) 都可以实现解密的情况,合理怀疑一个公钥h ( x ) h(x) h ( x ) 可以对应多个私钥f ( x ) f(x) f ( x ) ,也就是有可能上面解出来的前N N N 行都是对的,emmmm。