本文翻譯於 CKKS EXPLAINED, PART 5: RESCALING,主要介紹CKKS方案中最重要的技術- rescaling,重縮放技術
介紹
在CKKS的前一篇文章 CKKS Part4: CKKS的乘法和重線性化 中,我們瞭解了密文乘法在CKKS中的工作原理,為什麼需要重新線性化輸出以及保持恆定的密文大小,以及如何做到這一點。
儘管如此,正如我們將看到的,我們需要一個名為“重縮放”的最終操作來管理噪音並避免溢位。這將是本系列的最後一篇理論性文章,在下一篇也是最後一篇文章中,我們將用Python實現所有內容!
為了瞭解它是如何工作的,我們首先要有一個整體圖,然後再詳細瞭解它是如何工作的。
模數鏈的高階檢視
到目前為止,我們已經深入挖掘了CKKS的細節,但對於這一點,我們將後退一步。CKKS使用我們所說的level,級數,也就是說,在噪聲太大而無法正確解密輸出之前,所允許的有限乘法次數。
你可以想象這是一個油箱。最初,油箱充滿了汽油,但當你執行越來越多的操作時,汽油將被排空,直到沒有剩餘的汽油,就不能再做任何事情。同樣的道理也適用於同態加密方案:你先從一定量的汽油開始,但當你進行乘法時,汽油越來越少,直到用完為止,你不能再執行任何操作。
下圖說明了這一點。當你開始的時候,你的初始油箱已經滿了。但當你們執行乘法和重縮放時,你們會降低階數,這相當於消耗了你們的一些汽油。如果你從L層開始,表示為\(q_L,q_{L−1},…,q_1\),處於級別\(q_l\)意味著還剩下\(l\)個乘法,執行一個乘法會將級別從\(q_l\)降低到\(q_{l−1}\).
現在,一旦你的汽油用完了,就像在現實生活中一樣,你可以把油箱加滿,這樣你就可以在路上走得更遠。此操作稱為bootstrap,引導,本文將不介紹它。因此,如果我們假設我們不可能重新加註油箱,那麼在使用有限級同態加密方案時,必須考慮一個有趣的方面:您需要提前知道將要進行的乘法數量!
事實上,就像在現實生活中一樣,如果你打算走很遠的路,你將需要比你只是在附近走走更多的汽油。同樣的道理也適用於這裡,根據需要執行的乘法次數,您必須調整油箱的大小。但是油箱越大,計算就越繁重,你的引數也就越不安全。事實上,就像在現實生活中一樣,如果你需要一個更大的油箱,它會更重,這會使事情變得更慢,同時也會降低安全性。
我們不會詳細討論所有細節,但知道CKKS方案的難度取決於比率\(N/q\),N是多項式的階數,也就是向量的的大小;q是多項式係數模數,即我們的油箱大小。
因此,我們需要的乘法越多,油箱就越大,我們的引數就越不安全。為了保持相同的安全強度,我們需要增加N,這將增加我們操作的計算成本。(不是增加q麼?)
下面的圖,從 Microsoft Private AI Bootcamp 中,展示了在使用CKKS時必須考慮的折衷,顯示了多項式次數和模數的安全性之間的關係。為了保證128位的安全性,我們必須增加多項式次數,即使我們不需要它提供的“額外插槽”【是明文槽麼?】,因為增加模數可能會使我們的引數不安全。
因此,在我們進入更理論的部分之前,讓我們看看關鍵的收穫是什麼:
1、重縮放和噪音管理可以被視為管理一個油箱,你從一個初始預算(油量)開始,使用(做乘法)後預算(油量)將會減少,如果汽油用完了,你就什麼都做不了。
2、你需要提前知道你將進行多少次乘法,這將決定油箱的大小,這將影響你將使用的多項式次數的大小。
背景
現在,我們看到了整體圖,讓我們深入瞭解為什麼以及如何運作。
如果你正確地記得 CKKS Part2: CKKS的編碼和解碼 第二部分關於編碼的內容,如果我們有一個初始向量z,它在編碼過程中乘以一個縮放因子Δ,以保持一定的精度。
因此,包含在明文μ和密文c的基本值是\(Δ.Z\),所以當我們把兩個密文c和c'相乘時,最後的結果是\(z.z'.\Delta ^{2}\),所以它包含了縮放因子的平方,當縮放因子指數增長時,經過幾次乘法後可能會導致溢位。此外,正如我們之前看到的,每次乘法後噪聲都會增加。
因此,重縮放操作的目標實際上是保持縮放因子恆定,同時減少密文中存在的噪聲。
普通做法
那麼我們如何解決這個問題呢?要做到這一點,我們需要了解如何定義q。記住,這個引數q被用作多項式環\(R_{q}=Z_{q}\left[ X \right]/\left( X^{N}+1 \right)\)中係數的模數。
正如高階檢視中所述,q比作一個汽油箱的大小,我們將逐步進行計算,清空該汽油箱。
如果我們假設我們用一個縮放因子Δ,進行L次乘法,那麼我們將q定義為:\(q=\Delta ^{L}.q_{0}\),其中\(q_{0}\geq \Delta\),這將決定小數部分之前需要多少整數位。實際上,如果我們假設小數部分需要30位精度,整數部分需要10位精度,我們將設定:
一旦我們為整數和小數部分設定了我們想要的精度,選擇了我們想要執行的乘法的數量L,就能相應地求得q,接下來很容易定義重縮放操作,我們只需對密文進行分割和取整。
事實上,假設我們在一個給定的級數\(l\),那麼模是\(q_l\)。我們有密文\(c\in R_{q_{_{l}}}^{2}\),然後我們可以定義從\(l\)級到\(l-1\):
因為\(q_l=\Delta ^{l}.q_{0}\)
因此,通過這樣做,我們可以做到兩件事:
1、一旦我們解密了兩個密文c,c′的乘積,以及對應底層明文值\(\Delta .z,\Delta .z'\),應用重縮放後,我們有\(\Delta .z.z'\),因此,只要我們在每次乘法後重縮放,在整個計算過程中,縮放因子保持不變。
2、噪聲被減少了,因為我們既分割底層的明文值,也分割了解密時的噪聲,如果你記得清楚的話,它的形式是μ+e,(此時解密,再舍入得到的u不是原先的明文值)。因此,重縮放也可以達到降噪的目的。
所以,如果我們把所有的東西都放在一起,要在CKKS中進行乘法,你需要做三件事:
1、做乘法:\(c_{mult}=\mbox{C}_{Mult}\left( c,c' \right)=\left( d_{0},d_{1},d_{2} \right)\)
2、重線性化:\(c_{\mbox{re}lin}=\mbox{Re}lin\left( \left( d_{0},d_{1},d_{2} \right),evk \right)\)
3、重縮放:\(c_{rs}=R\mbox{S}_{l->l-1}\left( c \right)\)
如果你做好上面的工作,使用正確的金鑰就可解密成功!差不多了,下面還有最後一個細節我們要講。
CRT,中國剩餘定理
所以我們得到了我們需要的一切,但有一個技術問題:計算是在大數上完成的!事實上,我們已經知道,操作是在大模數\(q_l=\Delta ^{l}.q_{0}\)上完成的。例如,想象一下,小數部分需要30位精度,整數部分需要10位精度,乘法需要10位精度(即進行10次乘法),那麼我們有\(q_{L}=\Delta ^{L}.q_{0}=2^{30\cdot 10+40}=2^{340}\)。
因為我們有時會計算有大系數的多項式,比如均勻取樣得到的多項式,然而一些計算不適合常用的64位系統,所以我們必須找到一種方法使其工作。
這就是中國剩餘定理的由來!這個定理表明,如果我們有L個互素數\(p_{1},...,p_{L},p=\prod_{l=1}^{L}{p_{l}}\),然後對映:$$Z\ /pZ\ ->\ Z/ p_{1}Z\times \ ...\ \times Z/ p_{L}Z:\ x\left( \mbox{mod}\ p \right)\ ->\left( x\left( \mbox{mod}/ p_{1} \right),\ ...\ ,x\left( \mbox{mod}\ p_{L} \right) \right)$$,是一個環同構,即如果你想在大環\(Z\ /pZ\)上做算術運算,那麼你可以在小環\(Z\ /p_lZ\)上執行,這樣就不會在執行計算時超過64位的問題了。
所以在實際中有\(q_{L}=\Delta ^{L}.q_{0}\),我們選擇\(p_{1},...,p_{L}\),其中\(p_l約等於\Delta ,q_0\)是遠大於\(\Delta\)的素數,然後設定\(q_{L}=\prod_{l=1}^{L}{p_{l}.q_{0}}=q_0*p\)。
這樣,我們就可以使用CRT完成上面描述的小技巧,從而能夠執行大模數運算。必須稍微修改重縮放操作:\(R\mbox{S}_{l->l-1}\left( c \right)=\left\lfloor \frac{q_{l-1}}{q_{l}}.c \right\rfloor\left( \mbox{mod}\; q_{l-1} \right)=\left\lfloor p_{l}^{-1}.c \right\rfloor\left( \mbox{mod}\; q_{l-1} \right)\)
因此,我們在本文中看到了什麼是重縮放,為什麼需要它,以及如何在實踐中實現它。在下一篇也是最後一篇文章中,我們將把所有內容放在一起,用Python編寫一個類似CKKS的同態加密方案!