Skip to content

Commit

Permalink
Added koga's opt
Browse files Browse the repository at this point in the history
  • Loading branch information
nindanaoto committed Aug 13, 2024
1 parent aa799ff commit e123bc7
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 113 deletions.
47 changes: 26 additions & 21 deletions seccamp/html/2024/2.TRLWEandSampleExtractIndex.html

Large diffs are not rendered by default.

85 changes: 46 additions & 39 deletions seccamp/html/2024/5.IdentityKeySwitching.html

Large diffs are not rendered by default.

87 changes: 72 additions & 15 deletions seccamp/html/2024/8.BFV.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h1 id="tfhe%E5%AE%9F%E8%A3%85%E5%85%A5%E9%96%80">TFHE実装入門</h1>
<h2 id="8bfv">8.BFV</h2>
<p>松岡 航太郎</p>
Expand Down Expand Up @@ -83,7 +83,7 @@ <h2 id="8bfv">8.BFV</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="bfv%E3%81%A8%E3%81%AF">BFVとは</h2>
<ul>
<li>Brakerski-Fan-Vercauteren の略
Expand Down Expand Up @@ -147,7 +147,7 @@ <h2 id="bfv%E3%81%A8%E3%81%AF">BFVとは</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="bfv%E3%81%AE%E6%A7%8B%E6%88%90">BFVの構成</h2>
<ul>
<li>実はBFVとTFHEの間にはほとんど差がない
Expand Down Expand Up @@ -211,7 +211,7 @@ <h2 id="bfv%E3%81%AE%E6%A7%8B%E6%88%90">BFVの構成</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="bfv%E3%81%AE%E4%B9%97%E7%AE%97">BFVの乗算</h2>
<ul>
<li>加算はTFHEと同じなので割愛</li>
Expand Down Expand Up @@ -267,7 +267,7 @@ <h2 id="bfv%E3%81%AE%E4%B9%97%E7%AE%97">BFVの乗算</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="relinearlization">Relinearlization</h2>
<ul>
<li>見ての通り出力の暗号文は次元が<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="1.131ex" height="1.554ex" role="img" focusable="false" viewBox="0 -665 500 687"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path></g></g></g></svg></mjx-container>になってしまう
Expand Down Expand Up @@ -330,7 +330,7 @@ <h2 id="relinearlization">Relinearlization</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="packing">Packing</h2>
<ul>
<li>Canonical Embeddingと呼ばれることもある
Expand Down Expand Up @@ -405,7 +405,7 @@ <h2 id="packing">Packing</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="slot2coeffcoeff2slot">Slot2Coeff/Coeff2Slot</h2>
<ul>
<li>Packingで値を詰めた場合の各値のことをSlotと呼ぶ
Expand Down Expand Up @@ -464,7 +464,7 @@ <h2 id="slot2coeffcoeff2slot">Slot2Coeff/Coeff2Slot</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="lifting">Lifting</h2>
<ul>
<li>Bootstrappingをするにはノイズを消去する必要がある
Expand All @@ -481,12 +481,11 @@ <h2 id="lifting">Lifting</h2>
</li>
</ul>
</li>
<li>最も単純なものは<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="5.286ex" height="1.946ex" role="img" focusable="false" viewBox="0 -666 2336.6 860"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z"></path></g><g data-mml-node="mo" transform="translate(780.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(1836.6,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g></g></g></svg></mjx-container>の場合
<li>最も単純なものは<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="7.424ex" height="1.946ex" role="img" focusable="false" viewBox="0 -666 3281.2 860"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z"></path></g><g data-mml-node="mo" transform="translate(780.8,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(1836.6,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g><g data-mml-node="mo" transform="translate(2336.6,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z"></path></g><g data-mml-node="mn" transform="translate(2781.2,0)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path></g></g></g></svg></mjx-container>の場合
<ul>
<li>べき乗し続けるだけ</li>
<li><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="1.138ex" height="1.439ex" role="img" focusable="false" viewBox="0 -442 503 636"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D45D" d="M23 287Q24 290 25 295T30 317T40 348T55 381T75 411T101 433T134 442Q209 442 230 378L240 387Q302 442 358 442Q423 442 460 395T497 281Q497 173 421 82T249 -10Q227 -10 210 -4Q199 1 187 11T168 28L161 36Q160 35 139 -51T118 -138Q118 -144 126 -145T163 -148H188Q194 -155 194 -157T191 -175Q188 -187 185 -190T172 -194Q170 -194 161 -194T127 -193T65 -192Q-5 -192 -24 -194H-32Q-39 -187 -39 -183Q-37 -156 -26 -148H-6Q28 -147 33 -136Q36 -130 94 103T155 350Q156 355 156 364Q156 405 131 405Q109 405 94 377T71 316T59 280Q57 278 43 278H29Q23 284 23 287ZM178 102Q200 26 252 26Q282 26 310 49T356 107Q374 141 392 215T411 325V331Q411 405 350 405Q339 405 328 402T306 393T286 380T269 365T254 350T243 336T235 326L232 322Q232 321 229 308T218 264T204 212Q178 106 178 102Z"></path></g></g></g></svg></mjx-container>乗して引くことを繰り返すだけ</li>
</ul>
</li>
<li>任意の場合では多項式補完により求めることができる</li>
</ul>
<footer><img src="../../image/ccbysa.png" alt="" /> <a href="https://creativecommons.org/licenses/by-sa/4.0/">licence</a></footer>
</section>
Expand Down Expand Up @@ -524,11 +523,26 @@ <h2 id="lifting">Lifting</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
<h2 id="hat-encoding">Hat Encoding</h2>
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="lifting%E3%81%AE%E7%96%91%E4%BC%BC%E3%82%B3%E3%83%BC%E3%83%89">Liftingの疑似コード</h2>
<ul>
<li><a href="https://eprint.iacr.org/2017/809">https://eprint.iacr.org/2017/809</a></li>
<li><a href="https://eprint.iacr.org/2014/873">Bootstrapping for HElib</a>のFigure 1より
<ul>
<li>jのLoopのところがLifting</li>
<li>これで最上位桁を取り出せる</li>
</ul>
</li>
</ul>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>Digit Extraction(z,e)
w₀,₀ ← z
For k ← 0 to e-1
y ← z
For j ← 0 to k
wⱼ,ₖ₊₁ ← (wⱼ,ₖ)ᵖ
y ← (y - wⱼ,ₖ₊₁)/p
wₖ₊₁,ₖ₊₁
return wₑ,ₑ
</code></pre>
<footer><img src="../../image/ccbysa.png" alt="" /> <a href="https://creativecommons.org/licenses/by-sa/4.0/">licence</a></footer>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-paginate="true" data-footer="![](../../image/ccbysa.png) [licence](https://creativecommons.org/licenses/by-sa/4.0/)" data-theme="default" data-style="h1, h2, h3, h4, h5, header, footer {
Expand Down Expand Up @@ -565,10 +579,53 @@ <h2 id="hat-encoding">Hat Encoding</h2>
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="10" data-size="16:9">
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="hat-encoding">Hat Encoding</h2>
<ul>
<li><a href="https://eprint.iacr.org/2017/809">https://eprint.iacr.org/2017/809</a></li>
</ul>
<footer><img src="../../image/ccbysa.png" alt="" /> <a href="https://creativecommons.org/licenses/by-sa/4.0/">licence</a></footer>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-paginate="true" data-footer="![](../../image/ccbysa.png) [licence](https://creativecommons.org/licenses/by-sa/4.0/)" data-theme="default" data-style="h1, h2, h3, h4, h5, header, footer {
color: white;
}
section {
background-color: #505050;
color:white
}
table{
color:black
}
code{
color:black
}
a {
font-weight:bold;
color:#F00;
}
" lang="ja-JP" data-marpit-pagination="11" style="--paginate:true;--footer:![](../../image/ccbysa.png) [licence](https://creativecommons.org/licenses/by-sa/4.0/);--theme:default;--style:h1, h2, h3, h4, h5, header, footer {
color: white;
}
section {
background-color: #505050;
color:white
}
table{
color:black
}
code{
color:black
}
a {
font-weight:bold;
color:#F00;
}
;" data-marpit-pagination-total="11" data-size="16:9">
<h2 id="%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE">参考文献</h2>
<ul>
<li><a href="https://math.berkeley.edu/~kmill/math55sp17/crt.pdf">The Chinese Remainder Theorem</a></li>
<li><a href="https://inferati.com/blog/fhe-schemes-bfv">Introduction to BFV</a></li>
<li><a href="https://eprint.iacr.org/2014/873">Bootstrapping for HElib</a></li>
</ul>
<footer><img src="../../image/ccbysa.png" alt="" /> <a href="https://creativecommons.org/licenses/by-sa/4.0/">licence</a></footer>
</section>
Expand Down
Binary file added seccamp/image/crypto-security-relation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions seccamp/markdown/2024/10.IND-CPAD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
marp: true
---
<!--
theme: default
size: 16:9
paginate: true
footer : ![](../../image/ccbysa.png) [licence](https://creativecommons.org/licenses/by-sa/4.0/)
style: |
h1, h2, h3, h4, h5, header, footer {
color: white;
}
section {
background-color: #505050;
color:white
}
table{
color:black
}
code{
color:black
}
a {
font-weight:bold;
color:#F00;
}
-->

<!-- page_number: true -->

# TFHE実装入門

## 10. IND-CPAᴰ

松岡 航太郎

---

## IND-CPAとは

- IND-CPAᴰを説明する前にベースとなるIND-CPAの説明をする必要がある
- INDはIndistinguishablity(識別不能性)の略
- CPAはChosen Plaintext Attack(選択平文攻撃)の略
- 攻撃者は任意の平文に対する暗号文をchallengerから得ることができるとする
- 好きなだけそのような暗号文を得た後に2つの平文候補をchallengerに送る
- challengerはそのどちらかをランダムに選んで暗号化して返す
- 攻撃者はどちらが暗号化されたかわかるか?
- 暗号文から部分的な情報を取り出せるかどうか(Semantic Security)をINDは含んでいる

---

## IND-CPA以外の一般的な安全性

-


---

## 安全性の関係

- NMはNon-Malleability(頑強性)の略
- 雑に言うと準同型性がないこと
- 定義から行って準同型暗号はこれを満たすことができない
- IND-CCA2は達成不能(多くの実用的暗号はこれを満たす)

![](../../image/crypto-security-relation.png)
[図の出典](https://tex2e.github.io/blog/crypto/pubkey-crypto-security-relation#fn:indistinguishability)
12 changes: 7 additions & 5 deletions seccamp/markdown/2024/2.TRLWEandSampleExtractIndex.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ style: |
## 多項式環

- $N∈\mathbb{Z}^+$とする
- TRLWEで使う多項式環はTorusを係数とする多項式を$X^N+1$で割った余りが成す剰余環である
- TRLWEで使う多項式環はTorus係数多項式を$X^N+1$で割った余りが成す剰余環
- この多項式環を$\mathbb{T}_N[X]$と表記する
- Torus同士の乗算は定義できないことから$\mathbb{T}_N[X]$の元同士の積も定義できない
- 整数とTorusの乗算は定義できるので、$\mathbb{Z}_N[X]$の元との積は定義できる
Expand All @@ -68,7 +68,7 @@ style: |
- FFT(高速フーリエ変換)かNTT(数論変換)を使って実装するのが知る限り最速
- ここではナイーブな実装を扱う(知る限り最適な実装は7章で扱う)
- 課題2.1で扱ったもの
- 2つの元を掛け算したあと、剰余を取って、係数の小数部に相当する部分を抜き出せば良い
- 2つの元を掛け算、剰余を取り、係数の小数部に相当する部分を抜き出せば良い
- 入力を$a[X]∈\mathbb{T}_N[X],b[X]∈\mathbb{Z}_N[X]$とする
- $a[X]=\sum_{i=0}^{N-1}a_iX^i,a_i∈\mathbb{T}$である

Expand All @@ -95,7 +95,7 @@ for i from 0 to N-1
- TRLWEの暗号文は$b[X]=\mathbf{a}[X]⋅ \mathbf{s}[X]+ m[X] +e[X]$として、$(\mathbf{a}[X],b[X])$という$N-1$次の多項式$k+1$要素のベクトルである
- $b[X]-\mathbf{a}[X]⋅\mathbf{s}[X]=m[X]+e[X]$になるので、この$e[X]$をどうにかして削除する方法を加えると$m[X]$がとれて復号できる
- $N,k,α_{bk}$を大きくすればするほど安全($α_{bk}$は大きくしすぎると暗号文が壊れる)
- 同じ安全性、同じデータならTLWEよりTRLWEの方がサイズが小さい(と信じられている)
- 同じ安全性・データならTLWEよりTRLWEはサイズが小さい(と信じられている)

---

Expand All @@ -106,7 +106,7 @@ for i from 0 to N-1
- その和を$(\mathbf{a}[X]_1+\mathbf{a}[X]_2,b[X]_1+b[X]_2)$とする
- $b_1[X]+b_2[X]-(a_1[X]+a_2[X])⋅s[X]=m_1[X]+m_2[X]+e_1[X]+e_2[X]$になり、$m_1[X]+m_2[X]$が出てくるので加法準同型になっている
- TLWEよりサイズが小さいのでより高速に加算ができることになる
- 計数ごとに独立した加算なのでSIMDライク
- 係数ごとに独立した加算なのでSIMDライク

---

Expand Down Expand Up @@ -174,8 +174,10 @@ SampleExtractIndex((𝐚[X],b[X]),x)

## TRLWEのパラメータについて

- $N=512,k=2,α_{bk}=0.0000000342338787018369$または$\eta=16$, 32bit固定小数点
- $N=512,k=2,α_{bk}=0.0000000342338787018369$, 32bit固定小数点
- C++20の_BitIntとか使うなら27bitくらいに削ってもよいはず
- CBDだと$\eta$が大きくなりすぎる(1024超え?)のでやめたほうが良い
- 32bitより小さい固定小数点にとれば$\eta$も小さくなるので使える
- 実はTRLWEの安全性を直接推定する方法は知られていない
- TRLWEに入っている環の構造を利用した攻撃が知られていないため
- 安全性の推定はTLWEに変換して行われている(十分条件による弱い推定)
Expand Down
1 change: 1 addition & 0 deletions seccamp/markdown/2024/3.TRGSWandCMUX.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ $$
- このアイデアをナイーブに実装した場合の疑似コードを示そう
- やっていることはほぼ繰り上がり計算なので加算機にそれを任せる最適化が可能だが複雑になりすぎるのでここでは説明しない
- Torusは32bit固定小数点表現されていることを仮定している
- 式に合わせるために分けているがâを更新して返してもよい

```
Decomposition(a[X])
Expand Down
Loading

0 comments on commit e123bc7

Please sign in to comment.