神奇的题目ヾ(´∀ ˋ)ノ
CrewCTF
Inverse With Errors
题目
题目描述:
1 | This chall is equal to mystiz's chall, or is it? |
题目:
1 | import secrets |
题目有30组如下形式的等式:
其中$N, d$均为1024bit,$r_i$为100bit的小量,给出$e_i,r_i$,要求解$d$。
思路
概览
在赛中的时候我对这个题没有一点有效思路,但很好奇他的解法,就在赛后在discord上看了出题人@KLPP的解释,第一眼也没太看懂,仔细琢磨了很久他的exp,最终才明白这个题有多巧妙。
首先由于我们并没有$N$,因此写不出来一个模大数下的方程组,所以只能把上面的式子都展开到$\mathbb{Z}$下,也就是:
这个时候整个系统变成了一个32个变量、30个方程的方程组,直接求解这个方程组有几个问题:
- 变量数大于方程数,显然是欠定的
- 有二次项$k_iN$,整个方程并不线性,求解难度比较高
能利用的地方在于:
- 方程结构很统一,并且并不复杂
- 所有未知量都有界,都在$2^{1024}$这个量级
变量代换(部分$k_i \rightarrow t_i$)
解法的思路是很难直接想到的,所以我就直接阐述解法的步骤了。首先我们可以固定几个等式(出题人的exp中固定了4个),然后对剩下的第5到第30个等式,分别找到一组小系数$v_{i1},v_{i2},v_{i3},v_{i4}$,使其满足:
把这些小系数分别乘到对应等式上并求和,就可以消去d,得到新的等式:
这个等式也可以写为:
一共会有30-4=26组这样的等式。
而对于这样的等式,我们需要注意一下各项的数量级关系。笼统的说,由于$v_{ij}$是小系数且$r_i$也在100bit内,所以整个式子是$k_i$和$N$两个1024bit数量级的在占主导作用,因此上述等式的这两项的数量级差不多:
这告诉了我们重要的一个事实:$\sum_{j=1}^{4}v_{ij}k_j + k_i$的值是比较小的,实际测试一下大约是440bit左右,我们不妨把这个量记做$t_i$,也就是$t_i = \sum_{j=1}^{4}v_{ij}k_j + k_i$,此时$k_i$就可以表示成$k_i = t_i - \sum_{j=1}^{4}v_{ij}k_j$。
那么把这种表示代回刚才的式子,我们的方程组发生了一点变化:
- 前四个式子不变,依然是$e_id = 1 + k_i(N+r_i) \quad i \in \{1,2,3,4\}$
- 第5-30个式子代入$t_i$的表示后,变成了$e_id = 1 + (t_i - \sum_{j=1}^{4}v_{ij}k_j)(N+r_i) \quad i \in \{5,6,\cdots,30\}$
做这样的等式变换的好处和坏处都很明显:
- 好处在于有26个变量从1024bit变成了440bit的小量
- 坏处在于有26个式子的结构变复杂了,多了几个二次项
所以这有一种tradeoff的思想在里面。
coppersmith
而神奇的地方才刚刚开始,出题人接下来的想法是对上述式子做copper,这很容易让人感到疑惑:
- copper的作用一般来说可以表述成这样:给定一组模意义下有小根的方程,通过格的手段约简多项式的系数,从而使整个方程组从模数下脱离出来,变成$\mathbb{Z}$下的方程,此时可以对方程求根得到这些小根
那这题目的方程组怎么会用到copper?这些方程本身就是$\mathbb{Z}$下的,无法求根的原因在于方程数不够且方程为二次方程。
精妙的地方就在这里,我们先忽略copper的目的,直接去应用他,也就是把30个等式按照单项依次写成行向量从而得到一个矩阵,这个矩阵是30x62的:
行数是30很好理解,30个方程分别对应一个行向量
列数是62是因为这30个方程一共有62个不同的单项,分别是:
由copper我们可以知道,既然这格的行向量都是以$d,k_i,t_i,N$这些为根的多项式,因此对他做约简之后,得到的每一行行向量其实都对应一个同样以$d,k_i,t_i,N$这些为根、且系数更小的多项式。
因为就相当于是把一些根相同的多项式做了一个系数的线性组合
此时重要的一步来了,我们从copper的视角跳脱出来,单纯审视这个格以及他的规约过程,我们可以做到这样一件事情:给含$d$以及$k_i$的列配上一个大系数再去规约,那么我们能得到一些较短的行向量,他们对应的多项式会是仅含如下单项的多项式:
而我们知道格的规约有一个特性:规约后的向量各分量是趋于平衡的,那么对于这个格来说,他规约出来的东西是新的多项式的系数,而观察原来含这些单项的多项式里(也就是$e_id = 1 + k_i(N+r_i) \quad i \in \{1,2,3,4\}$和$e_id = 1 + (t_i - \sum_{j=1}^{4}v_{ij}k_j)(N+r_i) \quad i \in \{5,6,\cdots,30\}$)这些量的系数会发现分别是:
- $1$的系数就是$1$
- $t_i$的系数是$r_i$
- $t_iN$的系数是$1$
因此规约出来的系数数量级差的也不过是$r_i$的数量级,也就是100bit,形象一点理解的话,我们记格规约出来的这些单项系数为:
那么这条行向量对应多项式就是:
且$a, x_i, y_i$数量级差距不大。
意义
理解到上面这一步后,问题马上就来了:这样做的意义在哪里?
这个意义非常精妙,虽然系数向量$(a, x_5,\cdots, x_{30}, y_5,\cdots, y_{30})$的各分量数量级差距不大(并且由于是规约出来的,这些都比较小),但是我们可以注意到单项$(1, t_5,\cdots, t_{30}, t_1N,\cdots,t_{30}N)$之间的数量级差异是巨大的,由于$t_i$仅有440bit左右而$N$有1024bit,因此两部分可以分离出来,也就是我们能分别得到:
而第二条其实也就是:
这非常的有用——这些等式是崭新的等式,并且是线性的,所以把这些等式和前面30个等式一起做groebner就可以得到包括$N,d$在内的所有未知量了。
exp
1 | R = [] |
1 | m = 30 |
1 | Final_poly = [] |
1 | for i in range(n): |
1 | d = 105161125166605172985549230601848031277103055304769022514486694213250702858759115384924357531761239330626948615552847720925761215583349311437556873968774464033940956188047781659237669672632756699201613300897438047922454957029036703887892843872083276722895063014080938151603150387874025791522311723981427501717 |