-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
487 lines (262 loc) · 282 KB
/
atom.xml
File metadata and controls
487 lines (262 loc) · 282 KB
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>随缘的博客</title>
<subtitle>su1yu4n's Blog</subtitle>
<link href="https://su1yu4n.github.io/atom.xml" rel="self"/>
<link href="https://su1yu4n.github.io/"/>
<updated>2025-08-01T09:30:21.552Z</updated>
<id>https://su1yu4n.github.io/</id>
<author>
<name>随缘(su1yu4n)</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>NepCTF2025 ezRSA2官方题解</title>
<link href="https://su1yu4n.github.io/2025/08/01/NepCTF2025-ezRSA2%E5%AE%98%E6%96%B9%E9%A2%98%E8%A7%A3/"/>
<id>https://su1yu4n.github.io/2025/08/01/NepCTF2025-ezRSA2%E5%AE%98%E6%96%B9%E9%A2%98%E8%A7%A3/</id>
<published>2025-08-01T03:30:00.000Z</published>
<updated>2025-08-01T09:30:21.552Z</updated>
<content type="html"><![CDATA[<p>这是一个简单的RSA二元Coppersmith。题目中已知$d < N^{0.33}$, 以及一些$d \bmod l_i$的值。这些$l_i$的乘积约为$N^{0.17}$。</p><p>这道题也可以用Wiener攻击的思路构造三维格求解。以下为题目和两种解法的详细说明。</p><span id="more"></span><h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>Easy RSA, easy strategy. No need to brute force.</p><p>Perhaps it’s easier than ezRSA in NepCTF 2024.</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> getStrongPrime, getRandomNBitInteger, GCD, inverse, long_to_bytes, bytes_to_long, sieve_base</span><br><span class="line"><span class="keyword">from</span> flag <span class="keyword">import</span> flag</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">gen_parameters</span>(<span class="params">gamma=<span class="number">0.33</span>, beta=<span class="number">0.33</span></span>):</span><br><span class="line"> p = getStrongPrime(<span class="number">1024</span>)</span><br><span class="line"> q = getStrongPrime(<span class="number">1024</span>)</span><br><span class="line"> N = p*q</span><br><span class="line"> phi = (p-<span class="number">1</span>)*(q-<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> d = getRandomNBitInteger(<span class="built_in">int</span>(<span class="number">2048</span>*beta))</span><br><span class="line"> <span class="keyword">if</span> GCD(d, phi) == <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> e = inverse(d, phi)</span><br><span class="line"> </span><br><span class="line"> hints = []</span><br><span class="line"> M = <span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="built_in">len</span>(sieve_base)):</span><br><span class="line"> li = sieve_base[i]</span><br><span class="line"> hints.append(d%li)</span><br><span class="line"> M *= li</span><br><span class="line"> <span class="keyword">if</span> M.bit_length() >= <span class="number">1024</span>*gamma:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> e, N, hints</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line"> e,N,hints = gen_parameters()</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'e=<span class="subst">{<span class="built_in">hex</span>(e)}</span>'</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'N=<span class="subst">{<span class="built_in">hex</span>(N)}</span>\n'</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'hints=<span class="subst">{hints}</span>\n'</span>)</span><br><span class="line"> </span><br><span class="line"> flag_prefix = <span class="string">b'NepCTF{'</span></span><br><span class="line"> <span class="keyword">assert</span> flag.startswith(flag_prefix)</span><br><span class="line"> <span class="keyword">assert</span> flag.endswith(<span class="string">b'}'</span>)</span><br><span class="line"> </span><br><span class="line"> pt = bytes_to_long(flag[<span class="built_in">len</span>(flag_prefix):-<span class="number">1</span>])</span><br><span class="line"> ct = <span class="built_in">pow</span>(pt, e, N)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'ct=<span class="subst">{<span class="built_in">hex</span>(ct)}</span>'</span>)</span><br><span class="line"> </span><br><span class="line">main()</span><br><span class="line"></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">e=0x73915608ed64c9cf1a2279684cab4f4a78fba229d45d4f860971a241481363470a19cb0dc0d00f816b5befdaca017cf71483e96ef17b36179012f5194a0e6bf481bb06c2644f74c6812efb65d05c00631f282d6aa55c0bc140a1830b95a1cf4b6024cb0db53f2c2189897c41f22e2eec773723f531ec4bfa537fae6de5fe480cf46fe17850f7eb47df08194d95db3d26ac923b26e110ee645239ab586bbc546ddc5906f280a106edbb727ccb05536b5a3f5c0ebcf865c95ce58be54f7f3547aa53baa218b0dfa98e42d925fa341e45f94a3b16b0c83802660c7f34de3336cb21f219073cf8e9f5e39d47f0a9a9ee7c255f09a6add9a2f7a47960f4a853183d29</span></span><br><span class="line"><span class="string">N=0xba8956e81394f3f1265ca5d9c4ad1ab0078bb43c4b80a231ab2cc62246ae45f66a562252622aed2cbbfc08647ef2fec0f97a632bf2242845f4b3af0c427cec3d90f42e90278a5a0feeed0922a8cd2278074ac54e9cfc0e96ff68f8d8f266dd87dc1cc59c2895ec884de2022311767f6a9a7e0bd288c79620e28b83bb3c8d8ad1047c839d6ccf5544eaf434a5f00b951769ab3121298d04b63a162757beb3d49917cd0c9e02ee1ac29398c8130961d5a2f2833aba1e538edb7bb97071f40fae543d1622f0c9206c6d4d8abb2ac1b93ebfb603c2f3a909ede357ade4043550fe540d13a4e87db8d731fe130f15a43a1a00364f5da2d87f7b660c3a04e734218a11</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">hints=[1, 3, 0, 3, 9, 16, 10, 14, 5, 11, 21, 18, 30, 30, 38, 2, 20, 62, 66, 1, 22, 56, 41, 13, 78, 59, 51, 6, 57, 117, 73, 75, 96, 112, 50, 93, 158, 97, 146, 8, 65, 96, 186, 161, 90, 131, 46, 32, 140, 133, 50, 43, 151, 234]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">ct=0x101b284ad196b5bbd3d3df00a7d3577caeb29c681bdd122582b705afc671febf45d4f3786640e55aadd6a31ecc49175f97b772720f1735f8555f768b137a4643cd6958f80a3dfca4d0270ad463d6dde93429940bd2abb5ad8408b0906fa8d776544a1c50cc0d95939bef4c3fb64d0b52dca81ff0f244fc265bfc0bc147435d05f8f1a146e963a1403b3c123b4d6e73d1fd897109995009be1673212607f0ea7ae33d23f3158448b05c28ea6636382eee9436c4a6c09023ead7182ecd55ac73a68d458d726e1abc208810468591e63f4b4c2c1f3ce27c4800b52f7421ccab432c03e88b3b255740d719e40e0226eabb7633d97ed210e32071e2ac36ed17ef442e</span></span><br><span class="line"><span class="string">"""</span></span><br></pre></td></tr></table></figure><h2 id="解法"><a href="#解法" class="headerlink" title="解法"></a>解法</h2><p>符号约定:</p><p>设$M= \prod_{i=1}^{\mathrm{len(hints)}} \mathrm{sievebase} [i]$, 根据CRT,可由$\mathrm{hints}$求得 $d_0 := d \bmod M$.</p><p>记$d=d_1M+d_0$, $r=p+q$.</p><h4 id="方法1"><a href="#方法1" class="headerlink" title="方法1"></a>方法1</h4><p>根据RSA等式有$e(d_1M + d_0) = 1 + k(N+1-r) \implies $</p><p><script type="math/tex">1-ed_0+k(N+1-r) \equiv 0 \bmod eM \quad (1)</script></p><p>考虑到题目中$d \approx N^{0.33}, M \approx N^{0.17}$, 与无额外信息的小$d$攻击(最佳渐进界为$N^{0.2928}$)界相差不大。且题目描述中提示了,不需要使用复杂的Coppersmith策略(界是富裕的),并且比NepCTF 2024的ezRSA更简单。</p><p>使用简单shift多项式策略的二元coppersmith方法,直接求解式 $(1)$即可。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> sieve_base, long_to_bytes</span><br><span class="line"><span class="keyword">import</span> itertools</span><br><span class="line"><span class="keyword">from</span> sage.<span class="built_in">all</span> <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">beta = <span class="number">0.33</span></span><br><span class="line"></span><br><span class="line">e=<span class="number">0x73915608ed64c9cf1a2279684cab4f4a78fba229d45d4f860971a241481363470a19cb0dc0d00f816b5befdaca017cf71483e96ef17b36179012f5194a0e6bf481bb06c2644f74c6812efb65d05c00631f282d6aa55c0bc140a1830b95a1cf4b6024cb0db53f2c2189897c41f22e2eec773723f531ec4bfa537fae6de5fe480cf46fe17850f7eb47df08194d95db3d26ac923b26e110ee645239ab586bbc546ddc5906f280a106edbb727ccb05536b5a3f5c0ebcf865c95ce58be54f7f3547aa53baa218b0dfa98e42d925fa341e45f94a3b16b0c83802660c7f34de3336cb21f219073cf8e9f5e39d47f0a9a9ee7c255f09a6add9a2f7a47960f4a853183d29</span></span><br><span class="line">N=<span class="number">0xba8956e81394f3f1265ca5d9c4ad1ab0078bb43c4b80a231ab2cc62246ae45f66a562252622aed2cbbfc08647ef2fec0f97a632bf2242845f4b3af0c427cec3d90f42e90278a5a0feeed0922a8cd2278074ac54e9cfc0e96ff68f8d8f266dd87dc1cc59c2895ec884de2022311767f6a9a7e0bd288c79620e28b83bb3c8d8ad1047c839d6ccf5544eaf434a5f00b951769ab3121298d04b63a162757beb3d49917cd0c9e02ee1ac29398c8130961d5a2f2833aba1e538edb7bb97071f40fae543d1622f0c9206c6d4d8abb2ac1b93ebfb603c2f3a909ede357ade4043550fe540d13a4e87db8d731fe130f15a43a1a00364f5da2d87f7b660c3a04e734218a11</span></span><br><span class="line"></span><br><span class="line">hints=[<span class="number">1</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">9</span>, <span class="number">16</span>, <span class="number">10</span>, <span class="number">14</span>, <span class="number">5</span>, <span class="number">11</span>, <span class="number">21</span>, <span class="number">18</span>, <span class="number">30</span>, <span class="number">30</span>, <span class="number">38</span>, <span class="number">2</span>, <span class="number">20</span>, <span class="number">62</span>, <span class="number">66</span>, <span class="number">1</span>, <span class="number">22</span>, <span class="number">56</span>, <span class="number">41</span>, <span class="number">13</span>, <span class="number">78</span>, <span class="number">59</span>, <span class="number">51</span>, <span class="number">6</span>, <span class="number">57</span>, <span class="number">117</span>, <span class="number">73</span>, <span class="number">75</span>, <span class="number">96</span>, <span class="number">112</span>, <span class="number">50</span>, <span class="number">93</span>, <span class="number">158</span>, <span class="number">97</span>, <span class="number">146</span>, <span class="number">8</span>, <span class="number">65</span>, <span class="number">96</span>, <span class="number">186</span>, <span class="number">161</span>, <span class="number">90</span>, <span class="number">131</span>, <span class="number">46</span>, <span class="number">32</span>, <span class="number">140</span>, <span class="number">133</span>, <span class="number">50</span>, <span class="number">43</span>, <span class="number">151</span>, <span class="number">234</span>]</span><br><span class="line"></span><br><span class="line">ct=<span class="number">0x101b284ad196b5bbd3d3df00a7d3577caeb29c681bdd122582b705afc671febf45d4f3786640e55aadd6a31ecc49175f97b772720f1735f8555f768b137a4643cd6958f80a3dfca4d0270ad463d6dde93429940bd2abb5ad8408b0906fa8d776544a1c50cc0d95939bef4c3fb64d0b52dca81ff0f244fc265bfc0bc147435d05f8f1a146e963a1403b3c123b4d6e73d1fd897109995009be1673212607f0ea7ae33d23f3158448b05c28ea6636382eee9436c4a6c09023ead7182ecd55ac73a68d458d726e1abc208810468591e63f4b4c2c1f3ce27c4800b52f7421ccab432c03e88b3b255740d719e40e0226eabb7633d97ed210e32071e2ac36ed17ef442e</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># defund small_roots</span></span><br><span class="line"><span class="comment"># https://github.com/defund/coppersmith</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">small_roots</span>(<span class="params">f, bounds, m=<span class="number">1</span>, d=<span class="literal">None</span></span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> d:</span><br><span class="line"> d = f.degree()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">isinstance</span>(f, Polynomial):</span><br><span class="line"> x, = polygens(f.base_ring(), f.variable_name(), <span class="number">1</span>)</span><br><span class="line"> f = f(x)</span><br><span class="line"></span><br><span class="line"> R = f.base_ring()</span><br><span class="line"> N = R.cardinality()</span><br><span class="line"> </span><br><span class="line"> f /= f.coefficients().pop(<span class="number">0</span>)</span><br><span class="line"> f = f.change_ring(ZZ)</span><br><span class="line"></span><br><span class="line"> G = <span class="type">Sequence</span>([], f.parent())</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(m+<span class="number">1</span>):</span><br><span class="line"> base = N**(m-i) * f**i</span><br><span class="line"> <span class="keyword">for</span> shifts <span class="keyword">in</span> itertools.product(<span class="built_in">range</span>(d), repeat=f.nvariables()):</span><br><span class="line"> g = base * prod(<span class="built_in">map</span>(power, f.variables(), shifts))</span><br><span class="line"> G.append(g)</span><br><span class="line"></span><br><span class="line"> B, monomials = G.coefficient_matrix()</span><br><span class="line"> monomials = vector(monomials)</span><br><span class="line"></span><br><span class="line"> factors = [monomial(*bounds) <span class="keyword">for</span> monomial <span class="keyword">in</span> monomials]</span><br><span class="line"> <span class="keyword">for</span> i, factor <span class="keyword">in</span> <span class="built_in">enumerate</span>(factors):</span><br><span class="line"> B.rescale_col(i, factor)</span><br><span class="line"> st1 = time.time()</span><br><span class="line"> </span><br><span class="line"> B = (B.dense_matrix()).LLL(epsilon=<span class="number">0.99</span>)</span><br><span class="line"> <span class="comment"># B = flatter(B)</span></span><br><span class="line"> </span><br><span class="line"> end = time.time()</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'time of lattice reduction: <span class="subst">{end-st1}</span>s'</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{B.dimensions() = }</span>'</span>)</span><br><span class="line"> B = B.change_ring(QQ)</span><br><span class="line"> <span class="keyword">for</span> i, factor <span class="keyword">in</span> <span class="built_in">enumerate</span>(factors):</span><br><span class="line"> B.rescale_col(i, <span class="number">1</span>/factor)</span><br><span class="line"></span><br><span class="line"> H = <span class="type">Sequence</span>([], f.parent().change_ring(QQ))</span><br><span class="line"> <span class="keyword">for</span> h <span class="keyword">in</span> <span class="built_in">filter</span>(<span class="literal">None</span>, B*monomials):</span><br><span class="line"> H.append(h)</span><br><span class="line"> I = H.ideal()</span><br><span class="line"> <span class="keyword">if</span> I.dimension() == -<span class="number">1</span>:</span><br><span class="line"> H.pop()</span><br><span class="line"> <span class="keyword">elif</span> I.dimension() == <span class="number">0</span>:</span><br><span class="line"> roots = []</span><br><span class="line"> <span class="keyword">for</span> root <span class="keyword">in</span> I.variety(ring=ZZ):</span><br><span class="line"> root = <span class="built_in">tuple</span>(R(root[var]) <span class="keyword">for</span> var <span class="keyword">in</span> f.variables())</span><br><span class="line"> roots.append(root)</span><br><span class="line"> <span class="keyword">return</span> roots</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> []</span><br><span class="line"></span><br><span class="line">li_list = <span class="built_in">list</span>(sieve_base[<span class="number">1</span>:<span class="built_in">len</span>(hints)+<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">attack</span>():</span><br><span class="line"> M = prod(li_list)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{M.bit_length() = }</span>'</span>)</span><br><span class="line"> dM = CRT(hints, li_list)</span><br><span class="line"> <span class="comment"># ed-1 = k(N+1-(p+q))</span></span><br><span class="line"> <span class="comment"># k(N+1)-k(p+q)-(e*dM-1) = 0(eM)</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{dM = }</span>'</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{dM.bit_length() = }</span>'</span>)</span><br><span class="line"></span><br><span class="line"> PR = PolynomialRing(Zmod(e*M), <span class="string">'x,y'</span>)</span><br><span class="line"> x,y = PR.gens()</span><br><span class="line"></span><br><span class="line"> f = x*(N+<span class="number">1</span>)-x*y-(e*dM-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> XX = (e*<span class="number">2</span>**ceil(<span class="number">2048</span>*beta)) // N</span><br><span class="line"> YY = <span class="number">3</span>*<span class="number">2</span>**<span class="number">1024</span></span><br><span class="line"></span><br><span class="line"> roots = <span class="built_in">list</span>(small_roots(f, [XX,YY], m=<span class="number">1</span>))</span><br><span class="line"> <span class="built_in">print</span>(roots)</span><br><span class="line"> <span class="keyword">assert</span> <span class="built_in">len</span>(roots) == <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> k, r = roots[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># ed-1=k(N+1-r)</span></span><br><span class="line"> k, r = ZZ(k), ZZ(r)</span><br><span class="line"> d = (k*(N+<span class="number">1</span>-r) + <span class="number">1</span>) // e</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{d=}</span>'</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f'<span class="subst">{d.bit_length() = }</span>'</span>)</span><br><span class="line"> <span class="keyword">assert</span> e*d-<span class="number">1</span>==k*(N+<span class="number">1</span>-r)</span><br><span class="line"></span><br><span class="line"> pt = <span class="built_in">pow</span>(ct, d, N)</span><br><span class="line"> <span class="built_in">print</span>(long_to_bytes(pt))</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line"> attack()</span><br><span class="line"> </span><br><span class="line">main()</span><br></pre></td></tr></table></figure><h4 id="方法2"><a href="#方法2" class="headerlink" title="方法2"></a>方法2</h4><p>由于界比较富裕,可以根据Wiener攻击对应的二维格构造思路进行攻击。</p><p><script type="math/tex">e(d_1M + ed_0) = 1 + k(N+1-r)</script></p><p>取其中小量为 $1-kr$,将其表为已知量的线性组合</p><p><script type="math/tex">d_1\cdot eM + 1\cdot ed_0 - k\cdot (N+1) = 1-kr \quad (2)</script></p><p>构造格$\mathbf{L}$如下</p><p><script type="math/tex">(d_1,1,-k) \begin{bmatrix} eM & 0 & X_1\\ ed_0 & X_2 & 0\\ N+1 & 0 & 0 \end{bmatrix} =(1-kr,X_2,d_1X_1) =: \mathbf{v}</script></p><p>格的行列式为 $\det(\mathbf{L}) = (N+1)X_1X_2$,攻击条件为$\lvert \mathbf{v} \rvert < \det(L)^{1/3}$.</p><p><strong>最佳做法是令</strong><script type="math/tex">\mathbf{v}</script><strong>的分量绝对值量级一致</strong>,因此选择如下参数配平</p><script type="math/tex; mode=display">X_1 = 2^{1024+675-338}\ , \ X_2 = 2^{1025+675}</script><p>此时有$\lvert \bf{v} \rvert \approx 2^{1701}$, $\det(\mathbf{L})^{1/3} \approx 2^{1703}$,大致满足攻击条件。</p><p>用LLL解出$\mathbf{v}$,由第3个分量求$d_1$,再计算$d=d_1M+d_0$即可解密。</p><p><strong>一些补充:</strong></p><ol><li>三维格的多种构造方法(例如X1放到最后一行第3个),但它们的界相同。第一行不放$X_1$,$\mathbf{v}$的分量中就不涉及$d_1$。但也可根据LLL算法的行变换矩阵算出$d_1$,或解出$k$后再用式$(2)$ 算 $d_1$</li><li>二维格的界不够,最佳配平下$\det(\mathbf{L})^{1/2} \approx 2^{1590}, \ \lvert \mathbf{v} \rvert \approx 2^{1700}$</li></ol><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sage.<span class="built_in">all</span> <span class="keyword">import</span> Matrix, prod, CRT, ZZ</span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> sieve_base, long_to_bytes</span><br><span class="line"></span><br><span class="line"><span class="comment"># 攻击算法大框架与关键注释来自于SeanDictionary的wp,此处做了一些修改</span></span><br><span class="line"><span class="comment"># https://seandictionary.top/nepctf-2025/</span></span><br><span class="line"></span><br><span class="line">e=<span class="number">0x73915608ed64c9cf1a2279684cab4f4a78fba229d45d4f860971a241481363470a19cb0dc0d00f816b5befdaca017cf71483e96ef17b36179012f5194a0e6bf481bb06c2644f74c6812efb65d05c00631f282d6aa55c0bc140a1830b95a1cf4b6024cb0db53f2c2189897c41f22e2eec773723f531ec4bfa537fae6de5fe480cf46fe17850f7eb47df08194d95db3d26ac923b26e110ee645239ab586bbc546ddc5906f280a106edbb727ccb05536b5a3f5c0ebcf865c95ce58be54f7f3547aa53baa218b0dfa98e42d925fa341e45f94a3b16b0c83802660c7f34de3336cb21f219073cf8e9f5e39d47f0a9a9ee7c255f09a6add9a2f7a47960f4a853183d29</span></span><br><span class="line">N=<span class="number">0xba8956e81394f3f1265ca5d9c4ad1ab0078bb43c4b80a231ab2cc62246ae45f66a562252622aed2cbbfc08647ef2fec0f97a632bf2242845f4b3af0c427cec3d90f42e90278a5a0feeed0922a8cd2278074ac54e9cfc0e96ff68f8d8f266dd87dc1cc59c2895ec884de2022311767f6a9a7e0bd288c79620e28b83bb3c8d8ad1047c839d6ccf5544eaf434a5f00b951769ab3121298d04b63a162757beb3d49917cd0c9e02ee1ac29398c8130961d5a2f2833aba1e538edb7bb97071f40fae543d1622f0c9206c6d4d8abb2ac1b93ebfb603c2f3a909ede357ade4043550fe540d13a4e87db8d731fe130f15a43a1a00364f5da2d87f7b660c3a04e734218a11</span></span><br><span class="line"></span><br><span class="line">ct=<span class="number">0x101b284ad196b5bbd3d3df00a7d3577caeb29c681bdd122582b705afc671febf45d4f3786640e55aadd6a31ecc49175f97b772720f1735f8555f768b137a4643cd6958f80a3dfca4d0270ad463d6dde93429940bd2abb5ad8408b0906fa8d776544a1c50cc0d95939bef4c3fb64d0b52dca81ff0f244fc265bfc0bc147435d05f8f1a146e963a1403b3c123b4d6e73d1fd897109995009be1673212607f0ea7ae33d23f3158448b05c28ea6636382eee9436c4a6c09023ead7182ecd55ac73a68d458d726e1abc208810468591e63f4b4c2c1f3ce27c4800b52f7421ccab432c03e88b3b255740d719e40e0226eabb7633d97ed210e32071e2ac36ed17ef442e</span></span><br><span class="line"></span><br><span class="line">hints = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">9</span>, <span class="number">16</span>, <span class="number">10</span>, <span class="number">14</span>, <span class="number">5</span>, <span class="number">11</span>, <span class="number">21</span>, <span class="number">18</span>, <span class="number">30</span>, <span class="number">30</span>, <span class="number">38</span>, <span class="number">2</span>, <span class="number">20</span>, <span class="number">62</span>, <span class="number">66</span>, <span class="number">1</span>, <span class="number">22</span>, <span class="number">56</span>, <span class="number">41</span>, <span class="number">13</span>, <span class="number">78</span>, <span class="number">59</span>, <span class="number">51</span>, <span class="number">6</span>, <span class="number">57</span>, <span class="number">117</span>, <span class="number">73</span>, <span class="number">75</span>, <span class="number">96</span>, <span class="number">112</span>, <span class="number">50</span>, <span class="number">93</span>, <span class="number">158</span>, <span class="number">97</span>, <span class="number">146</span>, <span class="number">8</span>, <span class="number">65</span>, <span class="number">96</span>, <span class="number">186</span>, <span class="number">161</span>, <span class="number">90</span>, <span class="number">131</span>, <span class="number">46</span>, <span class="number">32</span>, <span class="number">140</span>, <span class="number">133</span>, <span class="number">50</span>, <span class="number">43</span>, <span class="number">151</span>, <span class="number">234</span>]</span><br><span class="line">d0 = CRT(hints, <span class="built_in">list</span>(sieve_base)[<span class="number">1</span>:<span class="built_in">len</span>(hints)+<span class="number">1</span>])</span><br><span class="line">M = prod(<span class="built_in">list</span>(sieve_base)[<span class="number">1</span>:<span class="built_in">len</span>(hints)+<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line"><span class="comment"># 675 = int(2048*beta)</span></span><br><span class="line"><span class="comment"># 338 ~ 1024*gamma</span></span><br><span class="line">X1 = <span class="number">2</span>**(<span class="number">1024</span>+<span class="number">675</span>-<span class="number">338</span>)</span><br><span class="line">X2 = <span class="number">2</span>**(<span class="number">1025</span>+<span class="number">675</span>)</span><br><span class="line"></span><br><span class="line">L = Matrix(ZZ, <span class="number">3</span>, <span class="number">3</span>)</span><br><span class="line">L[<span class="number">0</span>, <span class="number">0</span>] = e*M</span><br><span class="line">L[<span class="number">0</span>, <span class="number">2</span>] = X1</span><br><span class="line">L[<span class="number">1</span>, <span class="number">0</span>] = e*d0</span><br><span class="line">L[<span class="number">1</span>, <span class="number">1</span>] = X2</span><br><span class="line">L[<span class="number">2</span>, <span class="number">0</span>] = N+<span class="number">1</span></span><br><span class="line"></span><br><span class="line">L = L.LLL()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'After LLL, L=\n<span class="subst">{L}</span>'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> row <span class="keyword">in</span> L:</span><br><span class="line"> d = d0 + row[<span class="number">2</span>]//X1*M</span><br><span class="line"> <span class="built_in">print</span>(<span class="built_in">int</span>(d).bit_length(), row[<span class="number">1</span>]==X2)</span><br><span class="line"> <span class="comment"># 这里关注d的位数要等于675</span></span><br><span class="line"> <span class="comment"># 然后最短向量的中间一位应该为K2</span></span><br><span class="line"> <span class="comment"># 按照这两个约束进行调参</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">int</span>(d).bit_length() == <span class="built_in">int</span>(<span class="number">2048</span>*<span class="number">0.33</span>):</span><br><span class="line"> m = <span class="built_in">pow</span>(ct, d, N)</span><br><span class="line"> <span class="built_in">print</span>(long_to_bytes(<span class="built_in">int</span>(m)))</span><br></pre></td></tr></table></figure><h2 id="后记-amp-致谢"><a href="#后记-amp-致谢" class="headerlink" title="后记 & 致谢"></a>后记 & 致谢</h2><p>审wp时看到方法2的解法感觉比较惊喜,有2位选手用了类似的方法。此处我们对三维格构造的思想与细节做了补充,希望对大家有益。<em>方法2的代码是基于<a href="https://seandictionary.top/nepctf-2025/">SeanDictionary的wp</a>改的,这位选手将额外获得出题人(我)的一份礼物。</em></p><p>此外,方法1有可用优化,但shift多项式选取策略较为复杂。见<a href="https://eprint.iacr.org/2018/516">Partial Key Exposure Attacks on RSA: Achieving the Boneh-Durfee Bound</a>的第5节。</p><p>顺带一提,ezRSA2的续作很可能会在NepCTF 2026出现。可能涉及前作所用的技术,但难度会更高。敬请期待!</p>]]></content>
<summary type="html"><p>这是一个简单的RSA二元Coppersmith。题目中已知$d &lt; N^{0.33}$, 以及一些$d \bmod l_i$的值。这些$l_i$的乘积约为$N^{0.17}$。</p>
<p>这道题也可以用Wiener攻击的思路构造三维格求解。以下为题目和两种解法的详细说明。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="CTF" scheme="https://su1yu4n.github.io/tags/CTF/"/>
<category term="RSA" scheme="https://su1yu4n.github.io/tags/RSA/"/>
<category term="密码分析" scheme="https://su1yu4n.github.io/tags/%E5%AF%86%E7%A0%81%E5%88%86%E6%9E%90/"/>
<category term="Coppersmith" scheme="https://su1yu4n.github.io/tags/Coppersmith/"/>
</entry>
<entry>
<title>CSIDH方案短课(沙龙)</title>
<link href="https://su1yu4n.github.io/2024/10/15/CSIDH%E6%96%B9%E6%A1%88%E5%88%86%E4%BA%AB/"/>
<id>https://su1yu4n.github.io/2024/10/15/CSIDH%E6%96%B9%E6%A1%88%E5%88%86%E4%BA%AB/</id>
<published>2024-10-15T02:54:13.000Z</published>
<updated>2024-11-25T03:05:36.319Z</updated>
<content type="html"><![CDATA[<p>这段时间研究CSIDH,时间跨度接近一年了。<strong>这次分享尽可能降低了门槛,让大家听懂。</strong></p><p>个人认为CSIDH方案是数学、计算优化与工科思维的集大成者。同源密码用到的数学比较深,而同源计算也很灵活,可以将群论与工科式的想法结合。<strong>这次分享对数学原理和优化都有所覆盖。</strong></p><p>CM Torsor的性质没有深入,想了解建议看复环面/复椭圆曲线的复乘理论。</p><span id="more"></span><h2 id="前置基础-讲稿PDF和回放"><a href="#前置基础-讲稿PDF和回放" class="headerlink" title="前置基础, 讲稿PDF和回放"></a>前置基础, 讲稿PDF和回放</h2><p><a href="prerequisites.pdf">前置基础</a></p><p><a href="slides.pdf">讲稿</a></p><p><a href="https://www.bilibili.com/video/BV1yzmVY6E9r">B站回放</a></p><h2 id="提纲"><a href="#提纲" class="headerlink" title="提纲"></a>提纲</h2><h3 id="前置基础"><a href="#前置基础" class="headerlink" title="前置基础"></a>前置基础</h3><ul><li>同源基本常识<ul><li>同源的定义</li><li>同源与子群的对应关系</li><li>同源计算方法和复杂度:Velu公式(黑盒)</li></ul></li><li><p>群作用相关概念</p><ul><li>基本概念、实例</li><li>自由、可迁、挠子性质 $|G|=|X|$</li></ul></li><li><p>椭圆曲线相关</p><ul><li>超奇异椭圆曲线:$\left|E(\mathbb{F}_p)\right |=p+1$</li><li>Montgomery曲线<ul><li>曲线方程</li><li>二次扭曲与有理点群的对应</li><li><script type="math/tex">\mathbb{F}_p-</script>同构类中的唯一性</li></ul></li></ul></li></ul><h3 id="讲解内容"><a href="#讲解内容" class="headerlink" title="讲解内容"></a>讲解内容</h3><ol><li>CM Torsor和方案描述<ol><li>简述CM Torsor</li><li>方案概述</li><li><strong>群作用与同源的关系</strong></li><li><strong>密钥空间的选取</strong></li></ol></li><li>群作用计算<ol><li><strong>群作用计算流程</strong></li><li><strong>群作用层面优化介绍</strong></li><li>简述为何高效:无需扩域、仅需x坐标、避免求逆</li><li>CSIDH方案计算层次</li></ol></li><li>安全性简介 <ol><li>经典安全性:$O(\mathcal{K}^{1/2})$ 中间相遇</li><li>量子安全性:亚指数,512 ~ “60 qbits”</li></ol></li><li>实用性简介<ol><li>优势:NIKE (0-RTT TLS, X3DH中替换经典DH的备选) , 密钥尺寸小</li><li>劣势:计算耗时:一次群作用100ms (2048 ~ NIST-I)</li></ol></li></ol>]]></content>
<summary type="html"><p>这段时间研究CSIDH,时间跨度接近一年了。<strong>这次分享尽可能降低了门槛,让大家听懂。</strong></p>
<p>个人认为CSIDH方案是数学、计算优化与工科思维的集大成者。同源密码用到的数学比较深,而同源计算也很灵活,可以将群论与工科式的想法结合。<strong>这次分享对数学原理和优化都有所覆盖。</strong></p>
<p>CM Torsor的性质没有深入,想了解建议看复环面/复椭圆曲线的复乘理论。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="isogeny" scheme="https://su1yu4n.github.io/tags/isogeny/"/>
<category term="CSIDH" scheme="https://su1yu4n.github.io/tags/CSIDH/"/>
</entry>
<entry>
<title>Solution to S0DH in D3CTF 2024</title>
<link href="https://su1yu4n.github.io/2024/04/30/Solution-to-S0DH/"/>
<id>https://su1yu4n.github.io/2024/04/30/Solution-to-S0DH/</id>
<published>2024-04-30T03:19:45.000Z</published>
<updated>2024-11-23T11:00:48.286Z</updated>
<content type="html"><![CDATA[<p>Here’s the official writeup for S0DH, including the challenge and solutions (intended and unintended).<br><span id="more"></span></p><h2 id="The-challenge"><a href="#The-challenge" class="headerlink" title="The challenge"></a>The challenge</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sage.<span class="built_in">all</span> <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> bytes_to_long</span><br><span class="line"><span class="keyword">from</span> secret <span class="keyword">import</span> flag</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"></span><br><span class="line">flag_start = <span class="string">b'd3ctf{'</span></span><br><span class="line"><span class="keyword">assert</span> flag.startswith(flag_start)</span><br><span class="line">flag = flag[<span class="built_in">len</span>(flag_start):-<span class="number">1</span>]</span><br><span class="line"><span class="keyword">assert</span> <span class="built_in">len</span>(flag) == <span class="number">32</span></span><br><span class="line"></span><br><span class="line">a = <span class="number">38</span></span><br><span class="line">b = <span class="number">25</span></span><br><span class="line">p = <span class="number">2</span>**a * <span class="number">3</span>**b - <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> is_prime(p)</span><br><span class="line">Fp = GF(p)</span><br><span class="line"></span><br><span class="line">Fpx = PolynomialRing(Fp, <span class="string">"x"</span>)</span><br><span class="line">x = Fpx.gen()</span><br><span class="line">Fp2 = Fp.extension(x**<span class="number">2</span> + <span class="number">1</span>, <span class="string">"ii"</span>)</span><br><span class="line">ii = Fp2.gen()</span><br><span class="line"></span><br><span class="line">A0 = Fp2(<span class="number">6</span>)</span><br><span class="line">E0 = EllipticCurve(Fp2, [<span class="number">0</span>, A0, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">E0.set_order((p+<span class="number">1</span>)**<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">NOTE: Follow SIKE's spec in the generation of E[2^a] torsion basis.</span></span><br><span class="line"><span class="string">It will allow you to compute the isogeny faster.</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"></span><br><span class="line">sqrtof2 = Fp2(<span class="number">2</span>).sqrt()</span><br><span class="line">f = x**<span class="number">3</span> + A0 * x**<span class="number">2</span> + x</span><br><span class="line"></span><br><span class="line">Pa = E0(<span class="number">0</span>)</span><br><span class="line">Qa = E0(<span class="number">0</span>)</span><br><span class="line">Pa_done = <span class="literal">False</span></span><br><span class="line">Qa_done = <span class="literal">False</span></span><br><span class="line">d = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> c <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>, p):</span><br><span class="line"> Rx = ii + c</span><br><span class="line"> Ry_square = f(ii + c)</span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> Ry_square.is_square():</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> Ra = E0.lift_x(Rx)</span><br><span class="line"> Pa = <span class="number">3</span>**b * Ra</span><br><span class="line"></span><br><span class="line"> Ta = <span class="number">2</span> ** (a - <span class="number">1</span>) * Pa</span><br><span class="line"> <span class="keyword">if</span> Ta.is_zero():</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> Tax_plus_3 = Ta.xy()[<span class="number">0</span>] + <span class="number">3</span></span><br><span class="line"> <span class="keyword">if</span> Tax_plus_3 == <span class="number">2</span> * sqrtof2 <span class="keyword">or</span> Tax_plus_3 == -<span class="number">2</span> * sqrtof2:</span><br><span class="line"> Pa_done = <span class="literal">True</span></span><br><span class="line"> <span class="keyword">elif</span> Tax_plus_3 == <span class="number">3</span> <span class="keyword">and</span> <span class="keyword">not</span> Qa_done:</span><br><span class="line"> Qa = Pa</span><br><span class="line"> Qa_done = <span class="literal">True</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">raise</span> ValueError(<span class="string">'Unexcepted order 2 point.'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> Pa_done <span class="keyword">and</span> Qa_done:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> Pa.order() == <span class="number">2</span>**a <span class="keyword">and</span> Qa.order() == <span class="number">2</span>**a</span><br><span class="line"><span class="keyword">assert</span> Pa.weil_pairing(Qa, <span class="number">2</span>**a) ** (<span class="number">2</span> ** (a - <span class="number">1</span>)) != <span class="number">1</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Pb = E0(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">while</span> (<span class="number">3</span>**(b-<span class="number">1</span>))*Pb == <span class="number">0</span>:</span><br><span class="line"> Pb = <span class="number">2</span>**a * E0.random_point()</span><br><span class="line">Qb = Pb</span><br><span class="line"><span class="keyword">while</span> Pb.weil_pairing(Qb, <span class="number">3</span>**b)**(<span class="number">3</span>**(b-<span class="number">1</span>)) == <span class="number">1</span>:</span><br><span class="line"> Qb = <span class="number">2</span>**a * E0.random_point()</span><br><span class="line"></span><br><span class="line"><span class="comment"># print(Pa,Qa,Pb,Qb)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Pa = <span class="subst">{Pa.xy()}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Qa = <span class="subst">{Qa.xy()}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Pb = <span class="subst">{Pb.xy()}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Qb = <span class="subst">{Qb.xy()}</span>'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">sa = randint(<span class="number">0</span>, <span class="number">2</span>**a-<span class="number">1</span>)</span><br><span class="line">Ra = Pa + sa * Qa</span><br><span class="line">phia = E0.isogeny(kernel=Ra, algorithm=<span class="string">'factored'</span>, model=<span class="string">'montgomery'</span>, check=<span class="literal">False</span>)</span><br><span class="line">Ea = phia.codomain()</span><br><span class="line"></span><br><span class="line">sb = randint(<span class="number">0</span>, <span class="number">3</span>**b-<span class="number">1</span>)</span><br><span class="line">Rb = Pb + sb * Qb</span><br><span class="line">phib = E0.isogeny(kernel=Rb, algorithm=<span class="string">'factored'</span>, model=<span class="string">'montgomery'</span>, check=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line">Ea, phia_Pb, phia_Qb = phia.codomain(), phia(Pb), phia(Qb)</span><br><span class="line">Eb, phib_Pa, phib_Qa = phib.codomain(), phib(Pa), phib(Qa)</span><br><span class="line"></span><br><span class="line"><span class="comment"># This time, no Alice torsion point image.</span></span><br><span class="line"><span class="comment"># print(phia_Pb,phia_Qb)</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'phib_Pa = <span class="subst">{phib_Pa.xy()}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'phib_Qa = <span class="subst">{phib_Qa.xy()}</span>'</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Ea: <span class="subst">{Ea}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'Eb: <span class="subst">{Eb}</span>'</span>)</span><br><span class="line"></span><br><span class="line">phib_Ra = phib_Pa + sa * phib_Qa</span><br><span class="line">Eab = Eb.isogeny(kernel=phib_Ra, algorithm=<span class="string">'factored'</span>, model=<span class="string">'montgomery'</span>, check=<span class="literal">False</span>).codomain()</span><br><span class="line">jab = Eab.j_invariant()</span><br><span class="line"></span><br><span class="line">phia_Rb = phia_Pb + sb * phia_Qb</span><br><span class="line">Eba = Ea.isogeny(kernel=phia_Rb, algorithm=<span class="string">'factored'</span>, model=<span class="string">'montgomery'</span>, check=<span class="literal">False</span>).codomain()</span><br><span class="line">jba = Eba.j_invariant()</span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> jab == jba</span><br><span class="line">h = bytes_to_long(hashlib.sha256(<span class="built_in">str</span>(jab).encode()).digest())</span><br><span class="line">enc = h ^ bytes_to_long(flag)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'enc = <span class="subst">{enc}</span>'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">Pa = (199176096138773310217268*ii + 230014803812894614137371, 21529721453350773259901*ii + 106703903226801547853572)</span></span><br><span class="line"><span class="string">Qa = (8838268627404727894538*ii + 42671830598079803454272, 232086518469911650058383*ii + 166016721414371687782077)</span></span><br><span class="line"><span class="string">Pb = (200990566762780078867585*ii + 156748548599313956052974, 124844788269234253758677*ii + 161705339892396558058330)</span></span><br><span class="line"><span class="string">Qb = (39182754631675399496884*ii + 97444897625640048145787, 80099047967631528928295*ii + 178693902138964187125027)</span></span><br><span class="line"><span class="string">phib_Pa = (149703758091223422379828*ii + 52711226604051274601866, 112079580687990456923625*ii + 147229726400811363889895)</span></span><br><span class="line"><span class="string">phib_Qa = (181275595028116997198711*ii + 186563896197914896999639, 181395845909382894304538*ii + 69293294106635311075792)</span></span><br><span class="line"><span class="string">Ea: Elliptic Curve defined by y^2 = x^3 + (11731710804095179287932*ii+170364860453198752624563)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2</span></span><br><span class="line"><span class="string">Eb: Elliptic Curve defined by y^2 = x^3 + (191884939246592021710422*ii+96782382528277357218650)*x^2 + x over Finite Field in ii of size 232900919541184113672191^2</span></span><br><span class="line"><span class="string">enc = 48739425383997297710665612312049549178322149326453305960348697253918290539788</span></span><br><span class="line"><span class="string">"""</span></span><br></pre></td></tr></table></figure><h2 id="The-Flag"><a href="#The-Flag" class="headerlink" title="The Flag"></a>The Flag</h2><p><code>d3ctf{is0geny_gr4ph_m33t_1n_7he_m1ddl3}</code></p><h2 id="Intended-Solution"><a href="#Intended-Solution" class="headerlink" title="Intended Solution"></a>Intended Solution</h2><h3 id="The-main-idea"><a href="#The-main-idea" class="headerlink" title="The main idea"></a>The main idea</h3><p>Meet in the middle attack has time and space complexity $O(2^{a/2}) = O(p^{1/4})$. Using the given isogeny computing function, it takes about 1h to solve Alice’s secret isogeny $\phi_a$.</p><h3 id="MITM"><a href="#MITM" class="headerlink" title="MITM"></a>MITM</h3><p>Let $K_a = 2^{a/2}P_a + s_a \cdot 2^{a/2}Q_a$, where $\left \langle P_a + s_a \cdot Q_a\right\rangle$ is the kernel of $\phi_a$. As a path in the 2-isogeny graph, $\phi_a$ passes through the node $E_{mid1} := E_0/ \left\langle{K_a}\right\rangle$. </p><p>Therefore we can compute all possible $2^{a/2}$-isogenies and construct a hash table. The keys are the j-invariant of codomains and the values are ${s_a}\pmod{2^{a/2}}$. </p><p><em>Remark: In my script, I compute $2^{a/2+1}$-isogenies and construct the hash table. Because I planned to set a=43 at first.</em></p><h4 id="Use-the-j-invariant-as-the-key-of-hash-table"><a href="#Use-the-j-invariant-as-the-key-of-hash-table" class="headerlink" title="Use the j-invariant as the key of hash table"></a>Use the j-invariant as the key of hash table</h4><p>Note that each node of isogeny graph is an isomorphism class (over $\mathbb{F_{p^2}}$) of elliptic curve, so we need to compute the j-invariant (an isomorphic invariant) and use it as the key of our hash table.</p><p>The j-invariant of a untwisted Montgomery curve $E_A$ is </p><script type="math/tex; mode=display">j_A = \frac{256(A^2-3)^3}{A^2 - 4}.</script><p>To avoid unnecessary computation of inversion, write $A = A_x/A_z$ and we get </p><script type="math/tex; mode=display">j_A = \frac{256(A_x^2 - 3A_z^2)^3}{A_z^4(A_x^2 - 4A_z^2)}.</script><p><em>See [1] for the j-invariant.</em></p><p>So we can use 1 inversion to compute the $j_A$ from the fractional representation of $A$.</p><h4 id="Working-with-the-given-isogeny-formula"><a href="#Working-with-the-given-isogeny-formula" class="headerlink" title="Working with the given isogeny formula"></a>Working with the given isogeny formula</h4><p>Note that computing $2^a$-isogeny requires us to compute a chain a 2-isogeny and 4-isogeny. As <a href="https://sike.org/files/SIDH-spec.pdf">SIKE’s spec</a> pointed out in page 6~7, the input kernel point of isog2 cannot be $(0,0)$, and the input kernel point of isog4 cannot be $(1, \cdot)$ or $(-1, \cdot)$. </p><p>So how can we make use of this formula to compute isogenies starting from $E_a$?<br>The generation process of $P_a$ and $Q_a$ in <code>challenge.py</code> suggests that we can choose $Q_a’$ such that $2^{a-1} \cdot Q_a’ = (0,0)$, and choose a $P_a’$ such that $e_{2^{a}}(P_a’, Q_a’)$ is a primitive $2^a$-th root.</p><h4 id="Searching-from-E-a"><a href="#Searching-from-E-a" class="headerlink" title="Searching from $E_a$"></a>Searching from $E_a$</h4><p>According to the structure of 2-isogeny graph, there are $3 \cdot 2^{a/2-1} $ isogenies to try. But taking $2^{a/2}P_a’ + s_a’ \cdot 2^{a/2}Q_a’$ as the kernel only makes $2^{a/2}$ isogenies. </p><p>In fact, the other isogenies correspond to $\left\langle{t_a’P_a’ + Q_a’}\right\rangle$, where $t_a’=0,2, …, 2^{a/2}$.</p><h3 id="After-MITM"><a href="#After-MITM" class="headerlink" title="After MITM"></a>After MITM</h3><p>The collision gives us ${s_a}\pmod{2^a}$ and $t_a’, s_a’$ , where $E_{mid2} := E_a/\left\langle K_a’\right\rangle \cong E_{mid1}$ and $K_a’ = 2^{a/2}(t_a’P_a’ + s_a’Q_a’)$</p><p>Denote $\phi_1: E_0 \to E_{mid1}$, $\phi_2: E_a \to E_{mid2}$, $\sigma: E_{mid1} \xrightarrow{\sim} E_{mid2}$ .<br>We can reconstruct the isogeny $\phi_a = \hat{\phi_2} \circ \sigma \circ \phi_1$ with the help of sagemath.</p><p>Since $\phi_a(P_a+s_aQ_a) = O$, we have $\phi_a(P_a) = -s_a\phi_a(Q_a)$. So we can solve the discrete logarithm to recover $s_a$</p><p>Now it is sufficient to follow SIDH protocol to find $j_{AB}$.</p><h3 id="Some-Further-Optimization"><a href="#Some-Further-Optimization" class="headerlink" title="Some Further Optimization"></a>Some Further Optimization</h3><p>In fact, there are some further optimization for the attack [3] and the computation of isogeny chain (optimal strategy) [2, 4]. </p><h3 id="code"><a href="#code" class="headerlink" title="code"></a>code</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sage.<span class="built_in">all</span> <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="comment"># import multiprocessing as mp</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment">## Parameters</span></span><br><span class="line"></span><br><span class="line">a = <span class="number">38</span></span><br><span class="line">b = <span class="number">25</span></span><br><span class="line">p = <span class="number">2</span>**a * <span class="number">3</span>**b - <span class="number">1</span></span><br><span class="line"><span class="keyword">assert</span> is_prime(p)</span><br><span class="line"></span><br><span class="line">Fp = GF(p)</span><br><span class="line"></span><br><span class="line">Fpx = PolynomialRing(Fp, <span class="string">"x"</span>)</span><br><span class="line">x = Fpx.gen()</span><br><span class="line">Fp2 = Fp.extension(x**<span class="number">2</span> + <span class="number">1</span>, <span class="string">"ii"</span>)</span><br><span class="line">ii = Fp2.gen()</span><br><span class="line"></span><br><span class="line">A0 = Fp2(<span class="number">6</span>)</span><br><span class="line">E0 = EllipticCurve(Fp2, [<span class="number">0</span>, A0, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line"><span class="keyword">assert</span> E0.is_supersingular(proof=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Pa = (<span class="number">199176096138773310217268</span>*ii + <span class="number">230014803812894614137371</span>, <span class="number">21529721453350773259901</span>*ii + <span class="number">106703903226801547853572</span>)</span><br><span class="line">Qa = (<span class="number">8838268627404727894538</span>*ii + <span class="number">42671830598079803454272</span>, <span class="number">232086518469911650058383</span>*ii + <span class="number">166016721414371687782077</span>)</span><br><span class="line">Pb = (<span class="number">200990566762780078867585</span>*ii + <span class="number">156748548599313956052974</span>, <span class="number">124844788269234253758677</span>*ii + <span class="number">161705339892396558058330</span>)</span><br><span class="line">Qb = (<span class="number">39182754631675399496884</span>*ii + <span class="number">97444897625640048145787</span>, <span class="number">80099047967631528928295</span>*ii + <span class="number">178693902138964187125027</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Pa = E0(Pa)</span><br><span class="line">Qa = E0(Qa)</span><br><span class="line">Pb = E0(Pb)</span><br><span class="line">Qb = E0(Qb)</span><br><span class="line"></span><br><span class="line">ka = <span class="number">11731710804095179287932</span>*ii+<span class="number">170364860453198752624563</span></span><br><span class="line">kb = <span class="number">191884939246592021710422</span>*ii+<span class="number">96782382528277357218650</span></span><br><span class="line">Ea = EllipticCurve(Fp2, [<span class="number">0</span>, ka, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">Eb = EllipticCurve(Fp2, [<span class="number">0</span>, kb, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">phib_Pa = (<span class="number">149703758091223422379828</span>*ii + <span class="number">52711226604051274601866</span>, <span class="number">112079580687990456923625</span>*ii + <span class="number">147229726400811363889895</span>)</span><br><span class="line">phib_Qa = (<span class="number">181275595028116997198711</span>*ii + <span class="number">186563896197914896999639</span>, <span class="number">181395845909382894304538</span>*ii + <span class="number">69293294106635311075792</span>)</span><br><span class="line">phib_Pa = Eb(phib_Pa)</span><br><span class="line">phib_Qa = Eb(phib_Qa)</span><br><span class="line"></span><br><span class="line">enc = <span class="number">48739425383997297710665612312049549178322149326453305960348697253918290539788</span></span><br><span class="line"></span><br><span class="line"><span class="comment">## attack</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">### isogenys</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">xA24</span>(<span class="params">Aaffine</span>):</span><br><span class="line"> <span class="keyword">return</span> Aaffine + <span class="number">2</span>, <span class="number">4</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_A_from_A24</span>(<span class="params">A24: <span class="built_in">tuple</span></span>):</span><br><span class="line"> A2C, FOUR_C = A24</span><br><span class="line"> FOUR_A = <span class="number">2</span> * A2C - FOUR_C <span class="comment"># A+2C + A+2C - 4C = 2A</span></span><br><span class="line"> FOUR_A = <span class="number">2</span> * FOUR_A <span class="comment"># 2A + 2A = 4A</span></span><br><span class="line"> <span class="keyword">return</span> FOUR_A, FOUR_C</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Get j-invariant from coeff (coeff in the form of fraction)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_j_invariant</span>(<span class="params">A: <span class="built_in">tuple</span></span>):</span><br><span class="line"> Ax, Az = A</span><br><span class="line"> Ax_square = Ax**<span class="number">2</span></span><br><span class="line"> Az_square = Az**<span class="number">2</span></span><br><span class="line"> Jx = <span class="number">256</span> * (Ax_square - <span class="number">3</span> * Az_square) ** <span class="number">3</span> <span class="comment"># Jx = 256(Ax^2 - 3Az^2)^3</span></span><br><span class="line"> Jz = Ax_square * Az_square**<span class="number">2</span> - <span class="number">4</span> * Az_square**<span class="number">3</span> <span class="comment"># Jz = Ax^2*Az^4 - 4Az^6</span></span><br><span class="line"> <span class="keyword">if</span> Jz == <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"A = <span class="subst">{A}</span>"</span>)</span><br><span class="line"> <span class="keyword">return</span> Jx * Jz ** (-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># phi: E -> E/<P> =: E2</span></span><br><span class="line"><span class="comment"># All points of input and output are projective x-coordinate,</span></span><br><span class="line"><span class="comment"># i.e. if P = (XP: YP: ZP) ∈ E, then P is (XP, ZP) in the code</span></span><br><span class="line"><span class="comment"># Input: E's A24, kernel point K of order 2, T the point to push</span></span><br><span class="line"><span class="comment"># Output: E2's A24, phi(T)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">isog2</span>(<span class="params">K, T</span>):</span><br><span class="line"> <span class="keyword">if</span> K[<span class="number">0</span>] == <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Meet the case we cannot use isog2."</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># return new curve's A24 = (A+2C: 4C).q</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">xisog2</span>(<span class="params">K</span>):</span><br><span class="line"> XP, ZP = K</span><br><span class="line"> A24_plus = XP**<span class="number">2</span></span><br><span class="line"> C24 = ZP**<span class="number">2</span></span><br><span class="line"> A2C = C24 - A24_plus</span><br><span class="line"> <span class="keyword">return</span> A2C, C24</span><br><span class="line"></span><br><span class="line"> <span class="comment"># P: kernel point, Q: point to push</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">xeval2</span>(<span class="params">P, Q</span>):</span><br><span class="line"> XP, ZP = P</span><br><span class="line"> XQ, ZQ = Q</span><br><span class="line"> T0 = XP + ZP</span><br><span class="line"> T1 = XP - ZP</span><br><span class="line"> T2 = XQ + ZQ</span><br><span class="line"> T3 = XQ - ZQ</span><br><span class="line"> T0 = T0 * T3</span><br><span class="line"> T1 = T1 * T2</span><br><span class="line"> T2 = T0 + T1</span><br><span class="line"> T3 = T0 - T1</span><br><span class="line"> XR = XQ * T2</span><br><span class="line"> ZR = ZQ * T3</span><br><span class="line"> <span class="keyword">return</span> XR, ZR</span><br><span class="line"></span><br><span class="line"> A24new = xisog2(K)</span><br><span class="line"> <span class="comment"># Anew = get_A_from_A24(A24new)</span></span><br><span class="line"> phiT = xeval2(K, T)</span><br><span class="line"> <span class="comment"># return Anew, phiT</span></span><br><span class="line"> <span class="keyword">return</span> A24new, phiT</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">isog4</span>(<span class="params">K, T</span>):</span><br><span class="line"> <span class="comment"># get new curve's A24 and three coeff for xeval4</span></span><br><span class="line"> <span class="keyword">if</span> K[<span class="number">0</span>] == <span class="number">1</span> <span class="keyword">or</span> K[<span class="number">0</span>] == -<span class="number">1</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">xisog4</span>(<span class="params">P</span>):</span><br><span class="line"> XP, ZP = P</span><br><span class="line"></span><br><span class="line"> K2 = XP - ZP</span><br><span class="line"> K3 = XP + ZP</span><br><span class="line"> K1 = ZP**<span class="number">2</span></span><br><span class="line"> K1 = K1 + K1</span><br><span class="line"> C24 = K1**<span class="number">2</span></span><br><span class="line"> K1 = K1 + K1</span><br><span class="line"> A24_plus = XP**<span class="number">2</span></span><br><span class="line"> A24_plus = A24_plus + A24_plus</span><br><span class="line"> A24_plus = A24_plus**<span class="number">2</span></span><br><span class="line"> <span class="keyword">return</span> (A24_plus, C24), (K1, K2, K3)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">xeval4</span>(<span class="params">P, coeff</span>):</span><br><span class="line"> XP, ZP = P</span><br><span class="line"> T0 = XP + ZP</span><br><span class="line"> T1 = XP - ZP</span><br><span class="line"> XP = T0 * coeff[<span class="number">1</span>]</span><br><span class="line"> ZP = T1 * coeff[<span class="number">2</span>]</span><br><span class="line"> T0 = T0 * T1</span><br><span class="line"> T0 = coeff[<span class="number">0</span>] * T0</span><br><span class="line"> T1 = XP + ZP</span><br><span class="line"> ZP = XP - ZP</span><br><span class="line"> T1 = T1**<span class="number">2</span></span><br><span class="line"> ZP = ZP**<span class="number">2</span></span><br><span class="line"> XP = T1 + T0</span><br><span class="line"> T0 = ZP - T0</span><br><span class="line"> XR = XP * T1</span><br><span class="line"> ZR = ZP * T0</span><br><span class="line"> <span class="keyword">return</span> XR, ZR</span><br><span class="line"></span><br><span class="line"> A24, coeff = xisog4(K)</span><br><span class="line"> phi_T = xeval4(T, coeff)</span><br><span class="line"> <span class="keyword">return</span> A24, phi_T</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">xmul_2k</span>(<span class="params">A24: <span class="built_in">tuple</span>, k: <span class="built_in">int</span>, T: <span class="built_in">tuple</span></span>):</span><br><span class="line"> <span class="keyword">assert</span> k >= <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">xdbl</span>(<span class="params">P: <span class="built_in">tuple</span>, A24: <span class="built_in">tuple</span></span>) -> <span class="built_in">tuple</span>:</span><br><span class="line"> XP, ZP = P</span><br><span class="line"> <span class="comment"># assert XP != 0 and ZP != 0</span></span><br><span class="line"> <span class="keyword">if</span> XP == <span class="number">0</span> <span class="keyword">or</span> ZP == <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"k=<span class="subst">{k}</span>"</span>)</span><br><span class="line"> <span class="comment"># print(f'XP={XP}')</span></span><br><span class="line"> <span class="comment"># print(f'ZP={ZP}')</span></span><br><span class="line"> V1 = XP + ZP <span class="comment"># line 1 of my pseudo code</span></span><br><span class="line"> V1 **= <span class="number">2</span></span><br><span class="line"> V2 = XP - ZP</span><br><span class="line"> V2 **= <span class="number">2</span></span><br><span class="line"> Z2P = A24[<span class="number">1</span>] * V2</span><br><span class="line"> X2P = Z2P * V1 <span class="comment"># line 6 of my pseudo code</span></span><br><span class="line"> V1 -= V2</span><br><span class="line"> Z2P += A24[<span class="number">0</span>] * V1</span><br><span class="line"> Z2P *= V1</span><br><span class="line"> <span class="keyword">return</span> X2P, Z2P</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(k):</span><br><span class="line"> T = xdbl(T, A24)</span><br><span class="line"> <span class="keyword">return</span> T</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># A: Estart affine coeff, T: kernel point (sagemath EC point object), k: T has order 2**k (same as the degree of this isogeny)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">isog_2k</span>(<span class="params">A, T, k</span>):</span><br><span class="line"> T = T[<span class="number">0</span>], T[<span class="number">2</span>]</span><br><span class="line"> A24 = xA24(A)</span><br><span class="line"> <span class="keyword">if</span> k % <span class="number">2</span> == <span class="number">1</span>:</span><br><span class="line"> <span class="comment"># T has order 2^a</span></span><br><span class="line"> P = T</span><br><span class="line"> P = xmul_2k(A24, k - <span class="number">1</span>, P) <span class="comment"># now P has order 2</span></span><br><span class="line"> result_isog2 = isog2(P, T)</span><br><span class="line"> <span class="keyword">if</span> result_isog2 <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"> A24, T = result_isog2</span><br><span class="line"> k -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">assert</span> k % <span class="number">2</span> == <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>, k + <span class="number">2</span>, <span class="number">2</span>):</span><br><span class="line"> <span class="comment"># T has order 2^(a-i+1)</span></span><br><span class="line"> P = T</span><br><span class="line"> P = xmul_2k(A24, k - i, P) <span class="comment"># now P has order 4</span></span><br><span class="line"> result_isog4 = isog4(P, T)</span><br><span class="line"> <span class="keyword">if</span> result_isog4 <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"> A24, T = result_isog4</span><br><span class="line"></span><br><span class="line"> Anew = get_A_from_A24(A24)</span><br><span class="line"> J = get_j_invariant(Anew)</span><br><span class="line"> <span class="keyword">return</span> J, Anew</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">### MITM</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#### Building a hash table, start from E0</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">compute_hash_table</span>(<span class="params">sa_start=<span class="number">0</span>, sa_stop=<span class="number">2</span> ** (<span class="params">a // <span class="number">2</span> - <span class="number">1</span></span>), steps=a // <span class="number">2</span> + <span class="number">1</span></span>):</span><br><span class="line"> table = {}</span><br><span class="line"></span><br><span class="line"> Pa_new = <span class="number">2</span> ** (a - steps) * Pa</span><br><span class="line"> Qa_new = <span class="number">2</span> ** (a - steps) * Qa</span><br><span class="line"> sa = sa_start</span><br><span class="line"></span><br><span class="line"> Ra = Pa_new + sa * Qa_new</span><br><span class="line"> <span class="keyword">while</span> sa < sa_stop:</span><br><span class="line"> <span class="comment"># Using the basis in SIKE spec, our formula never fail.</span></span><br><span class="line"> Jnew, Anew = isog_2k(A0, Ra, steps)</span><br><span class="line"> <span class="comment"># table[Jnew] = (Anew, sa)</span></span><br><span class="line"> table[Jnew] = sa</span><br><span class="line"> <span class="comment"># table[str(Jnew)]</span></span><br><span class="line"> Ra += Qa_new</span><br><span class="line"> sa += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> table</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">time1 = time.time()</span><br><span class="line"></span><br><span class="line">steps = a // <span class="number">2</span> + <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Start computing table."</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># <span class="doctag">NOTE:</span> The following code for parallel will raise segmentation fault on my PC...</span></span><br><span class="line"><span class="comment"># Maybe the problem has something to do with thread lock of finite field element?</span></span><br><span class="line"></span><br><span class="line"><span class="comment">## multiproc</span></span><br><span class="line"><span class="comment"># num_proc = 12</span></span><br><span class="line"><span class="comment"># # assert num_proc % 2 == 0</span></span><br><span class="line"><span class="comment"># size_per_proc = 2**steps // num_proc</span></span><br><span class="line"><span class="comment"># parameters = [[i*size_per_proc, (i+1)*size_per_proc, steps] for i in range(0, num_proc)]</span></span><br><span class="line"><span class="comment"># parameters[-1][1] = 2**steps</span></span><br><span class="line"><span class="comment"># print(f'parameters = {parameters}')</span></span><br><span class="line"><span class="comment"># with mp.Pool(num_proc) as p:</span></span><br><span class="line"><span class="comment"># tables = p.starmap(compute_hash_table, parameters)</span></span><br><span class="line"></span><br><span class="line">table2 = compute_hash_table(<span class="number">0</span>, <span class="number">2</span>**steps, steps)</span><br><span class="line"></span><br><span class="line">time2 = time.time()</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f"Hash table built, takes <span class="subst">{time2-time1}</span> seconds"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># <span class="doctag">NOTE:</span> You need to convert finite field type to str, Integer type to int before json.dump</span></span><br><span class="line"><span class="comment"># with open('hash_table.json', 'w') as f:</span></span><br><span class="line"><span class="comment"># json.dump(table2)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">### from another side (start from Ea)</span></span><br><span class="line"></span><br><span class="line">Pa_E0 = deepcopy(Pa)</span><br><span class="line">Qa_E0 = deepcopy(Qa)</span><br><span class="line"></span><br><span class="line"><span class="comment"># First choose a nice basis for Ea[2^b]</span></span><br><span class="line">Pa = Ea(<span class="number">0</span>)</span><br><span class="line">Qa = Ea(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> Qa = Ea.random_point()</span><br><span class="line"> Qa = <span class="number">3</span>**b * Qa</span><br><span class="line"> Ra = <span class="number">2</span> ** (a - <span class="number">1</span>) * Qa</span><br><span class="line"> <span class="keyword">if</span> Ra.is_zero():</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> <span class="keyword">assert</span> Ra.order() == <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> Ra.xy()[<span class="number">0</span>] == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"Ra = <span class="subst">{Ra}</span>"</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Qa found."</span>)</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> Pa = Ea.random_point()</span><br><span class="line"> Pa = <span class="number">3</span>**b * Pa</span><br><span class="line"> <span class="keyword">if</span> Pa.weil_pairing(Qa, <span class="number">2</span>**a) ** (a - <span class="number">1</span>) != <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Pa found."</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> Pa.order() == <span class="number">2</span>**a <span class="keyword">and</span> Qa.order() == <span class="number">2</span>**a</span><br><span class="line"><span class="keyword">assert</span> Pa.weil_pairing(Qa, <span class="number">2</span>**a) ** (<span class="number">2</span> ** (a - <span class="number">1</span>)) != <span class="number">1</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">steps = a - steps</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">search_from_Ea</span>(<span class="params">steps=steps</span>):</span><br><span class="line"> <span class="comment"># Save the collision with hashtable where the kernel is taPa + saQa</span></span><br><span class="line"> collision_isogenies = []</span><br><span class="line"> <span class="comment"># Save failed isogeny(ta, sa) where the kernel is taPa + saQa</span></span><br><span class="line"> Pa_new = <span class="number">2</span> ** (a - steps) * Pa</span><br><span class="line"> Qa_new = <span class="number">2</span> ** (a - steps) * Qa</span><br><span class="line"> failed_isogenies = []</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">search_one_isogeny</span>(<span class="params">ta, sa, Ra</span>):</span><br><span class="line"> result_isog2k = isog_2k(ka, Ra, steps)</span><br><span class="line"> <span class="keyword">if</span> result_isog2k <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"Isogeny failed for ta=<span class="subst">{ta}</span>, sa=<span class="subst">{sa}</span>"</span>)</span><br><span class="line"> failed_isogenies.append((ta, sa))</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> Jnew, Anew = result_isog2k</span><br><span class="line"> <span class="keyword">if</span> Jnew <span class="keyword">in</span> table2:</span><br><span class="line"> collision_isogenies.append((ta, sa, table2[Jnew]))</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Found one collision."</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"Start from Ea, sa=<span class="subst">{sa}</span>, ta=<span class="subst">{ta}</span>"</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"Start from E0, sa=<span class="subst">{table2[Jnew]}</span>"</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">f"Meet at A=<span class="subst">{Anew}</span>"</span>)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># First try these 2**steps SIDH-like isogeny</span></span><br><span class="line"> sa = <span class="number">0</span></span><br><span class="line"> Ra = Pa_new</span><br><span class="line"> <span class="keyword">while</span> sa < <span class="number">2</span>**steps:</span><br><span class="line"> search_one_isogeny(ta=<span class="number">1</span>, sa=sa, Ra=Ra)</span><br><span class="line"> Ra += Qa_new</span><br><span class="line"> sa += <span class="number">1</span></span><br><span class="line"> <span class="comment"># Note that we also need to try these isogenies correspond to <(0, 1)>, <(2, 1)>, ..., <(2**steps, 1)></span></span><br><span class="line"> ta = <span class="number">0</span></span><br><span class="line"> Ra = Qa_new</span><br><span class="line"> two_Pa_new = <span class="number">2</span> * Pa_new</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(collision_isogenies) == <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Collision not found in SIDH like isogenies"</span>)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Start searching the second part!"</span>)</span><br><span class="line"> <span class="keyword">while</span> ta < <span class="number">2</span>**steps:</span><br><span class="line"> search_one_isogeny(ta=ta, sa=<span class="number">1</span>, Ra=Ra)</span><br><span class="line"> Ra += two_Pa_new</span><br><span class="line"> ta += <span class="number">2</span></span><br><span class="line"> <span class="keyword">return</span> collision_isogenies, failed_isogenies</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">time1 = time.time()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Start searching from Ea!!"</span>)</span><br><span class="line">collision_isogenies, failed_isogenies = search_from_Ea(steps)</span><br><span class="line"></span><br><span class="line">time2 = time.time()</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f"Collision search from Ea over, takes <span class="subst">{time2-time1}</span> seconds"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">### reconstruct phi using sagemath</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f"collision_isogenies = <span class="subst">{collision_isogenies}</span>"</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f"failed_isogenies = <span class="subst">{failed_isogenies}</span>"</span>)</span><br><span class="line"></span><br><span class="line">ta, sa, sa_E0 = collision_isogenies[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line">Pa_new_E0 = (<span class="number">2</span>**steps) * Pa_E0</span><br><span class="line">Qa_new_E0 = (<span class="number">2</span>**steps) * Qa_E0</span><br><span class="line">Ka_E0 = Pa_new_E0 + sa_E0 * Qa_new_E0</span><br><span class="line">phi1 = E0.isogeny(kernel=Ka_E0, algorithm=<span class="string">"factored"</span>, model=<span class="string">"montgomery"</span>)</span><br><span class="line">E_middle_1 = phi1.codomain()</span><br><span class="line"></span><br><span class="line">Pa_new_Ea = <span class="number">2</span> ** (a - steps) * Pa</span><br><span class="line">Qa_new_Ea = <span class="number">2</span> ** (a - steps) * Qa</span><br><span class="line">Ka_Ea = ta * Pa_new_Ea + sa * Qa_new_Ea</span><br><span class="line">phi2 = Ea.isogeny(kernel=Ka_Ea, algorithm=<span class="string">"factored"</span>, model=<span class="string">"montgomery"</span>)</span><br><span class="line">E_middle_2 = phi2.codomain()</span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> E_middle_1.j_invariant() == E_middle_2.j_invariant()</span><br><span class="line"></span><br><span class="line">sigma = E_middle_1.isomorphism_to(E_middle_2)</span><br><span class="line">phi2_hat = phi2.dual()</span><br><span class="line">phi = phi2_hat*sigma*phi1</span><br><span class="line"></span><br><span class="line">phi_Pa_E0 = phi(Pa_E0)</span><br><span class="line">phi_Qa_E0 = phi(Qa_E0)</span><br><span class="line">sa = -phi_Qa_E0.discrete_log(phi_Pa_E0)</span><br><span class="line"><span class="keyword">if</span> sa < <span class="number">0</span>:</span><br><span class="line"> sa += <span class="number">2</span>**a</span><br><span class="line"></span><br><span class="line">Ea_solved = E0.isogeny(kernel=Pa_E0+sa*Qa_E0, algorithm=<span class="string">'factored'</span>,model=<span class="string">'montgomery'</span>).codomain()</span><br><span class="line"><span class="keyword">assert</span> Ea_solved == Ea</span><br><span class="line"></span><br><span class="line">Eab = Eb.isogeny(kernel=phib_Pa + sa*phib_Qa, algorithm=<span class="string">'factored'</span>,model=<span class="string">'montgomery'</span>).codomain()</span><br><span class="line">jab = Eab.j_invariant()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'jab = <span class="subst">{jab}</span>'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">## decryption</span></span><br><span class="line">h = bytes_to_long(hashlib.sha256(<span class="built_in">str</span>(jab).encode()).digest())</span><br><span class="line">flag = long_to_bytes(h ^ enc)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'flag = <span class="subst">{flag}</span>'</span>)</span><br></pre></td></tr></table></figure><h2 id="Unintended-Solution"><a href="#Unintended-Solution" class="headerlink" title="Unintended Solution"></a>Unintended Solution</h2><p>Actually, there are some alternative ways to find a collision. </p><p>In [5] there’s an attack leverages modular polynomial, and it compute the j-invariant only when computing 2-isogeny, instead of computing coefficient of the codomain. That’s really cool! </p><p>Another way is to get order-two points with sagemath’s <code>division_points</code> when going one step in DFS. (I thank hash_hash for telling me that) It seems that <code>division_points</code> make use of division polynomial to get these order-two points with low cost. Usually, when the degree of isogeny $l$ is a larger prime, we need to sample a random point $R$ and compute $(p+1)/l * R$. This is one of the main reasons why isogeny is slow! Another way is to push some points through the isogeny, but I think this is complicated in the scenario of MITM attack, perhaps not doable.</p><p>Here’s a MITM snippet using <code>division_points</code> and DFS from hash_hash.<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># <span class="doctag">NOTE:</span> from Hash Team hash_hash</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> *</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">dp</span>(<span class="params">way, E</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(way) > deepth:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> ker = E(<span class="number">0</span>).division_points(<span class="number">2</span>)[<span class="number">1</span>:]</span><br><span class="line"> j_next = [E.isogeny_codomain(k).j_invariant() <span class="keyword">for</span> k <span class="keyword">in</span> ker]</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> j_next:</span><br><span class="line"> <span class="keyword">if</span> j <span class="keyword">not</span> <span class="keyword">in</span> forward.keys():</span><br><span class="line"> forward[j] = way+[j]</span><br><span class="line"> dp(way+[j], EllipticCurve(j=Fp2(j)))</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">dp_find</span>(<span class="params">way, E</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(way) > deepth:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> ker = E(<span class="number">0</span>).division_points(<span class="number">2</span>)[<span class="number">1</span>:]</span><br><span class="line"> j_next = [E.isogeny_codomain(k).j_invariant() <span class="keyword">for</span> k <span class="keyword">in</span> ker]</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> j_next:</span><br><span class="line"> <span class="keyword">if</span> j <span class="keyword">in</span> forward.keys():</span><br><span class="line"> col = forward[j]+way[::-<span class="number">1</span>]</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"FIND!"</span>, <span class="built_in">len</span>(col))</span><br><span class="line"> <span class="keyword">elif</span> j <span class="keyword">not</span> <span class="keyword">in</span> back.keys():</span><br><span class="line"> back[j] = way+[j]</span><br><span class="line"> dp_find(way+[j], EllipticCurve(j=Fp2(j)))</span><br><span class="line"></span><br><span class="line">a = <span class="number">38</span></span><br><span class="line">b = <span class="number">25</span></span><br><span class="line">p = <span class="number">2</span>**a * <span class="number">3</span>**b - <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">assert</span> is_prime(p)</span><br><span class="line">Fp = GF(p)</span><br><span class="line"></span><br><span class="line">Fpx = PolynomialRing(Fp, <span class="string">"x"</span>)</span><br><span class="line">x = Fpx.gen()</span><br><span class="line">Fp2 = Fp.extension(x**<span class="number">2</span> + <span class="number">1</span>, <span class="string">"ii"</span>)</span><br><span class="line">ii = Fp2.gen()</span><br><span class="line"></span><br><span class="line">A0 = Fp2(<span class="number">6</span>)</span><br><span class="line">E0 = EllipticCurve(Fp2, [<span class="number">0</span>, A0, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">A1 = Fp2(<span class="number">11731710804095179287932</span>*ii+<span class="number">170364860453198752624563</span>)</span><br><span class="line">A2 = Fp2(<span class="number">191884939246592021710422</span>*ii+<span class="number">96782382528277357218650</span>)</span><br><span class="line"></span><br><span class="line">Ea = EllipticCurve(Fp2, [<span class="number">0</span>, A1, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">Eb = EllipticCurve(Fp2, [<span class="number">0</span>, A2, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">E_now = EllipticCurve(j=Fp2(<span class="number">0</span>))</span><br><span class="line">E_start = E0</span><br><span class="line">E_end = Ea</span><br><span class="line"></span><br><span class="line">forward = {}</span><br><span class="line">back = {}</span><br><span class="line">deepth = <span class="number">19</span></span><br><span class="line"></span><br><span class="line">forward[E_start.j_invariant()] = [E_start.j_invariant()]</span><br><span class="line">back[E_end.j_invariant()] = E_end.j_invariant()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"dp start"</span>)</span><br><span class="line">dp([E_start.j_invariant()], E_start)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"Search"</span>)</span><br><span class="line">dp_find([E_end.j_invariant()], E_end)</span><br></pre></td></tr></table></figure></p><p>By the way, a similar challenge had already appeared in the race SEETF 2023. Only after the race did I recognize that… See maple’s writeup for IsogenyMaze [6].</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ol><li><a href="https://eprint.iacr.org/2017/212">Montgomery curves and their arithmetic: The case of large characteristic fields</a></li><li><a href="https://sike.org/files/SIDH-spec.pdf">(SIKE’s spec) Supersingular Isogeny Key Encapsulation</a></li><li><a href="https://eprint.iacr.org/2019/298">Improved Classical Cryptanalysis of SIKE in Practice</a></li><li><a href="https://eprint.iacr.org/2016/413">Efficient algorithms for supersingular isogeny Diffie-Hellman</a></li><li><a href="https://learningtosqi.github.io/">Learning to SQI</a> - Meet in the Middle Isogenies</li><li><a href="https://blog.maple3142.net/2023/06/12/seetf-2023-writeups/#isogeny-maze">https://blog.maple3142.net/2023/06/12/seetf-2023-writeups/#isogeny-maze</a></li></ol><p>And you don’t want to miss this interesting song! <a href="https://krijn-math.github.io/">Kani came in like a wrecking ball</a></p>]]></content>
<summary type="html"><p>Here’s the official writeup for S0DH, including the challenge and solutions (intended and unintended).<br></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="CTF" scheme="https://su1yu4n.github.io/tags/CTF/"/>
<category term="isogeny" scheme="https://su1yu4n.github.io/tags/isogeny/"/>
<category term="SIDH" scheme="https://su1yu4n.github.io/tags/SIDH/"/>
<category term="MITM" scheme="https://su1yu4n.github.io/tags/MITM/"/>
</entry>
<entry>
<title>LadderLeak论文分享</title>
<link href="https://su1yu4n.github.io/2023/11/03/LadderLeak%E8%AE%BA%E6%96%87%E5%88%86%E4%BA%AB/"/>
<id>https://su1yu4n.github.io/2023/11/03/LadderLeak%E8%AE%BA%E6%96%87%E5%88%86%E4%BA%AB/</id>
<published>2023-11-03T03:42:03.000Z</published>
<updated>2024-11-23T07:41:59.925Z</updated>
<content type="html"><![CDATA[<p>去年讲了论文:<a href="https://eprint.iacr.org/2020/615">LadderLeak: Breaking ECDSA With Less Than One Bit Of Nonce Leakage</a>,<strong>现在公开幻灯片,请点击阅读更多获取</strong>。</p><span id="more"></span><p><a href="LadderLeak_slide.pdf">LadderLeak幻灯片.pdf</a></p>]]></content>
<summary type="html"><p>去年讲了论文:<a href="https://eprint.iacr.org/2020/615">LadderLeak: Breaking ECDSA With Less Than One Bit Of Nonce Leakage</a>,<strong>现在公开幻灯片,请点击阅读更多获取</strong>。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="密码分析" scheme="https://su1yu4n.github.io/tags/%E5%AF%86%E7%A0%81%E5%88%86%E6%9E%90/"/>
<category term="侧信道攻击" scheme="https://su1yu4n.github.io/tags/%E4%BE%A7%E4%BF%A1%E9%81%93%E6%94%BB%E5%87%BB/"/>
</entry>
<entry>
<title>复变函数笔记</title>
<link href="https://su1yu4n.github.io/2023/09/05/%E5%A4%8D%E5%8F%98%E5%87%BD%E6%95%B0%E7%AC%94%E8%AE%B0/"/>
<id>https://su1yu4n.github.io/2023/09/05/%E5%A4%8D%E5%8F%98%E5%87%BD%E6%95%B0%E7%AC%94%E8%AE%B0/</id>
<published>2023-09-05T13:38:40.000Z</published>
<updated>2024-11-23T07:39:12.058Z</updated>
<content type="html"><![CDATA[<p>(9.21更新, 不过当时部署之后没更新显示…)</p><p>学习了史济怀的《复变函数》第2~4章。第五章没细看,因为个人需求是会洛朗展开和留数定理去计算就行,而这两个东西早就知道了,因此就看了Borcherds的课,跟着用草稿纸去算一算特定的积分。</p><p>笔记有很多习题空着了,部分内容也跳过了。不过确实是写了自己思考的一些东西… 也许有一天再用复分析的时候干脆讲一讲,再完善一下这些笔记。还有二次剩余分布问题也可以讲一讲。</p><span id="more"></span><p><em>感觉数位板还是适合手头有纸质的初步笔记,然后边讲边写。直接对着电脑看效果差一点。</em></p><p><a href="史济怀《复变函数》第二章笔记.pdf">史济怀《复变函数》第二章笔记</a></p><p><a href="史济怀《复变函数》第三章笔记.pdf">史济怀《复变函数》第三章笔记</a></p><p><a href="史济怀《复变函数》第四章笔记.pdf">史济怀《复变函数》第四章笔记</a></p><h2 id="其他参考资料"><a href="#其他参考资料" class="headerlink" title="其他参考资料"></a>其他参考资料</h2><ol><li><a href="https://www.bilibili.com/video/BV15F41137Nn">Richard E. Borcherds的复分析课程</a></li><li>Complex Analysis by Alhfors </li><li>龚昇 - 《简明复分析》</li><li>之前学习点集拓扑和初步代数拓扑的笔记</li><li><a href="https://github.com/BhorisDhanjal/MathsRevisionCheatSheets">Complex Analysis Cheat Sheet by BhorisDhanjal (github)</a></li></ol>]]></content>
<summary type="html"><p>(9.21更新, 不过当时部署之后没更新显示…)</p>
<p>学习了史济怀的《复变函数》第2~4章。第五章没细看,因为个人需求是会洛朗展开和留数定理去计算就行,而这两个东西早就知道了,因此就看了Borcherds的课,跟着用草稿纸去算一算特定的积分。</p>
<p>笔记有很多习题空着了,部分内容也跳过了。不过确实是写了自己思考的一些东西… 也许有一天再用复分析的时候干脆讲一讲,再完善一下这些笔记。还有二次剩余分布问题也可以讲一讲。</p></summary>
<category term="Math" scheme="https://su1yu4n.github.io/categories/Math/"/>
<category term="复分析" scheme="https://su1yu4n.github.io/tags/%E5%A4%8D%E5%88%86%E6%9E%90/"/>
<category term="学习笔记" scheme="https://su1yu4n.github.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>知识分享会:密码学中的椭圆曲线</title>
<link href="https://su1yu4n.github.io/2023/04/17/%E5%AF%86%E7%A0%81%E5%AD%A6%E4%B8%AD%E7%9A%84%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E7%9F%A5%E8%AF%86/"/>
<id>https://su1yu4n.github.io/2023/04/17/%E5%AF%86%E7%A0%81%E5%AD%A6%E4%B8%AD%E7%9A%84%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E7%9F%A5%E8%AF%86/</id>
<published>2023-04-17T04:18:02.000Z</published>
<updated>2024-11-23T07:39:12.058Z</updated>
<content type="html"><![CDATA[<p><strong>(2023.4) 计划增加一些新内容(但可能没时间了…)</strong></p><p>椭圆曲线密码学实际上涉及到不少高深的数学知识。2022年10月在Nepnep战队做了一次线上分享,听众还有其他对密码学感兴趣的朋友以及geek学院的朋友等。<strong>主要内容是代数学基础回顾、射影几何基础以及GTM 106前三章的部分内容</strong>。</p><span id="more"></span><h2 id="勘误和补充"><a href="#勘误和补充" class="headerlink" title="勘误和补充"></a>勘误和补充</h2><h3 id="勘误"><a href="#勘误" class="headerlink" title="勘误"></a>勘误</h3><p>观看视频时请打开弹幕,其中提示了一些错误</p><h3 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h3><ol><li><p><strong><script type="math/tex">E/K</script>和$E(K)$的定义,以及两者之间的区别</strong>:</p><ul><li><script type="math/tex">E/K</script>:一种简写,表明$E$是定义在域$K$上的椭圆曲线,即曲线方程的系数属于$K$. 注意曲线 $E$ 的点为 $\mathbb{P}^2=\mathbb{P}^2(\overline{K})$中所有满足方程的点,因此其坐标分量不必属于$K$</li><li><script type="math/tex">E(K)</script>:椭圆曲线$E$的所有$K-$有理点,即坐标分量均属于$K$的那些点,是一个群。</li></ul><p>自然地,$E=E(\overline{K})$.</p></li><li><p>注意扭点群的定义、Weil对的反对称性等</p></li></ol><h2 id="主要内容"><a href="#主要内容" class="headerlink" title="主要内容"></a>主要内容</h2><h3 id="2022-10-分享"><a href="#2022-10-分享" class="headerlink" title="2022.10 分享"></a>2022.10 分享</h3><ol><li>群环域回顾和一点概形的精神</li><li>射影空间基础</li><li>椭圆曲线的方程、椭圆曲线点群公式、代数曲线上的有理函数域、曲线间的态射、二次孪生曲线(quadratic twist)、阶数、映射度、分歧指数、非零有理函数零极点的重数之和相等。</li><li>除子、主除子、黎曼罗赫定理及其推论、Picard群(特别是Jacobian)、椭圆曲线点群与它的Jacobian同构、双线性对及其应用</li></ol><h3 id="待补充(同源密码用)"><a href="#待补充(同源密码用)" class="headerlink" title="待补充(同源密码用)"></a>待补充(同源密码用)</h3><ol><li>椭圆曲线的黎曼面视角与代数曲线视角</li><li>同源基本概念:同源的定义、映射度、扭点与核、映射度与核的关系</li><li>Velu公式及其优化,以及其他的计算同源的算法</li><li>对偶同源(黎曼面视角和除子视角)</li><li>同构及其概念问题(所在的域,映射度)</li><li>Weil猜想和Sato-Tate定理</li><li>子群与同源的对应</li><li>超奇异椭圆曲线:几种等价定义、自同态环的结构</li><li>同源图,特别是超奇异椭圆曲线同源图,以及Richelot同源和超特殊主极化阿贝尔面同源图(isogeny graph of superspecial principally polarized abelian surfaces over $\overline{\mathbb{F}_p}$)等等</li><li><strong>“Kani wreck SIKE” (i.e. Kani’s “reducibility criterion” and Castryck-Decru attack and maybe more)</strong></li><li>除子的推前拉回、函数的推前拉回、主除子度数为0的一个代数证明</li><li>除子定义的Weil对、函数定义的Weil对、Tate对、Ate对等等及相关的计算算法</li><li>除子的几何对应——线丛</li><li><del>线性系统(linear system)、充沛除子(ample divisor)、充沛线丛(very ample line bundle)</del></li><li>曲线的点数</li></ol><p><strong>上述条目的2/3可以在黎曼面相关的书籍中学到(书籍见后)</strong></p><h2 id="视频、手写稿"><a href="#视频、手写稿" class="headerlink" title="视频、手写稿"></a>视频、手写稿</h2><p>B站视频合集:<a href="https://www.bilibili.com/video/BV15V4y1V71d">https://www.bilibili.com/video/BV15V4y1V71d</a></p><p>2022年10月分享手写稿:<a href="https://pan.baidu.com/s/1b_Whla_qhKVqu2KyLz6tCQ?pwd=hxd7">https://pan.baidu.com/s/1b_Whla_qhKVqu2KyLz6tCQ?pwd=hxd7</a></p><h2 id="后续推荐资料"><a href="#后续推荐资料" class="headerlink" title="后续推荐资料"></a>后续推荐资料</h2><h3 id="适用于密码学的"><a href="#适用于密码学的" class="headerlink" title="适用于密码学的"></a>适用于密码学的</h3><ol><li><p><a href="https://crypto.stanford.edu/pbc/notes/elliptic/">Elliptic Curves Notes</a></p><p>可以看下Weil对和Tate对是怎么用除子定义的。</p></li><li><p><a href="https://link.springer.com/article/10.1007/s00145-004-0315-8">Paper from JoC 2004: The Weil Pairing, and Its Efficient Calculation</a></p><p>JoC,密码界最强顶刊,其含金量甚至大于顶会。干脆来看这篇学Weil对</p></li><li><p>Elliptic Curves Number Theory and Cryptography</p><p>前言中说明了适用于密码学的学习章节,不过isogeny那章也可以看一看,是椭圆曲线同源密码的那个同源。</p></li><li><p><a href="http://www.jcr.cacrnet.org.cn/CN/10.13868/j.cnki.jcr.000512">基于椭圆曲线中配对的密码学研究综述(综述论文)</a></p></li><li><p><a href="http://safecurves.cr.yp.to/index.html">安全的椭圆曲线</a></p><p>安全性问题比如Ladder, Twist,MOV攻击,FR约化攻击… Weil Descent Attack就很难了,我到现在都感觉自己还差不少才能看懂。GTM106也只讲到2-descent。Milne的Elliptic Curves讲义可能有Weil restriction。</p></li><li><p>椭圆与超椭圆曲线公钥密码的理论和实现</p><p>难得的一本中文书,各种高级的攻击在里面都有写…</p></li><li><p>双线性对的应用,如:双线性对的三方一轮密钥协商,各种IBE、ABE方案… 双线性对曾经是密码学中最强大的数学工具,用它可以实现一些功能非常强大的、让人意想不到的密码学功能。</p></li><li><p><a href="https://arxiv.org/pdf/1711.04062.pdf">Mathematics of Isogeny Based Cryptography</a></p><p>关注同源,谢谢!</p></li></ol><h3 id="适用于数学的"><a href="#适用于数学的" class="headerlink" title="适用于数学的"></a>适用于数学的</h3><ol><li><p>Fulton的代数曲线</p><p>入门古典代数几何用,<a href="https://ziyuzhang.github.io/ma40188/Lecture_Notes_Long.pdf">有配套讲义</a>。</p></li><li><p>Elliptic Curves Number Theory and Cryptography</p><p>比GTM106简单些。</p></li><li><p>GTM 106 The Arithmetic of Elliptic Curves</p><p>后半要会一些代数数论才能看,有<a href="https://www.bilibili.com/video/BV1gN411o7un">网上课程</a></p></li><li><p>Algebraic Curves and Riemann Surfaces by Rick Miranda</p><p><strong>如果想绕过代数几何直观地搞懂视频中的一些结论,应该看这个紧黎曼面的内容</strong>。<em>非常友好的书,稍微学一些点集拓扑、基本群、微分流形,再看一个基础的单变量复变函数课就可以读的很顺畅。</em>Geek学院的<a href="https://www.bilibili.com/video/BV1FY4y1k7xJ">Ultra做过一次紧黎曼面的沙龙</a>,<strong>推荐看视频配着书,把握住重点。</strong></p></li><li><p>椭圆与超椭圆曲线公钥密码的理论和实现</p><p>感受一下椭圆曲线密码学攻击中的各种数学吧,你能看到De Rham上同调,同调群,Brauer群、Weil restriction等等…</p><p><em>不过有些地方作者似乎试图写得初等一点可能乍一看看不出来,例如Smart Attack实际上用到GTM 106第五章的一些知识(这还被写在了“一些初等的攻击”那一章…)。</em></p></li></ol><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li>GTM 106 - The Arithmetic of Elliptic Curves by Joseph H. Silverman</li><li>Algebraic Curves and Riemann Surfaces by Rick Miranda</li><li>Geek学院紧黎曼面沙龙(配套Miranda):<a href="https://www.bilibili.com/video/BV1FY4y1k7x">https://www.bilibili.com/video/BV1FY4y1k7x</a></li><li>一个 GTM 106 的课程:<a href="https://www.bilibili.com/video/BV1gN411o7un">https://www.bilibili.com/video/BV1gN411o7un</a></li><li>李卫平的代数几何短课:<a href="https://www.bilibili.com/video/BV1BD4y1o74e">https://www.bilibili.com/video/BV1BD4y1o74e</a></li><li>⑨代数:概形的灵感:<a href="https://www.bilibili.com/video/BV1Qx411i7b2">https://www.bilibili.com/video/BV1Qx411i7b2</a></li><li>刘思齐的《几何与对称》课程:<a href="https://www.bilibili.com/video/BV1AU4y1A7u9">https://www.bilibili.com/video/BV1AU4y1A7u9</a></li></ol><h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2><p>感谢<a href="https://ziyangzhu.github.io/home/">@朱子阳</a>的热心解惑。</p><p>另外这次分享中有几次挂黑板,也有很多很多没讲到位的地方。感谢各位听众的理解与支持!</p>]]></content>
<summary type="html"><p><strong>(2023.4) 计划增加一些新内容(但可能没时间了…)</strong></p>
<p>椭圆曲线密码学实际上涉及到不少高深的数学知识。2022年10月在Nepnep战队做了一次线上分享,听众还有其他对密码学感兴趣的朋友以及geek学院的朋友等。<strong>主要内容是代数学基础回顾、射影几何基础以及GTM 106前三章的部分内容</strong>。</p></summary>
<category term="Math" scheme="https://su1yu4n.github.io/categories/Math/"/>
<category term="Elliptic Curves" scheme="https://su1yu4n.github.io/tags/Elliptic-Curves/"/>
</entry>
<entry>
<title>NepCTF2022 - COA_RSA解读</title>
<link href="https://su1yu4n.github.io/2023/02/23/COA_RSA%E9%A2%98%E7%9B%AE%E7%BB%86%E8%8A%82%E5%8F%8A%E5%8F%8D%E6%80%9D/"/>
<id>https://su1yu4n.github.io/2023/02/23/COA_RSA%E9%A2%98%E7%9B%AE%E7%BB%86%E8%8A%82%E5%8F%8A%E5%8F%8D%E6%80%9D/</id>
<published>2023-02-23T08:23:03.000Z</published>
<updated>2024-11-23T07:40:12.689Z</updated>
<content type="html"><![CDATA[<p>之前给NepCTF 2022出了几道密码题,其中就包括这道… 官方题解WP在<a href="https://www.wolai.com/nepnep/q8dyRhz2ufGtqWTqnyeUwv">这里</a>。当时是想出一道反论文题,不过赛后发现做出来的选手中很多还是看论文做的。<strong>题目对应的论文本身写得很差,不推荐阅读。</strong></p><p>后来跟shallow师傅讨论了一下,又看了下<strong>当时的WP发现有很多细节没说,并且有点小问题。因此现在补充一下。</strong></p><span id="more"></span><h2 id="本题涉及内容"><a href="#本题涉及内容" class="headerlink" title="本题涉及内容"></a>本题涉及内容</h2><p>Carmichael定理, $\mathbb{Z}_{N}^{\ast}$ 的阶, Minkowski定理, Gauss reduction算法</p><h2 id="模N乘法群中元素的阶(一个Carmichael定理的推导)"><a href="#模N乘法群中元素的阶(一个Carmichael定理的推导)" class="headerlink" title="模N乘法群中元素的阶(一个Carmichael定理的推导)"></a>模N乘法群中元素的阶(一个Carmichael定理的推导)</h2><p><strong>(2023.8 补充):</strong> 不知道为什么之前自己写得那么复杂,<strong>实际上在群同构$\mathbb{Z}_{N}^{\ast} \cong \mathbb{Z}_{p}^{\ast} \times \mathbb{Z}_{q}^{\ast}$ 的视角下Carmichael定理是很容易看出来的。</strong>取模$p$原根$g_1$,模$q$原根$g_2$,$\mathbb{Z}_{N}^{\ast}$ 的元素在同构下对应某一个$(g_{1}^{x}, g_{2}^{y})$,于是他们的阶显然整除$\lambda(N)$。</p><p><strong>以下思路过于繁琐,不过这里仍然保留一下。</strong></p><p>WP中已经说明本题 $m^{1-e} \pmod n$ 比较小,这意味着$1-e$以极大的概率接近 $\text{ord}(m)$的倍数 ,据此我们可以推断出$1-e$的形式。现在关键问题是 $\text{ord}(m)$ 应该是什么样的形式?当时在这个问题上,很多师傅都翻车了。当时一位师傅做这个题的时候把 $\text{ord}(m)$ 想成了$\phi(N)$。那么 $\text{ord}(m)$ 实际上应该是什么样的形式呢?</p><p>先说结论:$\text{ord}(m)$ 整除 $\lambda := \lambda(N)=\text{lcm}(p-1, q-1)$</p><p><strong>定理:</strong>设 $G$ 是有限Abel群,记 $ o = \max_{a \in G}{\text{ord}(a)} $ ( $o$ 为 $G$ 中阶最大的元素的阶 ),那么 $$ \forall a \in G, \ \text{ord}(a) \,| \,o $$</p><p>为了说明 $ m^{\lambda} \equiv 1 \pmod{N} $,考虑群 $G = \mathbb{Z}_{N}^{<em>}$. 这是一个有限交换的乘法群。假设$\mathbb{Z}_{N}^{</em>}$中阶最大的元素是 $g$ ,考虑中国剩余定理。那么想让 $\text {ord}(g) = o$ 尽量最大的话,最好的可能就是 $g$ 同时是模 $ p $ 和 模 $ q $ 的原根。这时 $o = \text{lcm}(p-1, q-1) = \lambda$.</p><p>如果不存在一个元素同时是模 $ p $ 和 模 $ q $ 的原根,那么 $o$ 也一定整除 $\text{lcm}(p-1, q-1)$. </p><p>_不过根据原根的数量这种情况的概率应该很低?也可能根本不存在这种情况?我不清楚。好像有限Abel群结构定理能说明存在性,懒得想了。_</p><p>总之, <strong><script type="math/tex">o</script> 一定整除 $\lambda = \text{lcm}(p-1, q-1)$.</strong></p><p>结合上个定理,可以推出以下定理。</p><p><strong>Carmichael定理:</strong> 设 $N = p \cdot q$,其中 $p, q$ 皆为素数。设 $\lambda = \text{lcm}(p-1, q-1) $,则</p><script type="math/tex; mode=display">\forall a \in \mathbb{Z}_{N} ^{\ast}, \ a^{\lambda} \equiv 1 \pmod{N}</script><p><strong>因此 $\text{ord}(m)$ 整除 $\lambda$ ,因此 $\text{ord}(m)$ 也必然整除 $\phi(N)$</strong></p><h2 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h2><h3 id="总体概括"><a href="#总体概括" class="headerlink" title="总体概括"></a>总体概括</h3><ol><li><p>在<code>challenge.sage</code>中结合Description.md的提示发现 <code>get_e()</code>是从secret中import的没有给出,但是 $e$ 的值是给出的,猜测这个 $e$ 可能有特殊形式所以不能给出。</p><p>分析出<code>attack_experiment.sage</code> 攻击原理,写出使用的格。</p></li><li><p>再根据参数满足理论上的攻击条件使用Minkowski定理(上界),分析出 $e$ 约等于 $\text{ord}(m)$ 的倍数,然后开始找 $e$ 和 $\phi(N)$ 的关系。</p></li><li><p>计算 $N/e$ 发现非常接近7,因此 $\phi(N)/e$ 也非常接近7。</p></li><li><p>据此对$\phi(N)$进行爆破,然后用 $\phi(N)$ 分解 $N$ 。</p></li></ol><h3 id="具体细节"><a href="#具体细节" class="headerlink" title="具体细节"></a>具体细节</h3><ol><li>阅读<code>attack_experiment.sage</code>代码,推出其攻击原理如下:</li></ol><script type="math/tex; mode=display">c \equiv m^{e} \pmod{n} \Rightarrow \ c \equiv m^{x} \cdot m^{e-x} \pmod{n} \\ \Rightarrow m^{x-e} \cdot c \equiv m^{x} \pmod{n} \\ \text{令} \ x = 1, \text{则有} \ \ m^{1-e} \cdot c \equiv m \pmod{n} \ \text{。记}\ A = m^{1-e} \! \mod{n},可得 \\ A\cdot c = m + B\cdot n \ \Rightarrow \ m = A \cdot c - B\cdot n \\ \Rightarrow \begin{bmatrix} A\\m \end{bmatrix} = A \begin{bmatrix} 1\\c \end{bmatrix} - B \begin{bmatrix} 0\\n \end{bmatrix} \ \ \text{,其中} \ A,B \in \mathbb{Z} \text{。} \\ 因此 \begin{bmatrix} A\\m \end{bmatrix} 为格中非零最短向量时可用格基规约算法恢复明文 m。</script><ol><li>根据分析,$\begin{bmatrix} A\\m \end{bmatrix}$ 满足Minkowski界. 于是有</li></ol><script type="math/tex; mode=display">A^{2} + m^2 = ( m^{1-e} \ \text{mod}\ n )^2 + m^2 \leq 2n</script><p>可见 $m^{1−e} \mod n$ 的量级最大为 $\sqrt{n}$ ,然而很难找到一般的 $e$ 来满足这一点.</p><ol><li><p>可以猜测出 $1−e$ 约等于 $\text{ord}(m)$ 的倍数。考虑找 $e$ 和 $\phi(N)$ 的关系。计算$N/e$发现很接近7,于是 $\phi(N)/e$很接近7。因此 $e= \phi(N)/7 - b$, 并且 $b$ 很小。</p></li><li><p>对 $b$ 进行穷举。已知 $ \phi(N) = (p-1)(q-1) $ 分解 $N=pq$ 是容易的(中学数学),用 $n \mod p = 0$ 来判断当前分解是否正确即可。之后再做常规RSA解密就好了。</p></li></ol><h3 id="出题反思"><a href="#出题反思" class="headerlink" title="出题反思"></a>出题反思</h3><ol><li><p><code>get_e()</code>没给出,可能有一点脑洞。应该写得再明白一些,e是为了试图满足原攻击条件的特殊的e。</p></li><li><p>应该直接告诉大家,x在这里等于1。<em>当时是想让大家不看论文并根据<code>attack_experiment.sage</code>的代码逻辑,自己推出论文中那个攻击的原理。但是CTF中大家无疑都是会去看论文的…</em></p></li><li><p>附件中<code>Description.md</code>中的提示还是有点少,应该写明白预期解不是基于格的攻击。</p></li><li><p>WP的一个小问题:这道题的 $\phi(n)/7$ 是 $\text{ord}(m)$ 吗?<em>不可能,注意到 $\lambda$ 是偶数,实际上两者是倍数关系。但是当时太懒就少打了几个字。</em></p></li><li><p>正解的思路太复杂,招新赛出这个有点难了。</p></li></ol>]]></content>
<summary type="html"><p>之前给NepCTF 2022出了几道密码题,其中就包括这道… 官方题解WP在<a href="https://www.wolai.com/nepnep/q8dyRhz2ufGtqWTqnyeUwv">这里</a>。当时是想出一道反论文题,不过赛后发现做出来的选手中很多还是看论文做的。<strong>题目对应的论文本身写得很差,不推荐阅读。</strong></p>
<p>后来跟shallow师傅讨论了一下,又看了下<strong>当时的WP发现有很多细节没说,并且有点小问题。因此现在补充一下。</strong></p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="CTF" scheme="https://su1yu4n.github.io/tags/CTF/"/>
<category term="出题记录" scheme="https://su1yu4n.github.io/tags/%E5%87%BA%E9%A2%98%E8%AE%B0%E5%BD%95/"/>
</entry>
<entry>
<title>同态加密:Paillier方案学习</title>
<link href="https://su1yu4n.github.io/2023/02/23/%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86%EF%BC%9APaillier%E6%96%B9%E6%A1%88%E5%AD%A6%E4%B9%A0/"/>
<id>https://su1yu4n.github.io/2023/02/23/%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86%EF%BC%9APaillier%E6%96%B9%E6%A1%88%E5%AD%A6%E4%B9%A0/</id>
<published>2023-02-23T08:23:03.000Z</published>
<updated>2024-11-23T07:40:12.684Z</updated>
<content type="html"><![CDATA[<p>本文总结Paillier及其变种Paillier-DJN方案。</p><span id="more"></span><h2 id="Paillier-original"><a href="#Paillier-original" class="headerlink" title="Paillier(original)"></a>Paillier(original)</h2><h3 id="方案细节"><a href="#方案细节" class="headerlink" title="方案细节"></a>方案细节</h3><p>懒得写方案,因为到处都能找到。直接看<a href="https://zhuanlan.zhihu.com/p/420417626">(知乎)Paillier半同态加密:原理、高效实现方法和应用</a>。</p><h3 id="Carmichael定理背后的数学原理"><a href="#Carmichael定理背后的数学原理" class="headerlink" title="Carmichael定理背后的数学原理"></a>Carmichael定理背后的数学原理</h3><p><em>(2023.8) 之前写了一大段,不过因为跟COA_RSA那篇的内容重复,所以现在删掉了</em></p><p>见本博客的另一篇文章:NepCTF2022 - COA_RSA解读</p><h3 id="方案的设计思路"><a href="#方案的设计思路" class="headerlink" title="方案的设计思路"></a>方案的设计思路</h3><p>待补充…</p><h2 id="Paillier-DJN"><a href="#Paillier-DJN" class="headerlink" title="Paillier-DJN"></a>Paillier-DJN</h2><p>以下方案与<a href="https://link.springer.com/article/10.1007/s10207-010-0119-9">原论文</a>有出入。我这里写的是 section 4.1中,$s=1$时的情况。</p><h3 id="KeyGen"><a href="#KeyGen" class="headerlink" title="KeyGen"></a>KeyGen</h3><ol><li>Choose two random safe primes $p$, $q$ such that $p,q\equiv 3 \pmod 4$ and $\text{gcd}(p-1, q-1) = 2$</li><li><p>Compute $n = pq \ , \ \lambda = \text{lcm}(p-1, q-1) = (p-1) (q-1) / 2$</p></li><li><p>Choose $g = n+1$ </p></li><li>Choose random $x\leftarrow \mathbb{Z}_n^{*}$ , then compute $h = -x^{2}\ , \ h_s = h^{n} \mod {n^2}$ </li><li><script type="math/tex">pk = (n, h_s)\ , \ sk = \lambda</script></li></ol><h3 id="Enc"><a href="#Enc" class="headerlink" title="Enc"></a>Enc</h3><p> Let $|n|$ denote the bit length of n. </p><ol><li>Choose random $a\leftarrow \mathbb{Z}_{ 2^ \left \lceil |n|/2 \right \rceil }$.</li><li>Compute ciphertext $c = (1+mn)\cdot h_s^{a} \mod n^{2}$ //We can use CRT to calc $h_s^a \mod n^2$</li></ol><h3 id="Dec1"><a href="#Dec1" class="headerlink" title="Dec1"></a>Dec1</h3><p><strong>Note that here we assume $m \in \mathbb{Z}_{n}^{*}$ ( i.e. $m < n$)</strong> </p><ol><li>Compute $m\lambda = L( c^{\lambda} \!\mod n^{2})$, where $L(x) = \frac{x-1}{n}$</li><li>Recover $m$ by compute $m = m\lambda \cdot \lambda^{-1} \mod n^{2}$</li></ol><h3 id="Dec2"><a href="#Dec2" class="headerlink" title="Dec2"></a>Dec2</h3><p>Note that here we assume $m \in \mathbb{Z}_{n^2}^{<em>}$ . <em>*This is the case in the original paper, but it’s far more complicated then Dec1…</em></em></p><p>这种解密方案似乎没有在实际中应用,并且细节比较繁琐,这里就不写了。</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ol><li><p><a href="https://zhuanlan.zhihu.com/p/420417626">(知乎)Paillier半同态加密:原理、高效实现方法和应用</a></p></li><li><p><a href="https://link.springer.com/article/10.1007/s10207-010-0119-9">A generalization of Paillier’s public-key system with applications to electronic voting</a></p></li></ol>]]></content>
<summary type="html"><p>本文总结Paillier及其变种Paillier-DJN方案。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="同态加密" scheme="https://su1yu4n.github.io/tags/%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86/"/>
<category term="半同态加密(PHE)" scheme="https://su1yu4n.github.io/tags/%E5%8D%8A%E5%90%8C%E6%80%81%E5%8A%A0%E5%AF%86%EF%BC%88PHE%EF%BC%89/"/>
</entry>
<entry>
<title>CatCTF出题小记</title>
<link href="https://su1yu4n.github.io/2023/02/23/CatCTF%E5%87%BA%E9%A2%98%E5%B0%8F%E8%AE%B0/"/>
<id>https://su1yu4n.github.io/2023/02/23/CatCTF%E5%87%BA%E9%A2%98%E5%B0%8F%E8%AE%B0/</id>
<published>2023-02-23T08:22:30.000Z</published>
<updated>2024-11-23T07:40:12.689Z</updated>
<content type="html"><![CDATA[<p>CatCTF的题目总结以及出题的动机、想法。</p><span id="more"></span><h2 id="DDH-Game"><a href="#DDH-Game" class="headerlink" title="DDH_Game"></a>DDH_Game</h2><p>图片来自 <a href="https://toc.cryptobook.us/">A Graduate Course in Applied Cryptography(Version 0.5)</a></p><p><img src="DDH.png" alt="DDH.png"></p><p>这道题就是在让大家求解椭圆曲线上的DDH问题(ECDDHP)。</p><h3 id="解法一"><a href="#解法一" class="headerlink" title="解法一"></a>解法一</h3><p>由于题目中的BLS曲线是配对友好曲线,所以可以计算双线性对。</p><p>双线性对满足 $e(aG, bG) = e(G, abG)$</p><p>这就给了我们一个解DDHP的后门。因此如果随便选一个椭圆曲线点群,ECDDH假设通常是不成立的,并且攻击方法很简单:看等式$e(aG, bG) = e(G, cG)$ 是否成立。个人认为这是一个很优美的做法。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># sagemath 9.5</span></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> long_to_bytes</span><br><span class="line"></span><br><span class="line"><span class="comment"># Before running, modify your filename and add "DDH_instances = " at the beginning of the file.</span></span><br><span class="line">load(<span class="string">'DDH_instances.sage'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># curve</span></span><br><span class="line">p = <span class="number">0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab</span></span><br><span class="line">K = GF(p)</span><br><span class="line">a = K(<span class="number">0x00</span>)</span><br><span class="line">b = K(<span class="number">0x04</span>)</span><br><span class="line">E = EllipticCurve(K, (a, b))</span><br><span class="line"><span class="comment"># G = E(0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB, 0x08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1)</span></span><br><span class="line">E.set_order(<span class="number">0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001</span> * <span class="number">0x396C8C005555E1568C00AAAB0000AAAB</span>)</span><br><span class="line"></span><br><span class="line">G = E(<span class="number">3745324820672390389968901155878445437664963280229755729082200523555105705468830220374025474630687037635107257976475</span>, <span class="number">2578846078515277795052385204310204126349387494123866919108681393764788346607753607675088305233984015170544920715533</span>)</span><br><span class="line">n = G.order()</span><br><span class="line"></span><br><span class="line"><span class="comment"># Embedding degree of the curve</span></span><br><span class="line">k = <span class="number">12</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">solve_ECDDHP</span>(<span class="params">DDH_instances, G, Ep, m, n</span>):</span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Parameters:</span></span><br><span class="line"><span class="string"> DDH_instances - list consists of (aG, bG, cG), where aG, bG, cG are EC_point.xy()</span></span><br><span class="line"><span class="string"> m - embedding degree of <G></span></span><br><span class="line"><span class="string"> n - G's order. </span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> sols = []</span><br><span class="line"> </span><br><span class="line"> Fpm.<x> = GF(p^m)</span><br><span class="line"> Epm = Ep.base_extend(Fpm) </span><br><span class="line"> </span><br><span class="line"> G = Epm(G)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> ins <span class="keyword">in</span> DDH_instances:</span><br><span class="line"> aG, bG, cG = ins</span><br><span class="line"> aG = Epm(aG); bG = Epm(bG); cG = Epm(cG)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># e_aG_bG = aG.weil_pairing(bG, n)</span></span><br><span class="line"> e_aG_bG = aG.tate_pairing(bG, n, m)</span><br><span class="line"> </span><br><span class="line"> e_G_cG = G.tate_pairing(cG, n, m)</span><br><span class="line"> <span class="keyword">if</span> e_aG_bG == e_G_cG:</span><br><span class="line"> sols.append(<span class="literal">True</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> sols.append(<span class="literal">False</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> sols</span><br><span class="line"></span><br><span class="line">sols = solve_ECDDHP(DDH_instances, G, E, k, n)</span><br><span class="line"><span class="comment"># print(sols)</span></span><br><span class="line"></span><br><span class="line">pt = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(sols)):</span><br><span class="line"> pt += sols[i] * (<span class="number">2</span>^i)</span><br><span class="line"></span><br><span class="line">flag = long_to_bytes(pt)</span><br><span class="line"><span class="built_in">print</span>(flag)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">b'CatCTF{'</span> + flag + <span class="string">'}'</span>)</span><br></pre></td></tr></table></figure><h3 id="解法二"><a href="#解法二" class="headerlink" title="解法二"></a>解法二</h3><p>其实是非预期解,不过测题的时候队里有其他师傅想到了,这个思路也是直击DDH问题中的’Decisional’ 。</p><p>题目中点G的阶为<img src="点G的阶.png" alt="点G的阶"></p><p>做法类似Pohlig-Hellman算法中使用的原理,不过我们不用算出a, b和c,而是在模3, 模11, 模10177等的意义下计算出a,b和c。再对应考察同余式是否成立: $ab \equiv c \pmod{3}$ $ab \equiv c \pmod{11}, … $ 。如果成立那么大概率有$ab = c$。打印出来看看flag对不对就行了。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># sagemath 9.5</span></span><br><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> long_to_bytes</span><br><span class="line"><span class="comment"># Before running, modify your filename and add "DDH_instances = " at the beginning of the file.</span></span><br><span class="line">load(<span class="string">'DDH_instances.sage'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">p = <span class="number">0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab</span></span><br><span class="line">K = GF(p)</span><br><span class="line">a = K(<span class="number">0x00</span>)</span><br><span class="line">b = K(<span class="number">0x04</span>)</span><br><span class="line">E = EllipticCurve(K, (a, b))</span><br><span class="line">E.set_order(<span class="number">0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001</span> * </span><br><span class="line"><span class="number">0x396C8C005555E1568C00AAAB0000AAAB</span>)</span><br><span class="line">G = E(<span class="number">3745324820672390389968901155878445437664963280229755729082200523555105705468830220374025474630687037635107257976475</span>, </span><br><span class="line"> <span class="number">2578846078515277795052385204310204126349387494123866919108681393764788346607753607675088305233984015170544920715533</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">Pohlig_Hellman</span>(<span class="params">G, Y, ord_G, facts</span>):</span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Using the idea of Pohlig-Hellman.</span></span><br><span class="line"><span class="string"> G: EC group generator G</span></span><br><span class="line"><span class="string"> facts: list, some small factors of the group order</span></span><br><span class="line"><span class="string"> return x: discrete log of Y modulo prod(facts) </span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> new_bases = [(ord_G // facts[i])*G <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(facts))]</span><br><span class="line"> <span class="keyword">assert</span> <span class="built_in">len</span>(new_bases) == <span class="built_in">len</span>(facts)</span><br><span class="line"> xi = [new_bases[i].discrete_log((ord_G // facts[i])*Y, facts[i]) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(facts))]</span><br><span class="line"> <span class="comment"># print(f"xi = {xi}")</span></span><br><span class="line"> </span><br><span class="line"> x = CRT(xi, facts)</span><br><span class="line"> <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line">order = G.order()</span><br><span class="line"><span class="comment"># factors of order, pairwise coprime</span></span><br><span class="line">facts = [<span class="number">3</span>, <span class="number">11</span>, <span class="number">10177</span>]</span><br><span class="line">s = prod(facts)</span><br><span class="line">m = <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> tqdm</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> tqdm.tqdm(<span class="built_in">range</span>(<span class="built_in">len</span>(DDH_instances))):</span><br><span class="line"> aG, bG, cG = DDH_instances[i]</span><br><span class="line"> aG = E(aG); bG = E(bG); cG = E(cG)</span><br><span class="line"> a, b, c = [Pohlig_Hellman(G, E(Pt), order, facts) <span class="keyword">for</span> Pt <span class="keyword">in</span> (aG, bG, cG)]</span><br><span class="line"> <span class="keyword">if</span> (a*b) % s == c:</span><br><span class="line"> m += <span class="string">'1'</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> m += <span class="string">'0'</span></span><br><span class="line"><span class="built_in">print</span>(m)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(<span class="built_in">int</span>(m[::-<span class="number">1</span>], <span class="number">2</span>)))</span><br></pre></td></tr></table></figure><h3 id="动机和细节"><a href="#动机和细节" class="headerlink" title="动机和细节"></a>动机和细节</h3><p>早就想把密码理论与密码攻击相结合出一个题目,之前想到<a href="https://en.wikipedia.org/wiki/Decisional_Diffie%E2%80%93Hellman_assumption#Groups_for_which_DDH_is_assumed_to_hold">DDH</a>,上面写嵌入度较低的椭圆曲线上DDH假设不成立。于是我找了一条BLS曲线来出这道题,题面非常简单就是进行DDH Game。DDH假设是一个很重要的话题,Game则是密码理论中的security game,双线性对也是很重要的密码学工具。不过题目难度比较低,希望能够抛砖引玉。</p><h2 id="cat-theory"><a href="#cat-theory" class="headerlink" title="cat_theory"></a>cat_theory</h2><h3 id="题解"><a href="#题解" class="headerlink" title="题解"></a>题解</h3><p>根据交换图,两个明文先做加法再加密,其结果与先加密再做密文乘法相同。因此CatCrypto是一个同态加密,具有加法同态性。</p><p><em>其实这道题是Paillier-DJN算法,Paillier的一个变种。见<a href="https://zhuanlan.zhihu.com/p/420417626">Paillier半同态加密:原理、高效实现方法和应用</a></em></p><p><img src="交换图原图.png" alt="交换图原图"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> long_to_bytes</span><br><span class="line"></span><br><span class="line">m1_plus_m2 = <span class="number">127944711034541246075233071021313730868540484520031868999992890340295169126051051162110</span></span><br><span class="line">m2_plus_m3 = <span class="number">63052655568318504263890690011897854119750959265293397753485911143830537816733719293484</span></span><br><span class="line">m3_plus_m1 = <span class="number">70799336441419314836992058855562202282043225138455808154518156432965089076630602398416</span></span><br><span class="line"></span><br><span class="line">m = (m1_plus_m2 + m2_plus_m3 + m3_plus_m1) // <span class="number">2</span></span><br><span class="line"><span class="built_in">print</span>(long_to_bytes(m))</span><br><span class="line"></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">b'CatCTF{HE_sch3m3_c4n_b3_a_c4t_eg0ry}'</span></span><br><span class="line"><span class="string">"""</span></span><br></pre></td></tr></table></figure><h3 id="动机"><a href="#动机" class="headerlink" title="动机"></a>动机</h3><p>因为是Cat CTF,并且说出题可以不限于传统的CTF思路,所以想涉及一些猫论(category theory, 范畴论)。找了一些资料来看:<a href="https://www.peterhines.info/resources/talks/thompson.pdf">Categorical & Diagrammatic methods In Cryptography and Communication</a><br>确实有一些人提出范畴论与密码学结合,想法很有意思(比如p35~36的内容)。但这些想法似乎还没有太多应用。并且我自己对范畴论了解也很有限,也没试过自己编造一个密码方案。一时间想不到怎么用这个出一道题。</p><p>正好想到Craig Gentry(第一个全同态方案的提出者)给出的用交换图概括同态加密,交换图可以算是范畴论的东西,并且在密码学中也还是经常能看到的。于是干脆来个Paillier-DJN同态加密方案(Paillier的改进方案),给一张交换图来提示同态性。</p><h2 id="cat’s-gift"><a href="#cat’s-gift" class="headerlink" title="cat’s gift"></a>cat’s gift</h2><h3 id="题解-1"><a href="#题解-1" class="headerlink" title="题解"></a>题解</h3><p>跨年气氛题,想起Amann的Analysis上有一只猫猫,翻了一会儿找到一个与pi相关的公式。<strong>注意到flag示例中 CatCTF{apple} CatCTF{banana}是小写开头英文单词,都是食物,以及题目中提到这是一份礼物,因此提交的flag不是pi而是pie。</strong></p><p>有四种解法</p><ol><li><p>法一:直接猜结果是pie</p></li><li><p>法二:手算,写出arctanx的幂级数展开,然后把x=1带进去</p></li><li><p>法三:编程算近似值,然后猜</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">solve_gift</span>(<span class="params">n=<span class="number">100</span></span>):</span><br><span class="line"> ans = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(n):</span><br><span class="line"> ans += (-<span class="number">1</span>)**i * <span class="number">1</span>/(<span class="number">2</span>*i + <span class="number">1</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> ans * <span class="number">4</span></span><br><span class="line"> </span><br><span class="line">solve_gift(n=<span class="number">10000000</span>)</span><br></pre></td></tr></table></figure></li></ol><ol><li>法四:问猫猫(根据题目描述的提示)</li></ol><p> 找到Amann的 Analysis I p389</p><p><img src="Leibniz公式.png" alt="Leibniz公式"></p><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>其实pi=pie也是一种数学文化,3.14那天有一些人会吃派庆祝,因此就把这个题放在了跟数学最相近的crypto里面。出题时感觉应该很自然能想到pie吧,没想到很多朋友因为没有get到所以没做出来…</p><p>忘记了这是一种小众文化,出题人<strong>随缘在此向各位深表歉意</strong>。</p>]]></content>
<summary type="html"><p>CatCTF的题目总结以及出题的动机、想法。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="CTF" scheme="https://su1yu4n.github.io/tags/CTF/"/>
<category term="出题记录" scheme="https://su1yu4n.github.io/tags/%E5%87%BA%E9%A2%98%E8%AE%B0%E5%BD%95/"/>
</entry>
<entry>
<title>几个对CBC模式分组密码的简单攻击</title>
<link href="https://su1yu4n.github.io/2022/11/19/%E5%87%A0%E4%B8%AA%E5%AF%B9CBC%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%AE%80%E5%8D%95%E6%94%BB%E5%87%BB/"/>
<id>https://su1yu4n.github.io/2022/11/19/%E5%87%A0%E4%B8%AA%E5%AF%B9CBC%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%AE%80%E5%8D%95%E6%94%BB%E5%87%BB/</id>
<published>2022-11-19T04:56:39.000Z</published>
<updated>2024-11-23T07:40:12.686Z</updated>
<content type="html"><![CDATA[<p><strong>总结CBC模式下的字节翻转攻击和Padding Oracle Attack</strong>。由于时间关系,padding oracle attack的原理部分暂时上传手稿截图。</p><span id="more"></span><h2 id="CBC模式"><a href="#CBC模式" class="headerlink" title="CBC模式"></a>CBC模式</h2><p>参考<a href="https://ctf-wiki.org/crypto/blockcipher/mode/cbc/">CTF Wiki</a>即可。</p><p>除了CBC的结构需要掌握,还要知道一个很重要的结论:<strong>标准的CBC是CPA安全的,但不是CCA安全的。</strong>也就是说我们有一些选择密文攻击(Chosen Ciphertext Attack)。</p><h2 id="字节翻转攻击-Bit-Flip"><a href="#字节翻转攻击-Bit-Flip" class="headerlink" title="字节翻转攻击(Bit Flip)"></a>字节翻转攻击(Bit Flip)</h2><h3 id="攻击条件"><a href="#攻击条件" class="headerlink" title="攻击条件"></a>攻击条件</h3><p>假设我们知道采用的加密算法和IV值,并且我们知道一个明密文对$(P_1||P_2, C_1||C_2)$。假设我们可以控制待解密的$C_1||C_2$。 (这里$A||B$表示两个连续的明/密文分组)</p><h3 id="攻击原理和效果"><a href="#攻击原理和效果" class="headerlink" title="攻击原理和效果"></a>攻击原理和效果</h3><p>我们可以伪造密文,使得解密后的明文为$P_1||A$。其中第二个明文分组$A$是我们自己随意选择的。这是因为我们有:</p><script type="math/tex; mode=display">C_{i} = E_{K}\left(P_{i} \ \oplus \ C_{i-1}\right) \Longrightarrow \\ P_{i} = D_{K}(C_{i}) \ \oplus \ C_{i-1} \Longrightarrow \\ P_{2} = D_{K}(C_{2}) \ \oplus \ C_1</script><p><strong>如果我们想伪造$P_2’ = A$,我们只需要取$C_{1}’ = C_{1} \oplus P_{2} \oplus A$。</strong>可以验证等式$P_{2}’ = D_{K}(C_{2}) \ \oplus \ C_1’$ 成立。因此$C_{1}’ || C_{2}$对应的明文确实是$P_1||A$。</p><h3 id="可以控制IV的情况"><a href="#可以控制IV的情况" class="headerlink" title="可以控制IV的情况"></a>可以控制IV的情况</h3><p>如果我们能控制$IV$和密文值,由于$IV = C_{0}$,我们也有类似的攻击方法。考虑到</p><script type="math/tex; mode=display">P_{1} = D_{K}(C_{1}) \ \oplus \ C_0, \ \text{where} \ C_0 = IV</script><p>那么我们按照上面改$C_1$的方法修改$IV$即可。</p><p><em>Cryptohack有一个CTF题,感兴趣的可以找到它练一下。但是考虑到cryptohack的规则,我不说是哪个。</em></p><h2 id="Padding-Oracle-Attack"><a href="#Padding-Oracle-Attack" class="headerlink" title="Padding Oracle Attack"></a>Padding Oracle Attack</h2><p><em>以下攻击条件和攻击效果两部分基本引用了<a href="https://ctf-wiki.org/crypto/blockcipher/mode/padding-oracle-attack/">CTF Wiki - padding oracle attack</a>中的内容。但是我在看CTF Wiki攻击原理部分的时候感觉有一些不清晰的地方,因此我还是自己手推了一下攻击原理。</em></p><h3 id="攻击条件-1"><a href="#攻击条件-1" class="headerlink" title="攻击条件"></a>攻击条件</h3><p>Padding Oracle Attack 攻击一般需要满足以下几个条件</p><ul><li><p>加密算法</p><ul><li>采用 PKCS5/PKCS7 Padding 的加密算法。 当然,非对称加密中 OAEP 的填充方式也有可能会受到影响。</li><li>分组模式为 CBC 模式。</li></ul></li><li><p>攻击者能力</p><ul><li>攻击者可以拦截上述加密算法加密的消息。</li><li>攻击者可以和 padding oracle(即服务器) 进行交互:客户端向服务器端发送密文,服务器端会以某种返回信息告知客户端 padding 是否正常。</li></ul></li></ul><h3 id="攻击效果"><a href="#攻击效果" class="headerlink" title="攻击效果"></a>攻击效果</h3><p>Padding Oracle Attack 攻击可以达到的效果如下</p><ul><li>在不清楚 key 和 IV 的前提下解密任意给定的密文。</li></ul><h3 id="攻击原理"><a href="#攻击原理" class="headerlink" title="攻击原理"></a>攻击原理</h3><p>大思路是根据padding格式推出最后一个字节,然后在此基础上再考虑推出倒数第二个字节…最终发现可以对任意一个密文分组做解密。直接贴手稿图。</p><p><img src="padding_oracle_1.jpg" alt="padding_oracle_1"></p><p><img src="padding_oracle_2.jpg" alt="padding_oracle_2"></p><h3 id="一些对攻击的防御"><a href="#一些对攻击的防御" class="headerlink" title="一些对攻击的防御"></a>一些对攻击的防御</h3><ol><li><p>采用一些别的padding(例如One and Zeroes Padding)可以防止这个攻击,但是会有一些别的问题。参考:<a href="https://www.isg.rhul.ac.uk/~prai175/ISGStudentSem07/PaddingOracleAttacksphdseminar.pdf">Securing CBC mode Against Padding Oracle Attacks</a></p></li><li><p>引用<a href="https://research.nccgroup.com/2021/02/17/cryptopals-exploiting-cbc-padding-oracles/">Cryptopals: Exploiting CBC Padding Oracles</a>的Defenses部分</p></li></ol><blockquote><p>This attack is a chosen-ciphertext attack. It depends on the attacker being able to submit arbitrary ciphertexts to the oracle. As such, you can prevent the attack by <em>authenticating your ciphertexts</em>. <strong>You might do this by switching from CBC mode to an authenticated encryption mode like GCM or OCB; alternately, keep CBC mode but start MACing your ciphertexts using something like HMAC</strong>.</p><p>Removing the oracle would also prevent the attack. However, hopefully the example oracles above gave you some sense of how nontrivial this actually can be in practice. This is a cryptographic problem and it calls for a cryptographic solution; anything less is likely to be fragile and error-prone.</p><p>By adding authentication tags and checking them prior to decryption, we guarantee that we’ll be able to reject any attacker-crafted messages without ever decrypting them, preventing us from leaking any information at all about their decrypted contents, padding-related or otherwise.</p></blockquote><h3 id="现实中的攻击实例"><a href="#现实中的攻击实例" class="headerlink" title="现实中的攻击实例"></a>现实中的攻击实例</h3><ul><li>POODLE attack</li></ul><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ol><li><p><a href="https://ctf-wiki.org/crypto/blockcipher/mode/cbc/">CTF Wiki</a></p></li><li><p><a href="https://robertheaton.com/2013/07/29/padding-oracle-attack/">Robert Heaton - The Padding Oracle Attack</a></p></li><li><p>Cryptohack’s CTF challenges. Symmetry category</p><p><em>According to the rule of cryptohack, I won’t tell you which challenge is it. Sorry about that.</em></p></li><li><p>Securing CBC mode Against Padding Oracle Attacks</p></li><li><a href="https://research.nccgroup.com/2021/02/17/cryptopals-exploiting-cbc-padding-oracles/">Cryptopals: Exploiting CBC Padding Oracles</a></li></ol>]]></content>
<summary type="html"><p><strong>总结CBC模式下的字节翻转攻击和Padding Oracle Attack</strong>。由于时间关系,padding oracle attack的原理部分暂时上传手稿截图。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="分组密码" scheme="https://su1yu4n.github.io/tags/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81/"/>
<category term="Padding Oracle Attack" scheme="https://su1yu4n.github.io/tags/Padding-Oracle-Attack/"/>
<category term="字节翻转攻击" scheme="https://su1yu4n.github.io/tags/%E5%AD%97%E8%8A%82%E7%BF%BB%E8%BD%AC%E6%94%BB%E5%87%BB/"/>
</entry>
<entry>
<title>WSL2配置个人开发环境(C + Rust + sagemath)</title>
<link href="https://su1yu4n.github.io/2022/10/23/WSL2%20%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
<id>https://su1yu4n.github.io/2022/10/23/WSL2%20%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/</id>
<published>2022-10-23T14:00:00.000Z</published>
<updated>2024-11-23T07:41:08.246Z</updated>
<content type="html"><![CDATA[<p>之前把电脑恢复出厂设置了所以重新配了环境。这次正好把上次的问题解决了,记录下基于WSL2的开发环境配置。包括WSL2, sagemath, vscode, rust, C/C++. </p><span id="more"></span><p>我vim等工具玩的也不多,而且感觉也没需求(不过这次重装其实就是打N1CTF半截,vscode连不上WSL2,然后WSL2也炸了)。所以不搞花里胡哨的,一切从简..<br>但是sagemath 10.x版本对我来说很有必要,而apt包管理器目前只能下到9.5,所以sagemath是自己编译的。</p><h2 id="前置"><a href="#前置" class="headerlink" title="前置"></a>前置</h2><h2 id="WSL2-vscode"><a href="#WSL2-vscode" class="headerlink" title="WSL2 + vscode"></a>WSL2 + vscode</h2><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p><strong>默认是装C盘的,上次我C盘空间不足,很折磨。</strong> 所以这次选择手动安装。</p><p><strong>正确做法是import或者先官方安装 export再import,千万别自己解压缩包然后像下面这样安装!!</strong></p><ol><li><p>先升级Windows11到23H2,否则不方便让WSL2科学上网。这会影响到sagemath高版本的编译。<em>23H2应该很快就发布了,急着用就看<a href="https://zhuanlan.zhihu.com/p/593263088">这篇的2023.9.19更新</a></em></p></li><li><p>下载WSL2并做安装所需的前置步骤:<a href="https://learn.microsoft.com/zh-cn/windows/wsl/install-manual#downloading-distributions">下载发行版</a>里面选个ubuntu的LTS高版本下载,同时往上翻完成<strong>前五步</strong></p></li><li><p>下载的<code>.appx</code>文件后缀改为<code>.zip</code>,架构的<code>.appx</code>包拖出来再改为<code>.zip</code>,解压到你想安装的文件夹。然后点击ubuntu.exe</p></li><li><p>直接装vscode,打开右下角自动提示安装WSL2扩展。下面改xxx文件就可以直接code xxx了。没写权限先chmod,再改回去</p></li><li><p>Windows上装点东西:<a href="https://learn.microsoft.com/zh-cn/windows/wsl/setup/environment">设置 WSL 开发环境的最佳做法分步指南</a>。 Windows Terminal 肯定还是要装,别的看着办。</p></li></ol><h3 id="ubuntu配置"><a href="#ubuntu配置" class="headerlink" title="ubuntu配置"></a>ubuntu配置</h3><ol><li><p>换国内源</p></li><li><p>安装实用工具(可选):thefuck, ag, …</p></li><li><p><strong>给WSL2加内存、处理器核心数等等</strong>。根据<a href="https://learn.microsoft.com/en-us/windows/wsl/wsl-config#example-wslconfig-file">官方文档示例</a>,新建或编辑WSL的全局配置文件内容如下(根据自己电脑的配置自行修改),文件路径为<code>C:\Users\<YourUserName>\.wslconfig</code></p> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"># Settings apply across all Linux distros running on WSL 2</span><br><span class="line">[wsl2]</span><br><span class="line"></span><br><span class="line"># Limits VM memory to use no more than 14 GB, this can be set as whole numbers using GB or MB</span><br><span class="line">memory=14GB</span><br><span class="line"></span><br><span class="line"># Sets the VM to use six virtual processors</span><br><span class="line">processors=6</span><br><span class="line"></span><br><span class="line"># Specify a custom Linux kernel to use with your installed distros. The default kernel used can be found at https://github.com/microsoft/WSL2-Linux-Kernel</span><br><span class="line"># kernel=C:\\temp\\myCustomKernel</span><br><span class="line"></span><br><span class="line"># Sets additional kernel parameters, in this case enabling older Linux base images such as Centos 6</span><br><span class="line"># kernelCommandLine = vsyscall=emulate</span><br><span class="line"></span><br><span class="line"># Sets amount of swap storage space to 14GB, default is 25% of available RAM</span><br><span class="line">swap=14GB</span><br><span class="line"></span><br><span class="line"># Sets swapfile path location, default is %USERPROFILE%\AppData\Local\Temp\swap.vhdx</span><br><span class="line">swapfile=E:\\temp\\wsl-swap.vhdx</span><br><span class="line"></span><br><span class="line"># Disable page reporting so WSL retains all allocated memory claimed from Windows and releases none back when free</span><br><span class="line">pageReporting=false</span><br><span class="line"></span><br><span class="line"># Turn off default connection to bind WSL 2 localhost to Windows localhost</span><br><span class="line">localhostforwarding=true</span><br><span class="line"></span><br><span class="line"># Disables nested virtualization</span><br><span class="line">nestedVirtualization=false</span><br><span class="line"></span><br><span class="line"># Turns on output console showing contents of dmesg when opening a WSL 2 distro for debugging</span><br><span class="line">debugConsole=true</span><br><span class="line"></span><br><span class="line"># Enable experimental features</span><br><span class="line">[experimental]</span><br><span class="line">sparseVhd=true</span><br><span class="line"></span><br><span class="line"># For network purpose. Only useful when windows version is 23H2, and wsl --update --pre-release </span><br><span class="line"># Currently only a windows insider of Release Preview Channel can use this..</span><br><span class="line">networkingMode=mirrored</span><br><span class="line">dnsTunneling=true</span><br><span class="line">firewall=true</span><br><span class="line">autoProxy=true</span><br></pre></td></tr></table></figure><p> <strong>其中<code>swapfile</code>设定的路径所在文件夹必须存在</strong>。编辑之后,让WSL2关机再重启才会生效。Powershell <code>wsl --shutdown</code> 关机</p></li></ol><ol><li>让WSL2能科学上网,eg. <a href="https://zhuanlan.zhihu.com/p/451198301">clash</a>. 评论区也写了怎么一键配置和取消配置。</li></ol><h2 id="Rust"><a href="#Rust" class="headerlink" title="Rust"></a>Rust</h2><p>官网或直接一句话安装:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --proto <span class="string">'=https'</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh</span><br></pre></td></tr></table></figure><p>vscode扩展插件装上rust-analyzer。</p><h2 id="C-C"><a href="#C-C" class="headerlink" title="C/C++"></a>C/C++</h2><p>需要读一些项目代码,既安装了gcc又安装了clang。<br>目前vscode配上了扩展: call graph(LuoZhihao写的那个)。感觉效果差一些,准备摸索一下用doxygen + codeviz生成call graph。</p><h2 id="conda-sage源码安装sage"><a href="#conda-sage源码安装sage" class="headerlink" title="conda+sage源码安装sage"></a>conda+sage源码安装sage</h2><p><strong>自己编译sagemath真的很坑,很难装上,基本上得去google group请教sagemath的人。但是用anaconda安装还是不难的。</strong></p><p>此处参考<a href="https://doc.sagemath.org/html/en/installation/conda.html#using-conda-to-provide-all-dependencies-for-the-sage-library">sagemath conda安装方法</a>的’Using conda to provide all dependencies for the Sage library’章节</p><ol><li>先把sage源码 git clone下来, checkout 到 master分支:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">ORIG=https://github.com/sagemath/sage.git</span><br><span class="line"><span class="comment"># git clone -c core.symlinks=true --branch develop --tags $ORIG</span></span><br><span class="line">git <span class="built_in">clone</span> <span class="variable">$ORIG</span></span><br><span class="line"><span class="built_in">cd</span> sage</span><br><span class="line">git checkout master</span><br></pre></td></tr></table></figure></li><li>找个合适地方下载conda。注意读LICENSE环节,然后全部选择yes<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -L -O https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-$(<span class="built_in">uname</span>)-$(<span class="built_in">uname</span> -m).sh</span><br><span class="line">sh Mambaforge-$(<span class="built_in">uname</span>)-$(<span class="built_in">uname</span> -m).sh</span><br></pre></td></tr></table></figure></li><li>配置conda源为阿里源,据说清华源中科大源现在不好用了:<a href="https://developer.aliyun.com/mirror/anaconda">配置说明</a></li><li><code>conda install mamba</code></li><li>配置mamba源,类似conda源的配置:<a href="http://hpc.ncpgr.cn/app/099-mamba/#_1">说明</a>. 实际上直接把 .condarc 的拷一下就行. 然后也是 <code>mamba clean -i</code></li><li>回到clone的sage文件夹,然后开始安装环境<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 可以把sage改成XXX,以后activate时 mamba activate XXX</span></span><br><span class="line">mamba <span class="built_in">env</span> create --file src/environment-3.11.yml --name sage</span><br><span class="line">mamba activate sage</span><br></pre></td></tr></table></figure></li><li><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">./bootstrap</span><br><span class="line">pip install --no-build-isolation -v -v --editable ./pkgs/sage-conf_conda ./pkgs/sage-setup</span><br><span class="line">pip install --no-build-isolation --config-settings editable_mode=compat -v -v --editable ./src </span><br></pre></td></tr></table></figure></li><li>验证sagemath已安装<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sage -c <span class="string">'print(version())'</span></span><br></pre></td></tr></table></figure></li></ol>]]></content>
<summary type="html"><p>之前把电脑恢复出厂设置了所以重新配了环境。这次正好把上次的问题解决了,记录下基于WSL2的开发环境配置。包括WSL2, sagemath, vscode, rust, C/C++. </p></summary>
<category term="Misc Tech" scheme="https://su1yu4n.github.io/categories/Misc-Tech/"/>
<category term="环境搭建" scheme="https://su1yu4n.github.io/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
</entry>
<entry>
<title>【论文翻译】BKZ 2.0: Better Lattice Security Estimates</title>
<link href="https://su1yu4n.github.io/2022/04/15/%E3%80%90%E8%AE%BA%E6%96%87%E7%BF%BB%E8%AF%91%E3%80%91BKZ-2-0-Better-Lattice-Security-Estimates/"/>
<id>https://su1yu4n.github.io/2022/04/15/%E3%80%90%E8%AE%BA%E6%96%87%E7%BF%BB%E8%AF%91%E3%80%91BKZ-2-0-Better-Lattice-Security-Estimates/</id>
<published>2022-04-15T13:24:44.000Z</published>
<updated>2024-11-23T07:40:12.686Z</updated>
<content type="html"><![CDATA[<p>这是我毕业设计的论文翻译。之前用word写的,转为markdown发在csdn上发现公式显示不全。现在采用pdf格式上传到这个博客上。</p><span id="more"></span><p><a href="BKZ 2.0论文翻译.pdf">BKZ 2.0论文翻译.pdf</a></p>]]></content>
<summary type="html"><p>这是我毕业设计的论文翻译。之前用word写的,转为markdown发在csdn上发现公式显示不全。现在采用pdf格式上传到这个博客上。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="格基规约算法" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95/"/>
<category term="BKZ 2.0" scheme="https://su1yu4n.github.io/tags/BKZ-2-0/"/>
<category term="论文翻译" scheme="https://su1yu4n.github.io/tags/%E8%AE%BA%E6%96%87%E7%BF%BB%E8%AF%91/"/>
</entry>
<entry>
<title>密码学的抽代基础总结</title>
<link href="https://su1yu4n.github.io/2022/04/06/%E5%AF%86%E7%A0%81%E5%AD%A6%E7%9A%84%E6%8A%BD%E4%BB%A3%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93/"/>
<id>https://su1yu4n.github.io/2022/04/06/%E5%AF%86%E7%A0%81%E5%AD%A6%E7%9A%84%E6%8A%BD%E4%BB%A3%E5%9F%BA%E7%A1%80%E6%80%BB%E7%BB%93/</id>
<published>2022-04-05T16:00:00.000Z</published>
<updated>2024-11-23T07:39:12.058Z</updated>
<content type="html"><![CDATA[<p>整理一下密码学常用的抽代知识。分成两个部分:基本框架、重要内容。</p><p><strong>我在B站上录制了一个课程(建议1.5倍速),2小时即可快速回顾抽代知识:</strong><a href="https://www.bilibili.com/video/BV1pS4y1b7P6">密码学的数学基础:课程简介</a></p><span id="more"></span><h2 id="基本框架和语言"><a href="#基本框架和语言" class="headerlink" title="基本框架和语言"></a>基本框架和语言</h2><p>几个重要术语:<strong>代数结构、子结构、同态、商结构</strong></p><p>在线性代数中对应:线性空间、子空间、线性映射、商空间</p><div class="table-container"><table><thead><tr><th style="text-align:center">代数结构</th><th style="text-align:center">子结构</th><th style="text-align:center">同态</th><th style="text-align:center">商结构</th></tr></thead><tbody><tr><td style="text-align:center">群</td><td style="text-align:center">子群</td><td style="text-align:center">群同态</td><td style="text-align:center">正规子群->商群</td></tr><tr><td style="text-align:center">环</td><td style="text-align:center">子环</td><td style="text-align:center">环同态</td><td style="text-align:center">理想->商环</td></tr><tr><td style="text-align:center">域</td><td style="text-align:center">子域</td><td style="text-align:center">/(同上)</td><td style="text-align:center">/(同上)</td></tr><tr><td style="text-align:center">线性空间</td><td style="text-align:center">子空间</td><td style="text-align:center">线性映射</td><td style="text-align:center">商空间</td></tr></tbody></table></div><p>直积(直和)、生成子集对应线性代数中的直和、基。</p><h2 id="其他重要内容"><a href="#其他重要内容" class="headerlink" title="其他重要内容"></a>其他重要内容</h2><h3 id="群、环"><a href="#群、环" class="headerlink" title="群、环"></a>群、环</h3><ul><li>拉格朗日定理——费马小定理、欧拉定理</li><li>同构第一定理——$\mathbb{Z}_{N} \cong \mathbb{Z}/N\mathbb{Z}$(模运算)、中国剩余定理</li><li>循环群——离散对数问题</li><li>多项式环——NTRU、多变量公钥</li><li>一些概念:整环、除环、域、主理想、素理想、极大理想…</li><li><script type="math/tex">UFD \geq PID \geq ED</script></li></ul><h3 id="域"><a href="#域" class="headerlink" title="域"></a>域</h3><ul><li><p>素域、域的特征</p></li><li><p>由整环构造域:分式域、$R/M$ ( $PID$ 中 $R/(p)$ )</p></li><li><p>域的分类:按元素个数分为有限域、无限域,可用特征区分</p></li><li><p>域的扩张:代数扩张与有限扩张、<em>超越扩张与无限扩张</em></p></li><li><p>多项式的分裂域,例如 $\mathbb{R}$ 上 $x^2+1$ 的分裂域,$x^n - 1$ 的分裂域。</p></li><li><p>有限域的结构:子域格、$\mathbb{F}_q$ 作为向量空间,$\mathbb{F}_q$ 作为分裂域、本原元</p></li><li><p>一般有限域的结论(与$\mathbb{F}_p$类似):费马小定理、欧拉定理、Wilson定理… </p></li><li><p>有限域上的运算、元素的表示</p></li><li><p>本原多项式——LFSR相关理论、周期计算等</p></li></ul>]]></content>
<summary type="html"><p>整理一下密码学常用的抽代知识。分成两个部分:基本框架、重要内容。</p>
<p><strong>我在B站上录制了一个课程(建议1.5倍速),2小时即可快速回顾抽代知识:</strong><a href="https://www.bilibili.com/video/BV1pS4y1b7P6">密码学的数学基础:课程简介</a></p></summary>
<category term="Math" scheme="https://su1yu4n.github.io/categories/Math/"/>
<category term="抽象代数" scheme="https://su1yu4n.github.io/tags/%E6%8A%BD%E8%B1%A1%E4%BB%A3%E6%95%B0/"/>
</entry>
<entry>
<title>这是我的新博客!</title>
<link href="https://su1yu4n.github.io/2022/01/21/hello-world/"/>
<id>https://su1yu4n.github.io/2022/01/21/hello-world/</id>
<published>2022-01-21T04:00:00.000Z</published>
<updated>2022-01-25T01:32:46.000Z</updated>
<content type="html"><![CDATA[<p>感觉写得好的文章放到csdn就是浪费,所以决定整一个新的。除了数学、密码学和技术,这个博客里可能还会放一些其他的东西。下面是以前博客的链接。</p><span id="more"></span><p>我原来的csdn博客:<a href="https://blog.csdn.net/qq_42667481">https://blog.csdn.net/qq_42667481</a></p>]]></content>
<summary type="html"><p>感觉写得好的文章放到csdn就是浪费,所以决定整一个新的。除了数学、密码学和技术,这个博客里可能还会放一些其他的东西。下面是以前博客的链接。</p></summary>
</entry>
<entry>
<title>掌灯人</title>
<link href="https://su1yu4n.github.io/2021/10/30/%E6%8E%8C%E7%81%AF%E4%BA%BA/"/>
<id>https://su1yu4n.github.io/2021/10/30/%E6%8E%8C%E7%81%AF%E4%BA%BA/</id>
<published>2021-10-30T13:07:38.000Z</published>
<updated>2023-10-23T14:05:45.154Z</updated>
<content type="html"><![CDATA[<p>2021年10月底,写了一些反映当时心境的文字。当时想把它写成小说之类的东西,不过后来没有继续。</p><p>正文请点击阅读更多查看</p><span id="more"></span><h2 id="掌灯人"><a href="#掌灯人" class="headerlink" title="掌灯人"></a>掌灯人</h2><h3 id="其一"><a href="#其一" class="headerlink" title="其一"></a>其一</h3><p>与同行者从黑暗中走出时,他才发现不知何时手里已拿着一盏灯。其实世界还是一片黑,只不过为了方便自己探路,在某个地方偶然发现了一盏还能点亮的煤油灯拿了起来。就这样,他决定成为一名掌灯人。</p><p>点着了灯,便有顺路的人同行。可惜这灯并不强力,当寒风吹来时灯火便摇摇欲坠,于是众人便紧紧的围在一起,以防灯火被寒风吹灭。不过也因为这样,原本就不是很亮的灯只能照亮周围几个身位的距离,因此这队伍也无法壮大。况且,掌灯人听说过有人并不喜欢灯光,甚至会将灯偷偷灭掉,因此他总是戒备着那些在远处,看不清脸上表情的人。</p><p>每个人都有自己要走的道路,即使是掌灯的人也不例外。在一个错综复杂的路口,将与众人分道扬镳的。突然,身边的一人拿起一抔雪要将掌灯人手里的灯扑灭。</p><p>掌灯人知道自己手里的灯不能承受这袭击。好在,掌灯人毕竟是掌灯人,他及时护住自己的灯,让雪打在了自己身上。</p><p>(待续)</p>]]></content>
<summary type="html"><p>2021年10月底,写了一些反映当时心境的文字。当时想把它写成小说之类的东西,不过后来没有继续。</p>
<p>正文请点击阅读更多查看</p></summary>
<category term="文字" scheme="https://su1yu4n.github.io/tags/%E6%96%87%E5%AD%97/"/>
</entry>
<entry>
<title>RSA的共解密指数攻击</title>
<link href="https://su1yu4n.github.io/2021/06/29/RSA%E7%9A%84%E5%85%B1%E8%A7%A3%E5%AF%86%E6%8C%87%E6%95%B0%E6%94%BB%E5%87%BB/"/>
<id>https://su1yu4n.github.io/2021/06/29/RSA%E7%9A%84%E5%85%B1%E8%A7%A3%E5%AF%86%E6%8C%87%E6%95%B0%E6%94%BB%E5%87%BB/</id>
<published>2021-06-29T04:00:00.000Z</published>
<updated>2024-11-23T07:40:12.689Z</updated>
<content type="html"><![CDATA[<p>本文总结了一个<strong>基于格的攻击</strong>,该攻击针对的是多个<strong>共用同一个私钥的RSA</strong>实例。<strong>当私钥$\,d\,$满足一定条件时</strong>,即可根据这些RSA实例的公钥<strong>求出$\,d\,$</strong>,从而将这些RSA实例全部破解。</p><span id="more"></span><p>理解本文所需的前置背景:</p><ol><li>格论,可以先看看<a href="/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/" title="格基规约算法:数学基础">格基规约算法:数学基础</a></li><li>格基规约算法的用途,见<a href="/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/" title="格基规约算法:算法详解">格基规约算法:算法详解</a></li></ol><h2 id="攻击描述"><a href="#攻击描述" class="headerlink" title="攻击描述"></a>攻击描述</h2><h3 id="符号约定和假设"><a href="#符号约定和假设" class="headerlink" title="符号约定和假设"></a>符号约定和假设</h3><p>首先我们给出攻击中的假设条件和符号约定。设同一个RSA加密系统中有$\,r\,$个RSA实例共用同一个私钥$\,d\,$,这些实例的公钥分别为$\, \left(e_1,\ N_1\right),\ldots,\left(e_r,\ N_r\right)\,$ 。不妨设$\,N_1,\ldots,\ N_r\,$依次增大,并且由于是同一个系统中的实例,故认为$\, N_1,\ldots,\ N_r\,$具有相同的比特长度,于是有$\,N_1<N_2<\cdots<N_r<2N_1\,$。</p><p><strong>由RSA加密的原理可以得到如下$\,r\,$个方程</strong>:</p><script type="math/tex; mode=display">\begin{array}{c}e_{1} d=1+k_{1} \varphi\left(N_{1}\right) \\e_{2} d=1+k_{2} \varphi\left(N_{2}\right) \\\vdots \\e_{r} d=1+k_{r} \varphi\left(N_{r}\right)\end{array}</script><p>对任意的$\,i\,$,设$\, e_i<\varphi\left(N_i\right)\ ,\ \ \varphi\left(N_r\right)=N_i-s_i\,$.我们<strong>假定生成$\, N_1,\ldots,\ N_r\,$ 的素数具有相同的比特长度</strong>,则${\, s}_{i\ }<3N_1^{1/2}\,$ 。并且最关键的,<strong>假设以下命题成立</strong>:若$\, v\,$是格$\, \mathcal{L}\,$中满足Minkowski’s bound的一个向量,则$\, \pm v\,$为格中所有的非零最短向量,除此以外没有其他向量范数为$\,\lambda_{1}\!\left(\mathcal{L}\right)\,$ 。<br> </p><h3 id="攻击原理和方法"><a href="#攻击原理和方法" class="headerlink" title="攻击原理和方法"></a>攻击原理和方法</h3><p>设$\, M=\left\lfloor N_r^{1/2}\right\rfloor\,$ ,由之前假设中的等式可得方程组</p><script type="math/tex; mode=display">\begin{array}{c}d M=d M \\e_{1} d-N_{1} k_{1}=1-k_{1} s_{1} \\e_{2} d-N_{2} k_{2}=1-k_{2} s_{2} \\\vdots \\e_{r}-N_{r} k_{r}=1-k_{r} s_{r}\end{array}</script><p>下面将方程组写为矩阵形式。记</p><script type="math/tex; mode=display">\, x_r=\left(d,k_1,k_2,\cdots,k_r\right)\ ,v_r=\left(dM,1-k_1s_1,\cdots,1-k_rs_r\right)</script><script type="math/tex; mode=display">\mathcal{B}_{r}=\left[\begin{array}{ccccc}M & e_{1} & e_{2} & \cdots & e_{r} \\0 & -N_{1} & 0 & \cdots & 0 \\0 & 0 & -N_{2} & \cdots & 0 \\\vdots & \vdots & \vdots & \ddots & \vdots \\0 & 0 & 0 & \cdots & -N_{r}\end{array}\right]</script><p>则有$\, x_r\mathcal{B}_r=v_r\,$。注意到$\, \mathcal{B}_r\,$的行向量组生成了一个$\, r+1\,$维的格$\, \mathcal{L}\,$,而$\, v_r\in\mathcal{L}\,$。那么由假设可知,当不等式$\left|v_{r}\right| < \sqrt{r+1} \det(\mathcal{L})^{1 /(r+1)}$ 成立时(即满足Minkowski’s bound时),攻击者<strong>只要解出格$\, \mathcal{L}\,$上的SVP问题即可解出$\, v_r\,$,从而得到$\, v_r\,$第一个分量$\, dM\,$</strong>。$\,M\,$已知,因此攻击者可求出$\, d\,$,从而攻破这些共解密指数实例。</p><h3 id="攻击条件"><a href="#攻击条件" class="headerlink" title="攻击条件"></a>攻击条件</h3><p>经过一些简单的不等式推导可得,当$\, d<N_r^{\delta_r}\,$且$\, \delta_r<\frac{1}{2}-\frac{1}{2(r+2)}-\log_{N_r}6\,$时,不等式$\,\left|v_{r}\right| < \sqrt{r+1} \det(\mathcal{L})^{1 /(r+1)}\,$ 一定能成立。因此$\, d<N_r^{\delta_r}\,$且$\, \delta_r<\frac{1}{2}-\frac{1}{2(r+2)}-\log_{N_r}6\,$就是在先前提出的假设成立时,攻击一定能成功的条件(具体推导请查阅参考资料,查找关键词common private)。</p><p>攻击的提出者Hinek在对RSA-2048/4096进行实验时发现要想保证攻击一定成功,<strong>实际的$\,\delta_r\,$要比满足前面这个不等式的$\,\delta_r\,$最大值小一点(大概小0.005左右)</strong>。</p><p>共用私钥的RSA实例个数$\,r\,$越大,攻击效果越好。Hinek进行了全面的攻击实验,当设定$\,r=35\,$,当$\, d<N^{0.485}\,$,数万次攻击基本全部成功。更详细的实验结果请查阅文末的参考资料。</p><p> </p><h2 id="攻击代码"><a href="#攻击代码" class="headerlink" title="攻击代码"></a>攻击代码</h2><p>以下代码在<strong>sagemath 9.1</strong>上运行。</p><h3 id="攻击算法"><a href="#攻击算法" class="headerlink" title="攻击算法"></a>攻击算法</h3><p>当攻击成功时会计算并打印出正确的私钥$\,d\,$,当攻击失败时计算出的$\,d\,$是错误的。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">instance: 共私钥的RSA实例,为一个列表。该列表的每一项都是字典,instance[i]['e']为第i个RSA实例的e,instance[i]['n']为第i个RSA实例的n。</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">common_private_attack</span>(<span class="params">instance, debug=<span class="literal">False</span>, algo=<span class="string">"LLL"</span></span>):</span><br><span class="line"> r = <span class="built_in">len</span>(instance)</span><br><span class="line"> instance.sort(key=<span class="keyword">lambda</span> x: x[<span class="string">'n'</span>])</span><br><span class="line"> M = isqrt(instance[r-<span class="number">1</span>][<span class="string">'n'</span>]) </span><br><span class="line"> </span><br><span class="line"> <span class="comment"># Build up Lattice basis B</span></span><br><span class="line"> B = zero_matrix(r+<span class="number">1</span>)</span><br><span class="line"> B[<span class="number">0</span>,<span class="number">0</span>] = isqrt(instance[r-<span class="number">1</span>][<span class="string">'n'</span>])</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, r+<span class="number">1</span>):</span><br><span class="line"> B[<span class="number">0</span>,i] = instance[i-<span class="number">1</span>][<span class="string">'e'</span>]</span><br><span class="line"> B[i,i] = - instance[i-<span class="number">1</span>][<span class="string">'n'</span>]</span><br><span class="line"> <span class="keyword">if</span> debug:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"The basis of the lattice we build is:"</span>); <span class="built_in">print</span>(B)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> algo == <span class="string">"LLL"</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Performing LLL reduction..."</span>); B = B.LLL(); <span class="built_in">print</span>(<span class="string">"Done."</span>)</span><br><span class="line"> <span class="keyword">elif</span> algo == <span class="string">"BKZ"</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Performing BKZ reduction..."</span>); B = B.BKZ(block_size=<span class="built_in">len</span>(instance)); <span class="built_in">print</span>(<span class="string">"Done."</span>)</span><br><span class="line"> </span><br><span class="line"> dM = B[<span class="number">0</span>,<span class="number">0</span>]; d = dM // M;</span><br><span class="line"> <span class="comment"># 有时会算出负数</span></span><br><span class="line"> d = <span class="built_in">abs</span>(d)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">" dM = {} \n d = {}"</span>.<span class="built_in">format</span>(dM, d))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> dM % d != <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Fail to attack these instances."</span>)</span><br></pre></td></tr></table></figure><h3 id="测试代码"><a href="#测试代码" class="headerlink" title="测试代码"></a>测试代码</h3><p>调用以下方法即可生成满足攻击条件的RSA实例。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> getStrongPrime, getPrime, getRandomNBitInteger</span><br><span class="line"><span class="keyword">from</span> gmpy2 <span class="keyword">import</span> gcd, invert</span><br><span class="line"><span class="keyword">from</span> math <span class="keyword">import</span> floor, log</span><br><span class="line"></span><br><span class="line"><span class="comment"># Generate r instances of RSA with the same d.</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">gen_instance</span>(<span class="params">r=<span class="number">2</span>, bit_len=<span class="number">2048</span>, delta_r=<span class="literal">None</span>,delta=<span class="number">0</span>, debug=<span class="literal">False</span></span>):</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> delta_r <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line"> delta_r = <span class="number">0.5</span> - <span class="number">0.5</span> / (r+<span class="number">1</span>) - log(<span class="number">6</span>, <span class="number">2</span>^bit_len) + delta</span><br><span class="line"> <span class="comment"># d = getRandomNBitInteger(int(2 * bit_len * delta_r))</span></span><br><span class="line"> d = getPrime(floor(bit_len * delta_r))</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> d & <span class="number">1</span> == <span class="number">0</span>:</span><br><span class="line"> d += <span class="number">1</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"The d we choose is: {}"</span>.<span class="built_in">format</span>(d))</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"d satisfy the condition: d < Nr^{}"</span>.<span class="built_in">format</span>(delta_r))</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"\n"</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Generating instances ..."</span>)</span><br><span class="line"> instance = []</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(r):</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> p = getStrongPrime(bit_len//<span class="number">2</span>)</span><br><span class="line"> q = getStrongPrime(bit_len//<span class="number">2</span>)</span><br><span class="line"><span class="comment"># p = getPrime(bit_len)</span></span><br><span class="line"><span class="comment"># q = getPrime(bit_len)</span></span><br><span class="line"> n = p * q</span><br><span class="line"> phi = (p-<span class="number">1</span>)*(q-<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">if</span> gcd(d, phi) == <span class="number">1</span>:</span><br><span class="line"> e = invert(d, phi)</span><br><span class="line"> this = {<span class="string">'n'</span>:n, <span class="string">'e'</span>:e, <span class="string">'d'</span>:d}</span><br><span class="line"> instance.append(this)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Done."</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> debug:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"The RSA Instances we choose is below:"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(r):</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"instance {}: {}"</span>.<span class="built_in">format</span>(i, instance[i]))</span><br><span class="line"> <span class="keyword">return</span> instance</span><br></pre></td></tr></table></figure><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li>M. Jason Hinek. On the Security of Some Variants of RSA. 2007.</li><li>M. Jason Hinek. Cryptanalysis of RSA and Its Variants. 2009</li></ol>]]></content>
<summary type="html"><p>本文总结了一个<strong>基于格的攻击</strong>,该攻击针对的是多个<strong>共用同一个私钥的RSA</strong>实例。<strong>当私钥$\,d\,$满足一定条件时</strong>,即可根据这些RSA实例的公钥<strong>求出$\,d\,$</strong>,从而将这些RSA实例全部破解。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="RSA" scheme="https://su1yu4n.github.io/tags/RSA/"/>
<category term="密码分析" scheme="https://su1yu4n.github.io/tags/%E5%AF%86%E7%A0%81%E5%88%86%E6%9E%90/"/>
<category term="格论(几何数论)" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E8%AE%BA%EF%BC%88%E5%87%A0%E4%BD%95%E6%95%B0%E8%AE%BA%EF%BC%89/"/>
<category term="格基规约算法" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>格基规约算法:数学基础</title>
<link href="https://su1yu4n.github.io/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/"/>
<id>https://su1yu4n.github.io/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/</id>
<published>2021-06-20T03:10:01.000Z</published>
<updated>2024-11-23T07:40:12.684Z</updated>
<content type="html"><![CDATA[<p>本篇主要介绍学习格密码和格基规约算法必备的格论知识,以下内容为<strong>理解格基规约算法必备的数学基础</strong>。</p><span id="more"></span><!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} --><h1 id="欧氏空间"><a href="#欧氏空间" class="headerlink" title="欧氏空间"></a>欧氏空间</h1><p>想理解格基约化算法,首先<strong>必须理解施密特正交化</strong>。有了向量空间,就可以在空间中随意对向量进行数乘和加减法(怎么做都不会跑出这个空间)。再定义向量的长度和夹角,施密特正交化就显得很自然了。</p><h2 id="欧氏空间和范数"><a href="#欧氏空间和范数" class="headerlink" title="欧氏空间和范数"></a>欧氏空间和范数</h2><h3 id="向量空间"><a href="#向量空间" class="headerlink" title="向量空间"></a>向量空间</h3><p>向量空间的定义<strong>保证了向量的数乘和加减法有很好的性质</strong>。具体定义略,可参阅蓝以中的《高等代数简明教程》等。</p><h3 id="欧氏空间-1"><a href="#欧氏空间-1" class="headerlink" title="欧氏空间"></a>欧氏空间</h3><p><strong>欧氏空间</strong>:设$\,V\,$是实数域$\,\mathbb{R}\,$上的向量空间。如果$\,V\,$内任意两个向量$\,\alpha,\ \beta\,$都按某一法则对应于$\mathbb{R}$内一个唯一确定的数,记作$\,\langle\alpha,\beta\rangle\,$,且满足以下三个条件:</p><ol><li>对任意$\,k_1,k_2\in\mathbb{R}\,$和任意$\,\alpha_1,\alpha_2,\beta\in V\,$,有<script type="math/tex; mode=display">\left\langle{k_1\alpha}_1+k_2\alpha_2,\beta\right\rangle=\ k_1\left\langle\alpha_1,\beta\right\rangle+\ k_2\left\langle\alpha_2,\beta\right\rangle;</script></li><li>对任意$\,\alpha,\ \beta\in V\,$,有<script type="math/tex; mode=display">\left\langle\alpha,\beta\right\rangle=\ \langle\beta,\alpha\rangle;</script></li><li>(非退化性)对任意$\,\alpha\in V\,$,有$\,\left\langle\alpha,\alpha\right\rangle \geq 0\,$,且$\,\left\langle\alpha,\alpha\right\rangle = 0\,$的充分必要条件是$\,\alpha=0,$</li></ol><p>则称$\,\left\langle\alpha,\beta\right\rangle\,$为向量$\,\alpha,\ \beta\,$的内积。$V\,$称为欧几里得空间,简称欧氏空间。</p><p><em>内积是一种具有非退化性的双线性映射,与密码学中常用的双线性对非常类似。</em></p><p>取$\mathbb{R}^{m} \,$的内积为向量的点乘,可以验证<strong>向量空间$\, \mathbb{R}^m\,$是欧氏空间</strong>。</p><p>对于$\mathbb{R}^m$中的向量$\,\alpha\,$,定义其欧氏范数为$\, \left| \alpha \right| = \sqrt{\left\langle\alpha,\alpha\right\rangle} \,$。实际上,<strong>欧氏范数就是平时所说的向量长度</strong>。</p><p>向量的欧氏范数计算方法是对其各分量的平方和开方,因此<strong>也称$\, 2 - \,$范数</strong>。格密码中还会用到$\, \infty \,-$范数。在本篇中,“范数”默认指欧氏范数。</p><h2 id="子空间的正交补"><a href="#子空间的正交补" class="headerlink" title="子空间的正交补"></a>子空间的正交补</h2><p><strong>正交补</strong>:设$\,V\,$是一个$\,n\,$维欧氏空间,$\,M\,$是它的一个子空间,易知$\,M\,$关于$\,V\,$的内积也成一欧氏空间。定义$\,M^\bot \!\subset \!\ V\,$为</p><script type="math/tex; mode=display">M^\bot=\left\{\alpha\in V:\forall\beta\in M,\left\langle\alpha,\beta\right\rangle=0\right\}.</script><p>称$\,M^\bot\,$为$\,M\,$的正交补。$\,M^\bot\,$关于$\,V\,$中向量的加法及数乘运算显然封闭,故$\,M^\bot\,$也为$\,V\,$的子空间。 </p><p> 为了从几何的角度理解正交补,不妨思考一下$\,\mathbb{R}^{2}\,$和$\,\mathbb{R}^{3}\,$中过原点的直线、平面的正交补分别是什么。</p><h2 id="施密特正交化"><a href="#施密特正交化" class="headerlink" title="施密特正交化"></a>施密特正交化</h2><p>在欧氏空间$\,\mathbb{R}^m\,$中有施密特正交化方法。施密特正交化方法是由一个线性无关向量组得到一个正交向量组的方法,并且输入的向量组和输出的向量组张成的是同一个向量空间。格基约化算法的思路与施密特正交化相似并且算法中会调用施密特正交化,因此理解向量空间中的施密特正交化方法是理解格基约化算法的一个关键。</p><p>设$\mathbf{b}_1,\ldots,\mathbf{b}_n$为$\mathbb{R}^m$上一组线性无关的向量,施密特正交化方法如下:<br>令$\,\mathbf{b}_1^\ast=\mathbf{b}_1,$ 依次计算$\, \mathbf{b}_i^\ast=\mathbf{b}_i-\sum_{j=1}^{i-1}{\mu_{i,j}\mathbf{b}_j^\ast},\quad i>1\,$,其中$\,\mu_{i,j}=\frac{\left\langle\mathbf{b}_i,\mathbf{b}_j^\ast\right\rangle}{\left\langle\mathbf{b}_j^\ast,\mathbf{b}_j^\ast\right\rangle}\ ,\ 1\le j\,$。那么$\,\mathbf{b}_1^\ast,\cdots,\mathbf{b}_n^\ast\,$就是$\,\mathbb{R}^m\,$上的一组正交向量。</p><p><strong>核心思路</strong>:先选$\,\mathbf{b}_1^\ast=\mathbf{b}_1$作为基准,然后将$\, \mathbf{b}_2 \,$分解为与$\, \mathbf{b}_1 \,$平行和正交的两个分量,只保留正交的那个分量。</p><p>更进一步的理解是,<strong><script type="math/tex">\mathbf{b}_i^\ast\,</script>是$\, \mathbf{b}_i\,$在$\, \sum_{j=1}^{i-1}{\mathbb{R}\mathbf{b}}_j=\sum_{j=1}^{i-1}{\mathbb{R}\mathbf{b}_j^\ast}$ 的正交补上的投影</strong>。理解这一点才能搞懂格基约化算法的具体细节和优化。</p><h1 id="格论基础"><a href="#格论基础" class="headerlink" title="格论基础"></a>格论基础</h1><h2 id="格的相关概念"><a href="#格的相关概念" class="headerlink" title="格的相关概念"></a>格的相关概念</h2><h3 id="格和格基"><a href="#格和格基" class="headerlink" title="格和格基"></a>格和格基</h3><p><em>这部分没有贴图,可以结合An Introduction to Mathematical Cryptography中格的图像方便理解</em></p><p><strong>格</strong>:给定$n$个线性无关的向量$\mathbf{b}_1,\ldots,\mathbf{b}_n\in\mathbb{R}^m$,则称其整系数线性组合构成的集合</p><script type="math/tex; mode=display">\mathcal{L}=\sum_{i=1}^{n}\mathbf{b}_i\cdot\mathbb{Z}=\left\{\sum_{i=1}^{n}{c_i\mathbf{b}_i}:c_i\in\mathbb{Z}\right\}</script><p>为$\mathbb{R}^m$上的格。我们称$\mathcal{L}$的秩为$n$,$\mathcal{L}$的维数为$m$。我们称上述格的定义中出现的$\mathbf{b}_1,\ldots,\mathbf{b}_n$为格$\mathcal{L}$的一组基,简称<strong>格基</strong>。</p><p>记$\ \mathbf{B}={(\mathbf{b}}_1,\ldots,\mathbf{b}_n)$,称$\mathbf{B}$为基矩阵,那么格$\mathcal{L}$可以进一步表示为<br><script type="math/tex">\mathcal{L}=\sum_{i=1}^{n}\mathbf{b}_i\cdot\mathbb{Z}=\{\mathbf{B}x:x\in\mathbb{Z}^n\}</script><br>可以验证$\, \mathcal{L}\,$<strong>为</strong><script type="math/tex">\,\mathbb{R}^{m}\,</script><strong>的离散加法子群</strong>。与向量空间$\mathbb{R}^m$类似地,格$\mathcal{L}$的基不止一个。事实上[3],任意一个秩为1的格有两组基,而秩大于等于2的格有无数组基。取格$\mathcal{L}$的任意两组基,<strong>一组基矩阵可由另一组基矩阵左乘一个幺模矩阵$\mathbf{U}$得到</strong>,$\mathbf{U}$是两个格基之间的过渡矩阵。</p><h3 id="基本域和体积-volume"><a href="#基本域和体积-volume" class="headerlink" title="基本域和体积(volume)"></a>基本域和体积(volume)</h3><p>称格$\mathcal{L}$的一组格基围成的基本平行体为格$\mathcal{L}$的基本域,其严谨定义如下。</p><p>基本域:设$\mathcal{L}$为一个$n$维的格,且$\mathcal{L}$的一组基为$\mathbf{v}_1,\mathbf{v}_2,\ldots,\mathbf{v}_n$。则格$\mathcal{L}$(就格基$\mathbf{v}_1,\mathbf{v}_2,\ldots,\mathbf{v}_n$而言)的基本域$\mathcal{F}$为</p><script type="math/tex; mode=display">\mathcal{F}\left(\mathbf{v}_1,\ldots,\mathbf{v}_n\right)=\left\{t_1\mathbf{v}_1+t_2\mathbf{v}_2+\cdots+t_n\mathbf{v}_n:0\le t_i<1\right\}</script><p>之后定义格$\mathcal{L}$的行列式如下。<br> 行列式:设$\mathcal{L}$为一个$n$维的格,其基本域为$\mathcal{F}$,则称$\mathcal{F}$的体积(volume)为格$\mathcal{L}$的行列式,记作$\mathrm{det}{(\mathcal{L})}=\mathrm{Vol}(\mathcal{F})$。设$\mathbf{B}={(\mathbf{b}}_1,\ldots,\mathbf{b}_n)为\mathcal{L}$的一组基,根据$\mathrm{det}{(\mathcal{L})}$的几何含义可知$\mathrm{det}(\mathcal{L})= \left | \mathrm{det}{(\mathbf{B})} \right |$。由此易知,虽然$\mathrm{det}{(\mathcal{L})}$被定义$\mathcal{F}$的体积,且$\mathcal{F}$与选取的格基有关,但<strong><script type="math/tex">\mathrm{det}{(\mathcal{L})}</script>是格$\mathcal{L}$的一个不变量</strong>。即任意选取格$\mathcal{L}$的基本域(或者说选取格$\mathcal{L}$的任何一个格基),$\mathrm{det}{(\mathcal{L})}$的值都相同。这也是我们将其记为$\mathrm{det}{(\mathcal{L})}$的理由:其值只与格$\mathcal{L}$本身有关。</p><h3 id="整格-integral-lattice"><a href="#整格-integral-lattice" class="headerlink" title="整格(integral lattice)"></a>整格(integral lattice)</h3><p>密码学中的运算对象基本都是整数,因此实际应用中往往使用整格(integral lattice),其定义如下:若格$\mathcal{L}$中任意向量的坐标,其每个分量均为整数,则称格$\mathcal{L}$为整数格。当$\mathcal{L}$为整格时,$\mathcal{L}$是$\mathbb{Z}^m$的加法子群。</p><p>整格有时候也称为整数格(integer lattice)。</p><h2 id="格上的短向量"><a href="#格上的短向量" class="headerlink" title="格上的短向量"></a>格上的短向量</h2><p>格上的最短向量问题(SVP)是格密码方案安全性基于的难题,也是在格密码和传统公钥密码分析时常使用的问题。SVP及近似SVP问题正是格基约化算法求解的问题。</p><p>为了更好地描述格上短向量的长度,首先给出逐次最小长度的概念。</p><h3 id="逐次最小长度-successive-minima"><a href="#逐次最小长度-successive-minima" class="headerlink" title="逐次最小长度(successive minima)"></a>逐次最小长度(successive minima)</h3><p>逐次最小长度:设$\mathcal{L}$是$\mathbb{R}^m$中秩为$n$的格,设$\lambda_1,\ldots,\lambda_n\in\mathbb{R}$,若$\lambda_{i}\left(1\le i\le n\right)$为满足以下条件的最小值:<br>存在$i$个线性无关的的向量$\mathbf{v}_1,\ldots,\mathbf{v}_i\in\mathcal{L}$,使得$v_j ≤λ_i (1≤j≤i)$<br>则称$\lambda_1,\ldots,\lambda_n$为$\mathcal{L}$的逐次最小长度。为了表明$\lambda_i$是格$\mathcal{L}$的逐次最小长度,记$\lambda_i=\lambda_i(\mathcal{L})$。<br>用通俗的语言来讲,$\lambda_1$是$\mathcal{L}$中非零最短向量的长度,$\lambda_2$是所有非零向量长度中(并列)第二小的长度。这就是逐次最小长度的意义。</p><h3 id="短向量的长度"><a href="#短向量的长度" class="headerlink" title="短向量的长度"></a>短向量的长度</h3><p>为了让读者对$\lambda_1$的大小有一个认识,这里给出一系列相关定理来描述$\lambda_1$的上界。首先给出Minkowski定理作为引理。</p><p><strong>Minkowski定理</strong>:设$\mathcal{L}$是$\mathbb{R}^m$中的格,$S \subset \mathbb{R}^m$是一个关于原点对称的可测凸集,若$S$的体积为$\mathrm{Vol}(S)\geq2^m\mathrm{det}(\mathcal{L})$,则$\, S\cap\mathcal{L}\,$中有非零向量。</p><p>解读:看起来有些高深,但是在$\mathcal{L} = \mathbb{Z}^{2}$中是显然的。要想让对称的凸集$S$尽量大,且$\ S\cap\mathcal{L}\ = \mathbf{0}$,那么正方形应该是最好的选择,此时$\mathrm{Vol}(S) = 2^2\mathrm{det}{(\mathcal{L})}$。类似地,在$\mathcal{L} = \mathbb{Z}^{m}$选取超立方体是最好的。照此思路,$\mathcal{L}$为整数格时Minkowski定理也是很显然的。这样就理解了密码学所用的格中该定理成立。</p><p>利用Minkowski定理可证明下面的Minkowski第一定理(一些文献称其为<strong>Hermite定理</strong>)。<br><strong>Minkowski第一定理</strong>:设$\mathcal{L}$是$\mathbb{R}^m$中秩为$n$的格,则$\lambda_1(\mathcal{L}) \leq \sqrt n\mathrm{det}(\mathcal{L})^{1/n}$。称$\sqrt n\mathrm{det}(\mathcal{L})^{1/n}$为$\lambda_1\left(\mathcal{L}\right)$的<strong>Minkowski’s bound</strong>。</p><p>解读:如果$\mathcal{L} = \mathbb{Z}^{n}$,那么$\mathrm{det}(L)^{1/n}$就是超立方体$S$的边长,而$\sqrt n\mathrm{det}(\mathcal{L})^{1/n}$就是它的对角线长度。由于对角线的另一端就是一个格点,因此$\lambda_1\left(\mathcal{L}\right) \leq \sqrt n\mathrm{det}(\mathcal{L})^{1/n}$。</p><p><em>以上两个解读参考了<a href="https://zhuanlan.zhihu.com/p/161411204">Steven Yue的笔记</a>,推荐看一下。</em></p><p>对于$\lambda_1\left(\mathcal{L}\right)$,我们还能得到比Minkowski’s bound更好的理论上界。下面给出Hermite因子的概念。<br> <strong>Hermite因子</strong>:给定格的维度$n$,定义Hermite因子$\gamma_n\in\mathbb{R}$为满足以下条件的最小值:<br>对于任意维度为$n$的格$\mathcal{L}$,存在$\, \mathbf{v}\in\mathcal{L}\,$满足$\ \left|\mathbf{v}\right|^{2} ≤γ_{n}\mathrm{det}{(\mathcal{L})}^{2/n}$。称$\sqrt{\gamma_n}\mathrm{det}\left(\mathcal{L}\right)^{1/n}$为$\ \lambda_1\left(\mathcal{L}\right) \,$的Hermite bound。<br>根据定义可知,Hermite因子的大小只与$n$有关,目前我们只知道$\gamma_n$在 $1\le n\le 8$ 和 $n=24$ 时的精确值: </p><script type="math/tex; mode=display">\gamma_2^2=\frac{4}{3},\gamma_3^3=2,\gamma_4^4=4,\gamma_5^5=8,\gamma_6^6=\frac{64}{3},\gamma_7^7=64,\gamma_8^8=256,\gamma_{24}=4.</script><p>在格密码学中我们更关心$n$较大$(n > 200)$时$\gamma_n$的值,<strong>此时$\gamma_n$满足</strong></p><script type="math/tex; mode=display">\frac{n}{2\pi e}\le\gamma_n\le\frac{n}{\pi e} \, .</script><p>由Hermite因子能够得到比Minkowski’s bound更精确的$\lambda_1$上界。以维度为$n=2$的格$\mathcal{L}$为例,Minkowski’s bound告诉我们$\ \lambda_{1}(\mathcal{L})<\sqrt2\mathrm{det}(\mathcal{L})^{1/2}$ ,而由Hermite因子可得$\lambda_{1}(\mathcal{L}) < \sqrt{4/3} \mathrm{det}\left(\mathcal{L}\right)^{1/2}$。</p><p>下面的高斯启发函数与Hermite因子的下界很好地对应了起来。</p><p><strong>高斯启发函数(Gaussian Heuristic)</strong>:$GH(\mathcal{L})= \sqrt{\frac{n}{2\pi e}}\mathrm{det}(\mathcal{L})^{1/n}$</p><p><strong>上述GH函数只能用于估计高维格的</strong><script type="math/tex">\lambda_1\left(\mathcal{L}\right)</script>,<strong>在低维格中有另一个公式</strong>。然而低维格一般只在公钥密码分析中用的比较多,并且很多公钥密码分析中采用的是Minkowski’s bound作为假设。因此这里不给出(<del>其实就是不想起敲公式了</del>) ,具体可以看An Introduction to Mathematical Cryptography的相关小节。</p><p>我们往往不知道某个高维格的$\, \lambda_1\left(\mathcal{L}\right)\,$到底是多少,因此我们用$GH(\mathcal{L})$作为参考。<strong>在[<a href="https://latticechallenge.org/svp-challenge/index.php#">SVP Challenge (latticechallenge.org)</a>]中,若格基中最短向量的范数小于$1.05GH(\mathcal{L})$,就视为成功求解了SVP</strong>。</p><p> <br>如果以上内容还有疑问,可以看看 <em>An Introduction to Mathematical Cryptography</em> 这本书的相关章节,也可以看看这个视频:<a href="https://www.bilibili.com/video/BV1ux411f7US?p=18">数学潜水艇:初等数论、初等群论</a><br> </p><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><ol><li>蓝以中. 高等代数简明教程.下册, 2002. </li><li>王小云, 王明强, 孟宪萌. 公钥密码学的数学基础, 2013.</li><li>Hoffstein J , Pipher J C , Silverman J H . An Introduction to Mathematical Cryptography, 2014. </li><li><p>Galbraith S D . Mathematics of Public Key Cryptography: Lattices. 2012. </p></li><li><p><a href="https://zhuanlan.zhihu.com/p/161411204">Steven Yue的笔记</a></p></li><li><a href="https://coinc1dens.github.io/2020/02/27/%E6%A0%BC%E7%9B%B8%E5%85%B3-0.0.1.html">Coinc1dens’s blog</a></li></ol>]]></content>
<summary type="html"><p>本篇主要介绍学习格密码和格基规约算法必备的格论知识,以下内容为<strong>理解格基规约算法必备的数学基础</strong>。</p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="格论(几何数论)" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E8%AE%BA%EF%BC%88%E5%87%A0%E4%BD%95%E6%95%B0%E8%AE%BA%EF%BC%89/"/>
<category term="格密码" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E5%AF%86%E7%A0%81/"/>
</entry>
<entry>
<title>格基规约算法:算法详解</title>
<link href="https://su1yu4n.github.io/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/"/>
<id>https://su1yu4n.github.io/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E7%AE%97%E6%B3%95%E8%AF%A6%E8%A7%A3/</id>
<published>2021-06-20T03:10:01.000Z</published>
<updated>2024-11-23T07:40:12.684Z</updated>
<content type="html"><![CDATA[<p><strong>本文详细了介绍原始格基规约算法</strong>,并<strong>简单介绍目前对算法的改进</strong>。这些改进算法非常实用,被广泛应用于密码分析中。</p><p>阅读本篇前需要先了解格论,可以先看看<a href="/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/" title="格基规约算法:数学基础">格基规约算法:数学基础</a></p><span id="more"></span><p> </p><h1 id="原始格基规约算法"><a href="#原始格基规约算法" class="headerlink" title="原始格基规约算法"></a>原始格基规约算法</h1><h2 id="高斯算法"><a href="#高斯算法" class="headerlink" title="高斯算法"></a>高斯算法</h2><p>在18到19世纪间,拉格朗日和高斯先后提出了<strong>一种二维格基规约算法</strong>,现今称为高斯算法。下面介绍<strong>原始的高斯算法</strong>。</p><h3 id="算法描述"><a href="#算法描述" class="headerlink" title="算法描述"></a>算法描述</h3><p><em>以下内容基本来自 Lattice Basis Reduction: An Introduction to the LLL Algorithm and its Application .</em></p><p>首先先给出算法中出现的概念和符号。</p><ul><li><p><strong>最小基</strong>:设$\, \mathbf{x},\mathbf{y}\,$是二维格$\,\mathcal{L}\subset\mathbb{R}^2\,$的一组基。若$\, \mathbf{x},\mathbf{y}\,$满足$\,\left | \mathbf{x}\right | =\lambda_1\left(\mathcal{L}\right)\,$ 且$\, \mathbf{y}\,$是与$\, \mathbf{x}\,$线性无关的一个最短向量,则称$\, \mathbf{x},\mathbf{y}\,$是最小的(minimal)。最小基也被称为<strong>Minkowski约化基</strong>。</p></li><li><p>取整:记$\, \lceil\mu\rfloor\,$为距$\,\mu\,$最近的整数,即$\, \lceil\mu\rfloor=\left\lceil\mu-\frac{1}{2}\right\rceil\,$。我们规定对于整数$\,n\,$,$\lceil n+\frac{1}{2}\rfloor\,$的值为$\, n\,$ 。</p></li></ul><p>下面给出高斯算法的伪代码描述。</p><ul><li>输入:$\mathbb{R}^2$上的二维格$\mathcal{L}$的一组基 $\mathbf{x},\mathbf{y}$,其中$\left|\mathbf{x}\right|<\left|\mathbf{y}\right|$</li><li>输出:格$\,\mathcal{L}\,$的一组最小基$\,\mathbf{v}_1,\mathbf{v}_2$</li><li>算法步骤:<a href="Gauss_algo.png">高斯算法伪代码</a></li></ul><p>高斯算法中蕴含的思想与欧几里得算法类似,两者都是不断地实施<strong>先约化后交换</strong>的策略。在伪代码中,<strong>(2)(b)是约化步,(2)(c)(ii)是交换步</strong>。在约化步中会计算施密特正交化的系数,并且为了确保在格$\,\mathcal{L}\,$上运算,不能直接用施密特正交化系数,而是<strong>要将其取整后</strong>得到的$\,m\,$作为约化步中减去$\,\mathbf{v}_2\,$的系数。当$\, \left|\mathbf{v}_1\right|\le\left|\mathbf{v}_2\right|\,$时,算法结束并输出此时的${\, \mathbf{v}}_1\,$和${\ \mathbf{v}}_2\,$。可以证明算法输出的${\ \mathbf{v}}_1$和${\ \mathbf{v}}_2\,$是一组最小基,下面简述证明思路。</p><p>证明思路:首先,由取整的定义易知在算法的步骤(2)(b)执行后,有$\,\left|\mathbf{v}_2^\prime\cdot\mathbf{v}_1\right|\le\frac{1}{2}\left|\mathbf{v}_1\right|^2\,$,其中$\, \mathbf{v}_2^\prime\,$是步骤执行后所得新基的第二个向量。或者说,<strong>每次(2)(b)执行完毕后有 $\mu_{2,1} \le \frac{1}{2}$</strong>(此时称${\, \mathbf{v}}_1,{\ \mathbf{v}}_2\,$是 size-reduced的)。<strong>结合算法终止时$\, \left|\mathbf{v}_1\right|\le\left|\mathbf{v}_2\right|\,$这一条件即可证明</strong><script type="math/tex">\, \left|\mathbf{v}_1\right| = \lambda_{1}(\mathcal{L}) \,</script>。这一点从几何上非常直观,读者不妨考虑一下$\, \left|\mathbf{v}_1\right| = \left|\mathbf{v}_2\right|\,$时的情形。接下来再证$\,\mathbf{v}_2\,$是与$\,\mathbf{v}_1\,$线性无关的最短向量即可(证这一步有点繁琐)。</p><p>上述证明思路来源于二维空间上的几何直观,后面会看到在高维格中无法用类似的思路证明。在高维空间中,长度(2-范数)就没那么符合直觉了。由此也能侧面理解,为什么SVP问题在低维格中是容易的,在高维格中是困难的。</p><p>纵观高斯算法的流程,其实就是在不停地<strong>让两个向量互相约化,直到它们无法变得更短为止</strong>。因此,<strong>高斯算法可以视为一种贪心算法</strong>,且可以推广至高维(见后面的推广高斯算法)。</p><h3 id="算法实现"><a href="#算法实现" class="headerlink" title="算法实现"></a>算法实现</h3><p><strong>sagemath代码</strong>如下。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">Gauss</span>(<span class="params">x,y</span>):</span><br><span class="line"> <span class="comment"># step 1</span></span><br><span class="line"> v1 = x; v2 = y</span><br><span class="line"> finished = <span class="literal">False</span></span><br><span class="line"> <span class="comment"># step 2</span></span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">not</span> finished:</span><br><span class="line"> <span class="comment"># (a)</span></span><br><span class="line"> m = <span class="built_in">round</span>(( v2.dot_product(v1) / v1.dot_product(v1) ))</span><br><span class="line"> <span class="comment"># (b)</span></span><br><span class="line"> v2 = v2 - m*v1</span><br><span class="line"> <span class="comment"># (c)</span></span><br><span class="line"> <span class="keyword">if</span> v1.norm() <= v2.norm():</span><br><span class="line"> finished = <span class="literal">True</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> v1, v2 = v2, v1</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> v1, v2</span><br></pre></td></tr></table></figure><h3 id="算法效能"><a href="#算法效能" class="headerlink" title="算法效能"></a>算法效能</h3><p>高斯算法能够<strong>以平方级别的运行时间求解出一组Minkowski约化基(最小基)</strong>,具体如下。</p><ul><li>约化能力:设$\, \mathbf{x},\mathbf{y}\in\mathbb{R}^\mathbf{2}\,$是二维格$\,\mathcal{L}\,$的一组基,将$\mathbf{x},\mathbf{y}$作为高斯约化算法的输入,则算法一定能够在有限步内执行完成,且其输出的$\ \mathbf{v}_1,\mathbf{v}_2\,$是格$\,\mathcal{L}\,$的一组Minkowski约化基。</li><li>运行时间:输入二维格$\,\mathcal{L}\,$的任意一组基$\,\mathbf{u},\mathbf{v}\,$,假设$\, \left|\mathbf{u}\right|\le\left|\mathbf{v}\right|\,$,那么高斯算法会在$\, O\left(\log\left|\mathbf{v}\right|\cdot\left[1+\log\left|\mathbf{v}\right|-\log\lambda_1\left(\mathcal{L}\right)\right]\right)\,$的时间内运行完毕。</li></ul><h2 id="LLL算法"><a href="#LLL算法" class="headerlink" title="LLL算法"></a>LLL算法</h2><p>1982年诞生的LLL算法可视为高斯算法在高维格中的推广。接下来详细介绍原始LLL算法。</p><h3 id="算法描述-1"><a href="#算法描述-1" class="headerlink" title="算法描述"></a>算法描述</h3><p>设$\ \mathcal{L}\subset\mathbb{R}^m\,$是$\,n\,$维格,算法输入$\, \mathcal{L} \,$的任意一组基,并以多项式时间输出一组LLL约化基。首先介绍LLL约化基的概念。</p><p><strong>LLL约化基</strong>:设$\, \mathbf{b}_1,\ldots,\mathbf{b}_n \,$是$\, \mathcal{L}\,$的一组格基,若其满足以下两个性质:</p><ol><li><strong>(size-reduce)</strong>:对于任意的$\, j<i\le n\,$,有$\, \left|\mu_{i,j}\right| \le \frac{1}{2}\,$,其中$\,\mu_{i,j}=\frac{\left\langle\mathbf{b}_i,\mathbf{b}_j^\ast\right\rangle}{\left\langle\mathbf{b}_j^\ast,\mathbf{b}_j^\ast\right\rangle}\,$为施密特正交化中的系数。</li><li><strong>(Lovász condition)</strong>:对于任意的$\,\mathbf{b}_i,\ \mathbf{b}_{i+1}\,$有$\,\delta\left| \mathbf{b}_i^\ast \right|^2\le\left|\mathbf{b}_{i+1}^\ast+\mu_{i+1,i}\mathbf{b}_i^\ast \right|^2\,$.</li></ol><p>则称$\, \mathbf{b}_1,\ldots,\mathbf{b}_n \,$是$\, \mathcal{L}\,$的一组<strong><script type="math/tex">\delta-</script>LLL约化基</strong>。</p><p>性质2中的不等式$\,\delta\left| \mathbf{b}_i^\ast \right|^2\le\left|\mathbf{b}_{i+1}^\ast+\mu_{i+1,i}\mathbf{b}_i^\ast \right|^2\,$可以等价替换为$\, \left| \mathbf{b}_{i+1}^\ast \right|^2 \ge \left(\delta - \mu^{2}_{i+1,i} \right)\left| \mathbf{b}_{i}^\ast \right|^2 \ge \left(\delta - \frac{1}{4} \right)\left| \mathbf{b}_{i}^\ast \right|^2 \,$。性质1表明,LLL约化基中的向量是<strong>相对较短且近似正交</strong>的。性质2是为了根据范数对基中向量进行大致的排序。 </p><p>下面给出LLL算法的伪代码:</p><p><a href="LLL_algo.png">原始LLL算法伪代码</a></p><h3 id="简易实现"><a href="#简易实现" class="headerlink" title="简易实现"></a>简易实现</h3><p><strong>sagemath</strong>代码如下,参考 <a href="https://kel.bz/post/lll/">https://kel.bz/post/lll/</a></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">max</span>(<span class="params">a, b</span>):</span><br><span class="line"> <span class="keyword">return</span> a <span class="keyword">if</span> a > b <span class="keyword">else</span> b</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">LLL_v0</span>(<span class="params">M, delta=<span class="number">0.75</span></span>):</span><br><span class="line"> B = deepcopy(M)</span><br><span class="line"> Q, mu = B.gram_schmidt()</span><br><span class="line"> n, k = B.nrows(), <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">while</span> k < n:</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># size reduction step</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">reversed</span>(<span class="built_in">range</span>(k)):</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">abs</span>( mu[k][j] ) > <span class="number">0.5</span>:</span><br><span class="line"> B[k] = B[k] - <span class="built_in">round</span>( mu[k][j] ) * B[j]</span><br><span class="line"> Q, mu = B.gram_schmidt()</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># swap step </span></span><br><span class="line"> <span class="keyword">if</span> Q[k].dot_product(Q[k]) >= (delta - mu[k][k-<span class="number">1</span>]^<span class="number">2</span>) * Q[k-<span class="number">1</span>].dot_product(Q[k-<span class="number">1</span>]):</span><br><span class="line"> k = k + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> B[k], B[k-<span class="number">1</span>] = B[k-<span class="number">1</span>], B[k]</span><br><span class="line"> Q, mu = B.gram_schmidt()</span><br><span class="line"> k = <span class="built_in">max</span>(k-<span class="number">1</span>,<span class="number">1</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> B </span><br></pre></td></tr></table></figure><h3 id="常规实现"><a href="#常规实现" class="headerlink" title="常规实现"></a>常规实现</h3><p>在进行一次交换步或约化步之后,实际上只需要修改mu(施密特正交化系数)和Q(正交向量组)的个别值。而简易实现中,每次都会重新计算整个施密特正交化,这样的实现是低效的。</p><p>参考的伪代码不贴了,来源于 Lattice Basis Reduction - An Introduction to the LLL Algorithm and its Applications P.63 </p><p><strong>sagemath</strong>代码如下:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">LLL_v1</span>(<span class="params">M, delta=<span class="number">0.75</span></span>):</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> delta < <span class="number">0.25</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"delta should be greater than 0.25. Choose delta = 0.75 now."</span>)</span><br><span class="line"> alpha = delta <span class="keyword">if</span> <span class="number">0.25</span> < delta < <span class="number">1</span> <span class="keyword">else</span> <span class="number">0.75</span></span><br><span class="line"> </span><br><span class="line"> x = M</span><br><span class="line"> n = M.nrows()</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">reduce</span>(<span class="params">k, l</span>):</span><br><span class="line"> do_reduce = <span class="literal">False</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">abs</span>(mu[k,l]) > <span class="number">0.5</span>:</span><br><span class="line"> do_reduce = <span class="literal">True</span></span><br><span class="line"> </span><br><span class="line"> y[k] = y[k] - mu[k,l].<span class="built_in">round</span>() * y[l]</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(l):</span><br><span class="line"> mu[k,j] -= mu[k,l].<span class="built_in">round</span>() * mu[l,j]</span><br><span class="line"> mu[k,l] = mu[k,l] - mu[k,l].<span class="built_in">round</span>() </span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">exchange</span>(<span class="params">k</span>):</span><br><span class="line"> </span><br><span class="line"> y[k-<span class="number">1</span>], y[k] = y[k], y[k-<span class="number">1</span>]</span><br><span class="line"> NU = mu[k,k-<span class="number">1</span>]</span><br><span class="line"> delta = gamma[k] + NU ^ <span class="number">2</span> * gamma[k-<span class="number">1</span>]</span><br><span class="line"> mu[k,k-<span class="number">1</span>] = NU * gamma[k-<span class="number">1</span>] / delta <span class="comment"># all above is right</span></span><br><span class="line"> gamma[k] = gamma[k] * gamma[k-<span class="number">1</span>] / delta</span><br><span class="line"> gamma[k-<span class="number">1</span>] = delta</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(k-<span class="number">1</span>):</span><br><span class="line"> mu[k-<span class="number">1</span>,j], mu[k,j] = mu[k,j], mu[k-<span class="number">1</span>,j]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(k+<span class="number">1</span>, n):</span><br><span class="line"> xi = mu[i,k]</span><br><span class="line"> mu[i,k] = mu[i,k-<span class="number">1</span>] - NU * mu[i,k]</span><br><span class="line"> mu[i,k-<span class="number">1</span>] = mu[k,k-<span class="number">1</span>] * mu[i,k] + xi </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># step (1) </span></span><br><span class="line"> y = deepcopy(x)</span><br><span class="line"> <span class="comment"># step (2) </span></span><br><span class="line"> y_star, mu = y.gram_schmidt()</span><br><span class="line"> gamma = [y_star[i].norm() ^ <span class="number">2</span> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(n)]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># step (3)</span></span><br><span class="line"> k = <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># step (4)</span></span><br><span class="line"> <span class="keyword">while</span> k < n: </span><br><span class="line"> <span class="comment"># step (4)(a) </span></span><br><span class="line"> reduce(k, k-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># step (4)(b)</span></span><br><span class="line"> <span class="keyword">if</span> gamma[k] >= (alpha - mu[k,k-<span class="number">1</span>]^<span class="number">2</span>) * gamma[k-<span class="number">1</span>]:</span><br><span class="line"> <span class="comment"># (i)</span></span><br><span class="line"> <span class="keyword">for</span> l <span class="keyword">in</span> <span class="built_in">reversed</span>(<span class="built_in">range</span>(k-<span class="number">1</span>)):</span><br><span class="line"> reduce(k, l)</span><br><span class="line"> <span class="comment"># (ii)</span></span><br><span class="line"> k = k + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="comment"># (iii)</span></span><br><span class="line"> exchange(k)</span><br><span class="line"> <span class="comment"># (iv)</span></span><br><span class="line"> <span class="keyword">if</span> k > <span class="number">1</span>:</span><br><span class="line"> k = k-<span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> y</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><em>注:这两个版本的算法输出会有所不同,但这并不是因为代码写的有错误。两个算法求出的结果都是一组LLL-约化基。</em></p><h3 id="理论效能"><a href="#理论效能" class="headerlink" title="理论效能"></a>理论效能</h3><p>在密码分析的使用中,一般会选取$\,\delta=0.99\,$或其他合适的值。我们最关心LLL求解SVP的能力,下面给出$\, \delta\,$取任意值时所得$\, \mathbf{b}_1\,$范数的上界。</p><p><strong>约化能力</strong>:设$\, \mathbf{b}_1,\ldots,\mathbf{b}_n\,$是$\, n\,$维格$\, \mathcal{L}\,$的一组$\ \delta\,$- LLL约化基,则$\ \left| \mathbf{b}_1\right| \le\left(\frac{2}{\sqrt{4\delta-1}}\right)^{n-1}\lambda_1(\mathcal{L})\,$。</p><p>由定理可知,在LLL中$\, \delta\,$的选取会显著影响输出基的质量,$\, \delta\,$越大则基的范数越小。但算法中$\, \delta<1\ ,$,因此常见的选取为$\, \delta=0.99\,$。根据定理3.2.2,此时$\, \left|\mathbf{b}_1\right|<\left(1.35136\right)^\frac{n-1}{2}\lambda_1(\mathcal{L})\,$。</p><p>实际上,<strong>LLL算法输出基的质量在实践中一般优于上述定理给出的上界,以此估算LLL的实际表现是悲观的</strong>。与此相似,<strong>下面给出的时间复杂度上界也是一个悲观估计</strong>。</p><p><strong>时间复杂度</strong>:设$\, \mathcal{L}\subset\mathbb{R}^m\,$为$\, n\,$维格,LLL算法输入基为$\, \mathbf{b}_1,\ldots,\mathbf{b}_n\,$,则LLL算法会在$\ O\left(n^6\ln^3\!{B}\right)\,$的时间内运行完毕。其中$\ \forall1\le i\le n\ ,\ \left|\mathbf{b}_i\right|<B\ .$</p><p>LLL算法的理论效能总结如下:算法能够在$\ O\left(n^6\ln^3{B}\right)\,$的时间内,输出质量较高的约化基。当算法中的参数选取为$\, \delta=0.99\,$时,输出基中第一个向量的欧氏范数满足$\, \left|\mathbf{b}_1\right|<\left(1.352\right)^\frac{n-1}{2}\lambda_1(\mathcal{L})\,$。再次强调,<strong>这些结论仅仅是算法性能的下限</strong>,直接用这些值来预测算法性能过于悲观。后面还会看到,改进LLL算法的时间复杂度明显优于这个上界。</p><h2 id="BKZ算法"><a href="#BKZ算法" class="headerlink" title="BKZ算法"></a>BKZ算法</h2><p>1994年,Schnorr等人提出了BKZ算法。该算法<strong>比LLL算法的约化能力更强</strong>,可视为LLL算法的一种改进,其中使用了KZ约化(Korkin-Zolotarev reduction)和深插法(deep insertion)。下面介绍原始BKZ算法,而目前使用的BKZ 2.0在后面介绍。</p><h3 id="算法描述-2"><a href="#算法描述-2" class="headerlink" title="算法描述"></a>算法描述</h3><p><strong>KZ约化</strong>:KZ约化基是一组size-reduced,且<strong>其正交化后的向量范数为逐次最小长度的格基</strong>(特别地,基中第一个向量的长度即为$\,\lambda_1\,$)。计算高维格的KZ约化基是不切实际的,因为这需要要在输入格的投影子格上对SVP求解算法进行迭代式调用,其时间复杂度一般为超指数级。</p><p>为了<strong>以合理的时间代价得到比LLL约化基质量更好的基</strong>,Schnorr等人提出让格基的<strong>每个分块为KZ约化基</strong>即可。并且在原始BKZ中,分块的大小一般只会选取为10~30左右。下面给出BKZ约化基的概念。</p><p><strong>BKZ约化</strong>:若$\, {\mathbf{b}}_1,\ldots,\mathbf{b}_n\,$为格$\,\mathcal{L}\,$的LLL约化基,且对于任意的$\,i\,$,有</p><p><script type="math/tex">undefined</script>,</p><p>则称${\ \mathbf{b}}_1,\ldots,\mathbf{b}_n\,$为格$\,\mathcal{L}\,$的一组$\,\beta-$BKZ约化基,称其中的$\, \beta\,$为BKZ的分块大小。<br> 在BKZ算法中,<strong>只需在分块投影子格$\, \mathcal{L}([\pi_i(\mathbf{b}_i),\pi_i(\mathbf{b}_{i+1}),\ldots,\pi_i(\mathbf{b}_{min\left(i+\beta-1,n\right)})]) \,$上求解SVP</strong>,这要比KZ约化容易得多。BKZ中这个求解SVP的子算法称为<strong>SVP oracle,一般使用格枚举(lattice enumeration)实现</strong>。</p><p><strong>原始的BKZ</strong>使用<strong>精确格枚举算法</strong>,这个算法一定能够在输入投影子格上求解出SVP,但它的时间开销很大。实用的BKZ使用的是<strong>剪枝枚举算法</strong>,这种算法只能以一定的概率求解SVP,但它的时间开销比前者小很多。</p><p><em>枚举算法可视为对枚举树的DFS,剪枝枚举则是剪枝DFS。</em></p><p><strong>原始BKZ伪代码</strong>如下。<br> <strong>输入</strong>:格$\,\mathcal{L}\,$的基$\ B={(\mathbf{b}}_1,\ldots,\mathbf{b}_n)\,$,分块大小$\, \beta\in\left\{2,\ldots,n\right\}\,$,施密特系数矩阵$\, \mu\,$和${\, \left|\mathbf{b}_1^\ast\right|}^2,\ldots,\left|\mathbf{b}_n^\ast\right|^2 \,$<br> <strong>输出</strong>:$\,\beta-$BKZ约化基$\, {(\mathbf{b}}_1,\ldots,\mathbf{b}_n)\,$</p><p><strong>算法步骤</strong>:</p><p><a href="BKZ_algo.png">原始BKZ算法伪代码</a></p><p>BKZ算法的<strong>大致流程</strong>如下:</p><p>先对输入基进行LLL作为预处理,之后对当前分块进行格枚举求解SVP。若枚举算法得到的最短向量不是当前分块的第一个向量,就将最短向量插入到分块前,重新对整个基进行LLL约化。直到对所有分块都操作完毕。这样得到的输出基通常会优于LLL约化基。分块大致可以视为一种滑动窗口,第一个分块是$(\mathbf{b}_1,\ldots,\mathbf{b}_{\beta})$,第二个分块是$(\mathbf{b}_2,\ldots,\mathbf{b}_{\beta + 1})$…总之每次窗口向右移动一个向量。注意最后的$\,\beta-2\,$个分块长度是小于$\,\beta \,$的。</p><p><strong>为什么每次插入后要进行LLL呢</strong>?这主要是因为插入的子格最短向量与该子格的基线性相关,因此插入后当前的向量组就不是一组基了。而<strong>LLL能够消去线性相关性</strong>,同时进行一步约化。</p><h3 id="理论效能-1"><a href="#理论效能-1" class="headerlink" title="理论效能"></a>理论效能</h3><p>Hanrot等人运用动力系统分析出<strong>BKZ的约化能力下界</strong>为$\, \left|\mathbf{b}_1\right|\le\beta^{\frac{n-1}{2\left(\beta-1\right)}+\frac{3}{2}} \det(B)^\frac{1}{n}\,$。另一方面,当$\, \beta\,$设置为输入格维度$\, n\,$时,由BKZ约化基的定义可知$\, \left|\mathbf{b}_1\right|=\left|\mathbf{b}_1^\ast\right|=\lambda_1\left(\mathcal{L}\right)\,$。此时若BKZ算法能够终止,则其能够成功地求解$\, \mathcal{L}\,$上的SVP问题。<br> 尽管<strong>在实践中BKZ算法较为有效,但它至今仍没有被证明是多项式时间的算法</strong>。2008年,Gama和Nyugen在文指出当时BKZ时间复杂度的理论上界为$\,O\left(n\beta\right)^n\,$,关于维度$\, n\,$为超指数级(当然这也是<strong>悲观上界</strong>)。他们对BKZ进行了大量的实验。实验结果表明<strong>原始BKZ运行时间关于维度$\, n\,$似乎是指数级而不是多项式级</strong>。BKZ 2.0论文中指出,<strong>原始BKZ算法中$\,\beta=20\,$较为实用,但$\,\beta\geq25\,$时运行时间会显著增加</strong>。输入高维格时,选取分块大小为$\, \beta\geq40\,$会使BKZ运行得非常慢,甚至可能跑不出结果。</p><h2 id="总结与启发"><a href="#总结与启发" class="headerlink" title="总结与启发"></a>总结与启发</h2><p>前面总结了原始格基规约算法,其中<strong>高斯算法在理论上被研究的很透彻,而LLL和BKZ的理论效能分析结论并不实用,只是算法的下限</strong>。</p><p>目前使用的改进LLL算法与改进BKZ算法已经比原始算法的效能好很多,因此<strong>在实战中不使用两种原始算法。</strong>但即便如此原始算法仍然是值得回顾的,很容易受到如下<strong>启发</strong>:</p><ol><li><strong>理解各算法的优化方向</strong>。对于LLL算法,其改进版的优化主要集中在于大数运算的优化(包括大数算法的改进和浮点数的正确使用),以及使用深插法(deep insertion)提升算法的约化能力;对于BKZ算法,其改进版的优化会集中在SVP oracle(枚举)的调用次数和SVP oracle算法本身的改进,减少运行时间从而能使用更大的$\,\beta\,$。</li><li><strong>算法效能很难用理论进行分析</strong>。事实上,大多数使用的<strong>改进后的算法在理论分析上也很困难,结论也不太理想</strong>,并且经典的分析方法不再适用。目前比较有效的理论分析一般是利用启发公式的方法进行启发式估计,设计模拟算法进行实验来得到启发式时间复杂度,许多分析还使用离散动力系统理论作为数学工具。</li><li><strong>在大多数场景下BKZ往往比LLL更实用,因为BKZ约化能力更强</strong>。回顾时,我们发现原始BKZ在大多数场景更加实用。只有对求解速度有较大要求或需要在高维格中循环调用算法时才会调用LLL,其他情况下BKZ才是更好的选择。</li></ol><h1 id="改进格基约化算法"><a href="#改进格基约化算法" class="headerlink" title="改进格基约化算法"></a>改进格基约化算法</h1><p>目前,sagemath中的格基规约算法默认采用fpLLL的实现。在fpLLL中默认的LLL算法依照<a href="https://www.iacr.org/archive/eurocrypt2005/34940217/34940217.pdf"> $\mathrm{L}^2$算法</a>实现,并结合<a href="https://perso.ens-lyon.fr/damien.stehle/downloads/HLLL.pdf">H-LLL</a>;默认的BKZ算法主要依照<a href="https://www.iacr.org/archive/asiacrypt2011/70730001/70730001.pdf">BKZ 2.0</a>实现。对于LLL和BKZ,下面仅简单总结了$\, \mathrm{L}^2\,$算法和BKZ 2.0算法。</p><h2 id="mathrm-L-2-算法"><a href="#mathrm-L-2-算法" class="headerlink" title="\mathrm{L}^{2}算法"></a><script type="math/tex">\mathrm{L}^{2}</script>算法</h2><p>该算法为一种浮点型LLL算法,其中采用了浮点数和大数运算算法来优化运行时间,并使用deep insertion来提升算法的约化能力。即便不使用大数运算优化,$\, \mathrm{L}^2$算法的理论时间复杂度也为$\, O\!\left(d^4(d+\log B)\,m \log B\right)\,$,远优于原始LLL。($\,d\,$是格的维度,$\,B\,$是输入基中最长向量的范数,$\,\mathcal{L} \subset \mathbb{R}^{m}$)</p><h2 id="BKZ-2-0"><a href="#BKZ-2-0" class="headerlink" title="BKZ 2.0"></a>BKZ 2.0</h2><p>该算法为目前sagemath默认调用的BKZ算法,对原始BKZ算法进行了四个优化:</p><ol><li><p>将极限剪枝枚举算法(extreme pruning)和一种高概率线性剪枝算法(linear pruning)这两种算法搭配起来,作为BKZ 2.0的SVP oracle(论文中称为sound pruning)。这比最早提出的Schnorr-Euchner剪枝枚举算法还要快很多 。</p><p> <em>一次极限剪枝算法的成功概率虽低,但是速度非常快,以至于我们可以通过多次地调用它(例如一百次…),达到一个与其他算法相同的成功概率,速度却能快很多倍。</em></p></li><li><p>以大量实验结果为依据,使用Gaussian Heuristic启发式对剪枝枚举半径的值进行初始化。具体来说,枚举半径的初始值是1.05GH与输入格基的第一个向量范数中最小的那个。</p></li><li>使用早期中止技术,合理设置oracle的调用次数(多项式级别)。</li><li>对局部基进行预处理。</li></ol><p>BKZ 2.0的这些优化手段旨在<strong>降低BKZ的SVP oracle调用次数以及SVP oracle自身的运行时间</strong>。这一系列的优化<strong>使得BKZ 2.0可以使用较大的</strong> $\, \beta\,$,从而使得其约化能力显著强于LLL。BKZ 2.0论文中指出,设定算法参数为$\,\beta \ge 90\,$,甚至$\,\beta = 110\,$都是可以的。</p><p><em>要想更深入的理解BKZ 2.0,就要学习一下格枚举算法。可以在某英文网站上看一下视频 Lattice-based cryptography II - Enumeration attacks 和 Random Sampling Revisited Lattice Enumeration with Discrete Pruning的前半部分。</em></p><p>BKZ 2.0论文是我的外文翻译,不过感觉这篇论文翻译难度较大,我的翻译还需完善一下。如果有人想看的话,可能会在2022年1月完善后放出。</p><h2 id="扩展阅读"><a href="#扩展阅读" class="headerlink" title="扩展阅读"></a>扩展阅读</h2><p>2004年<strong>高斯算法</strong>被Nguyen等人<strong>推广至高维</strong>,他们指出推广算法在4维格中输出基为欧氏范数为Minkowski约化基(最小基)。同时,在4维格中算法复杂度(就输入基中最长向量范数的比特长度$\,n\,$而言)至少是平方级,若使用快速大数运算方法,算法的时间复杂度有希望提升到$\,O\!\left(n\log{n}\right)\,$级别。论文:<a href="https://perso.ens-lyon.fr/damien.stehle/downloads/lowdim-final.pdf">Low-Dimensional Lattice Basis Reduction Revisited</a></p><p><strong>下面提及的算法在fpLLL中也有实现。</strong></p><p><strong>H-LLL</strong>以$\,\mathrm{L}^2$算法为基础,在计算施密特正交化(QR分解)时使用householder算法替换了 Cholesky算法从而加快了运行速度。(具体做法并没这么简单,为了防止精度损失导致结果与原来不同,整个算法被重组)。论文:<a href="https://perso.ens-lyon.fr/damien.stehle/downloads/HLLL.pdf">H-LLL: Using Householder Inside LLL</a></p><p>2008年,Gama和Nyugen提出了<strong>slide reduction</strong>。算法结构很漂亮,并且它的理论效能强于使用中止技术的BKZ。不过最初的slide reduction算法,其实际表现远不如BKZ 2.0算法。论文:Finding Short Lattice Vectors within Mordell’s Inequality</p><p>2016年, Micciancio和Walter获得了很大成果。他们提出一种在<strong>对偶格上枚举最短向量</strong>的方法,并且这种方法不需要计算对偶基。这使得他们能够在slide reduction使用很大的block size。改进后的slide reduction,其效能与BKZ 2.0几乎差不多。并且更重要的是,<strong>在block size的值适中时,其理论效能与实际效能几乎一致。这意味着无需进行实验就可以估计格基约化算法对格密码的冲击。</strong>此外,他们还<strong>提出一种SDBKZ</strong>(self dual BKZ,即自对偶BKZ),其实际效能与BKZ 2.0相差无几,但其理论效能很容易分析。总之,这篇论文对于想进一步了解格基规约算法的人来说<strong>非常值得阅读</strong>。论文:<a href="https://link.springer.com/chapter/10.1007/978-3-662-49890-3_31">Practical, Predictable Lattice Basis Reduction</a></p><p>此外也推荐这些博客,与上面的内容相关:</p><ul><li><p><a href="https://blog.simons.berkeley.edu/2020/04/lattice-blog-reduction-part-i-bkz/">Lattice Blog Reduction – Part I: BKZ | Calvin Café: The Simons Institute Blog</a></p></li><li><p><a href="https://blog.simons.berkeley.edu/2020/05/lattice-blog-reduction-part-ii-slide-reduction/">Lattice Blog Reduction – Part II: Slide Reduction | Calvin Café: The Simons Institute Blog</a></p></li><li><p><a href="https://blog.simons.berkeley.edu/2020/08/lattice-blog-reduction-part-iii-self-dual-bkz/">Lattice Blog Reduction – Part III: Self-Dual BKZ | Calvin Café: The Simons Institute Blog</a></p></li></ul><p><strong>目前最强的算法是基于G6K的BKZ</strong>(全称General Sieve Kernel,读作Jessica),可以在英文网站上查找相关的讲解视频。论文:<a href="https://eprint.iacr.org/2019/089">The General Sieve Kernel and New Records in Lattice Reduction</a></p><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><h2 id="文献"><a href="#文献" class="headerlink" title="文献"></a>文献</h2><p>为了保证阅读体验,我没有在正文标注引用。本人只是把这方面内容重新组织和总结了一下,又写了一点自己的理解。根据以下论文的名字不难找到本文内容的出处。</p><ol><li><p>Hoffstein J , Pipher J C , Silverman J H . An Introduction to Mathematical Cryptography. 2008.</p></li><li><p>Galbraith S D . Mathematics of Public Key Cryptography: Lattices. 2012.</p></li><li><p>Nguyen P Q , D Stehlé. Low-Dimensional Lattice Basis Reduction Revisited. 2009.</p></li><li><p>Lenstra A . Factoring polynomial with rational coefficients. 1982.</p></li><li><p>Bremner M R . Lattice Basis Reduction: An Introduction to the LLL Algorithm and Its Applications. 2011.</p></li><li><p>Schnorr C P, Euchner M. Lattice basis reduction: improved practical algorithms and solving subset sum problems. 1994.</p></li><li><p>Gama, Nicolas, et al. “Lattice Enumeration Using Extreme Pruning.” EUROCRYPT’10 Proceedings of the 29th Annual International Conference on Theory and Applications of Cryptographic Techniques, 2010, pp. 257–278.</p></li><li><p>Chen Y, Nguyen P Q. BKZ 2.0: Better lattice security estimates. 2011.</p></li><li><p>PQ Nguyen, D Stehlé. Floating-Point LLL Revisited. 2005.</p></li><li><p>郑永辉,刘永杰,栾鸾.格基约化算法及其在密码分析中的应用综述. 2020.</p></li><li><p>Regev L O , Kaplan S E . Lattices in Computer Science LLL Algorithm. 2013.</p></li><li><p>Cohen H . A Course in Computational Algebraic Number Theory. 2013.</p></li><li><p>Hanrot G, Pujol X, Stehlé. Analyzing blockwise lattice algorithms using dynamical systems. 2011.</p></li><li><p>Gama N, Nguyen P Q. Predicting lattice reduction. 2008.</p></li><li><p>Morel I, Stehlé D, Villard G. H-LLL: using householder inside LLL. 2009.</p></li></ol><h2 id="博客"><a href="#博客" class="headerlink" title="博客"></a>博客</h2><p><a href="https://kel.bz/post/lll/">Building Lattice Reduction (LLL) Intuition | kel.bz</a></p><p><a href="https://blog.simons.berkeley.edu/2020/04/lattice-blog-reduction-part-i-bkz/">Lattice Blog Reduction – Part I: BKZ | Calvin Café: The Simons Institute Blog</a></p><p><a href="https://blog.simons.berkeley.edu/2020/05/lattice-blog-reduction-part-ii-slide-reduction/">Lattice Blog Reduction – Part II: Slide Reduction | Calvin Café: The Simons Institute Blog</a></p><p><a href="https://blog.simons.berkeley.edu/2020/08/lattice-blog-reduction-part-iii-self-dual-bkz/">Lattice Blog Reduction – Part III: Self-Dual BKZ | Calvin Café: The Simons Institute Blog</a></p><p><a href="https://blog.simons.berkeley.edu/2020/08/lattice-blog-reduction-part-iii-self-dual-bkz/">Lattice Blog Reduction – Part III: Self-Dual BKZ | Calvin Café: The Simons Institute Blog</a></p><p><em>还有一些英文视频,因为一些你懂得的原因这里就不贴了。</em></p>]]></content>
<summary type="html"><p><strong>本文详细了介绍原始格基规约算法</strong>,并<strong>简单介绍目前对算法的改进</strong>。这些改进算法非常实用,被广泛应用于密码分析中。</p>
<p>阅读本篇前需要先了解格论,可以先看看<a href="/2021/06/20/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95%EF%BC%9A%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/" title="格基规约算法:数学基础">格基规约算法:数学基础</a></p></summary>
<category term="Cryptology" scheme="https://su1yu4n.github.io/categories/Cryptology/"/>
<category term="格论(几何数论)" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E8%AE%BA%EF%BC%88%E5%87%A0%E4%BD%95%E6%95%B0%E8%AE%BA%EF%BC%89/"/>
<category term="格基规约算法" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E5%9F%BA%E8%A7%84%E7%BA%A6%E7%AE%97%E6%B3%95/"/>
<category term="格密码学" scheme="https://su1yu4n.github.io/tags/%E6%A0%BC%E5%AF%86%E7%A0%81%E5%AD%A6/"/>
</entry>
<entry>
<title>记一次对家中网络的简单优化</title>
<link href="https://su1yu4n.github.io/2021/03/04/%E8%B0%83%E6%95%B4%E5%85%89%E7%8C%AB%E5%92%8C%E8%B7%AF%E7%94%B1%E5%99%A8%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F/"/>
<id>https://su1yu4n.github.io/2021/03/04/%E8%B0%83%E6%95%B4%E5%85%89%E7%8C%AB%E5%92%8C%E8%B7%AF%E7%94%B1%E5%99%A8%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F/</id>
<published>2021-03-04T13:00:05.000Z</published>
<updated>2024-11-23T07:41:08.246Z</updated>
<content type="html"><![CDATA[<p>最近实在忍不了家里的WiFi了,经常丢包和断线,游戏没法打,网也上着费劲,因此决定对WiFi进行优化。</p><span id="more"></span><p>家里的网络结构是光猫接上路由器的WAN口,平时手机电脑上网时连路由器,路由器连光猫。就是那种很常见的小型家庭网络。</p><h2 id="优化光猫"><a href="#优化光猫" class="headerlink" title="优化光猫"></a>优化光猫</h2><h3 id="关无线功能"><a href="#关无线功能" class="headerlink" title="关无线功能"></a>关无线功能</h3><p>仔细看光猫,发现开启了路由模式(无线工作指示灯亮着),也就是说光猫既要进行光电信号的转换、拨号还要发射无线信号。但是光猫这玩意性能很差,这也是为什么我们要花钱买路由器。因此<strong>我们要把光猫的无线关掉。</strong></p><p><em>网上说可以让光猫开启桥接模式,让路由器来拨号。但是联通的光猫设置起来好像比较麻烦,我也没找到设置选项。也有人说就让光猫拨号就行,一般情况下不用搞,而且改桥接还可能被运营商限速。所以这里就只关掉光猫的wifi功能,没调桥接,光猫的DHCP也没关。</em></p><ol><li>首先,我们先查看下光猫的IP地址</li></ol><p><img src="打开路由器页面查看光猫IP.png" alt="打开路由器页面查看光猫IP"></p><p>这大概就是光猫的ip地址了,我们再用tracert看一下</p><p><img src="Powershell中使用tracert命令.png" alt="Powershell中使用tracert命令"></p><p>第一跳肯定是我们的路由器,第二跳肯定是光猫,可见光猫确实是192.168.18.1这个IP地址了。</p><ol><li>进入光猫配置页面,关掉Wifi功能。这里光猫的密码通过扫光猫上贴的二维码得到,如果光猫上到处没有写的话就要问下运营商了。</li></ol><p>既然关DHCP费劲,调桥接模式更费劲,那光猫就没什么可优化的了。</p><h3 id="关闭防火墙"><a href="#关闭防火墙" class="headerlink" title="关闭防火墙"></a>关闭防火墙</h3><p>就光猫这性能,防火墙铁定是鸡肋,不会有什么用的。家里的路由器开防火墙就足够了。我们把光猫的防DoS,ipv6spi统统关掉,节省一些光猫的性能。</p><h2 id="优化路由器"><a href="#优化路由器" class="headerlink" title="优化路由器"></a>优化路由器</h2><h3 id="开启QoS"><a href="#开启QoS" class="headerlink" title="开启QoS"></a>开启QoS</h3><p>有时候可能是家里看视频占带宽太大,网很卡。看到路由器CPU和内存负载挺低,那开个QoS吧。下载速度自己应该知道,上传速度,自己测一下就完事了。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>想小优化一下,发现其实没太多可优化的。要想优化得细节一些又要花很多时间捣腾,先就这样吧。</p>]]></content>
<summary type="html"><p>最近实在忍不了家里的WiFi了,经常丢包和断线,游戏没法打,网也上着费劲,因此决定对WiFi进行优化。</p></summary>
<category term="Misc Tech" scheme="https://su1yu4n.github.io/categories/Misc-Tech/"/>
<category term="网络" scheme="https://su1yu4n.github.io/tags/%E7%BD%91%E7%BB%9C/"/>
</entry>
<entry>
<title>随缘的英语听力练习秘籍</title>
<link href="https://su1yu4n.github.io/2019/09/01/%E9%9A%8F%E7%BC%98%E7%9A%84%E8%8B%B1%E8%AF%AD%E5%90%AC%E5%8A%9B%E7%A7%98%E7%B1%8D/"/>
<id>https://su1yu4n.github.io/2019/09/01/%E9%9A%8F%E7%BC%98%E7%9A%84%E8%8B%B1%E8%AF%AD%E5%90%AC%E5%8A%9B%E7%A7%98%E7%B1%8D/</id>
<published>2019-09-01T09:30:00.000Z</published>
<updated>2022-03-14T07:36:18.000Z</updated>
<content type="html"><![CDATA[<p>这是一种可以让英语应试水平和英语能力同步提升的训练方法。经过一个月的训练,我的朋友在之前英语水平一般的情况下,四级听力得到200分,也顺利通过了六级。</p><span id="more"></span><h3 id="考试方法"><a href="#考试方法" class="headerlink" title="考试方法"></a>考试方法</h3><p>考试关键点:听到了选项要在纸上随时做标记,记录一些关键词</p><h3 id="训练方法:精听"><a href="#训练方法:精听" class="headerlink" title="训练方法:精听"></a>训练方法:精听</h3><p>以练习<strong>精听为主</strong>,临考前可以再做几套听力题。</p><p>精听:拿一篇自己听起来有点困难的文章/对话,逐句听写。</p><h4 id="具体流程"><a href="#具体流程" class="headerlink" title="具体流程"></a>具体流程</h4><p>一句话听数次,把自己听到的部分写在纸上,直到写下完整句子,或者连续听了两次都听不出来一个新词为止。之后纠正错误,补全没听懂的部分。如果这句话有没听懂的地方(尤其是连读),看着原句对照其发音再听,有能力可模仿其发音(连读)。</p><h4 id="听力选材建议"><a href="#听力选材建议" class="headerlink" title="听力选材建议"></a>听力选材建议</h4><p><strong>用来做精听的文章词汇量不要高于自己词汇量</strong>,至少有1000以上词汇量(初中水平)再做精听</p><ul><li>高考不及格的水平可以听新概念2前半本;</li><li>四级500分及以下 / 高考的水平 听新概念英语2后半本、VOA慢速等;</li><li>四级550 / 六级500分水平 尝试听新概念3的前半本、VOA;</li><li>四级580以上 / 六级540以上 听新概念3后半本、老托福文章、新托福对话、VOA…</li></ul><p><strong>如果有考试听力练习的原文,可以对听力材料做精听。</strong></p><h4 id="练习时长及效果"><a href="#练习时长及效果" class="headerlink" title="练习时长及效果"></a>练习时长及效果</h4><p>每周听3-4天,每天1次,至少15分钟并且至少80个词。</p><p>坚持一个月,四级听力150->190</p><p>坚持两个月150->210-220(词汇量不低于3000情况下)</p><p>每周天天听,坚持40天 150->210</p><p>基本上,听个7-10天就感觉有提升。</p>]]></content>
<summary type="html"><p>这是一种可以让英语应试水平和英语能力同步提升的训练方法。经过一个月的训练,我的朋友在之前英语水平一般的情况下,四级听力得到200分,也顺利通过了六级。</p></summary>
<category term="English" scheme="https://su1yu4n.github.io/categories/English/"/>
<category term="English listening" scheme="https://su1yu4n.github.io/tags/English-listening/"/>
</entry>
</feed>