同態加密——如何讓幫你幹活的人不知道自己都幹了些什麼

同態加密——如何讓幫你幹活的人不知道自己都幹了些什麼

什麼是同態加密

隨著雲計算越來越發達,我們在雲伺服器上進行的計算越來越多。有時候我們需要把一些很私密的數據(比如需要實驗數據,個人信息等)上傳到雲伺服器上進行處理,這時候就存在數據被泄露的風險。

首先來考慮這麼兩個問題:

1. 如何運輸黃金而不被運輸的人把黃金偷走

2. 如何把黃金交給工匠進行加工,而且使得工匠也無法獲得任何黃金

假設我要運輸100g黃金,我只要把這100g黃金鎖在一個保險柜里運輸就可以了。但是如果我想要對這100g黃金進行加工,並且想要使加工黃金的工匠無法獲得黃金,單純的把黃金鎖在保險箱里就不可行了。這個問題的一個解決方法是:

1. 找一個帶手套的保險箱,把黃金鎖在裡面

2. 工匠可以通過保險柜上的手套操作黃金,這樣工匠即能對黃金進行處理又無法竊取黃金

3.打開保險箱,拿出裡面的黃金

圖片來自知乎回答https://www.zhihu.com/question/27645858/answer/37598506

和上面的例子相似,為了數據不被泄露,我們可以對數據進行加密。對使用普通加密方法加密得到的密文進行修改,修改後的密文在解密後一般都會變成毫無意義的亂碼。也就是說,我們無法操作加密後的數據。這種性質在一般的信息傳輸中是非常有用的,可以用來判斷信息是否被修改,但是想要對加密後的數據進行運算就非常困難了。為了解決這個問題,人們提出了一種叫做同態加密的加密方法。

什麼是同態加密呢? 同態加密就是一種能夠讓我們對加密後的內容進行運算,然後用密鑰對運算結果進行解密,解密得到的結果等於加密前的內容經過相同的運算之後的結果。比如把數字3加密之後得到密文A,數字5加密後得到密文B,2 	imes 密文A得到的密文解密後得到的結果為6, 密文A+密文B得到的密文解密的結果為8。有了同態加密後,我們就可以把加密後的數據上傳到雲伺服器上,在雲伺服器上進行運算,然後下載運算後的結果,對結果進行解密。這樣就得到了計算結果並且能夠保證數據不被泄露。因為數據是被加密的,所以把加密後的數據公布給所有人也不會發生數據泄露。這樣,我們就可以把計算任務通過區塊鏈眾包給普通用戶。

同態加密的例子

如果我們有一個加密函數 f , 把明文A變成密文A, 把明文B變成密文B,也就是說 f(A) = Af(B) = B 。另外我們還有一個解密函數 f^{-1} 能夠將 f 加密後的密文解密成加密前的明文。對於一般的加密函數,如果我們將A和B相加,得到C。我們用 f^{-1} 對C進行解密得到的結果一般是毫無意義的亂碼。但是,如果 f 是個可以進行同態加密的加密函數, 我們對C使用 f^{-1} 進行解密得到結果C, 這時候的C = A + B。如果滿足 f(A) + f(B) = f(A + B) , 我們將這種加密函數叫做加法同態,如果滿足 f(A) 	imes f(B) = f(A 	imes B) ,我們將這種加密函數叫做乘法同態。如果一個加密函數只滿足加法同態,我們就只能進行加減法運算;如只滿足乘法同態,那麼就只能進行乘除法運算。如果一個同態加密函數同時滿足加法同態和乘法同態,那麼這個使用這個加密函數完成各種加密後的運算(加減乘除、多項式求值、指數、對數、三角函數)。第一個滿足加法和乘法同態的同態加密方法直到2009年才由Craig Gentry提出。

同態加密之所以被稱為同態加密是因為這種加密方法跟抽象代數中的同態很像。在抽象代數中,如果 G和H 是兩個交換環,如果函數 f:G 	o H 使得:

  1. f(e_G) = e_H , 其中 e_G , e_H 分別是G和H中的幺元
  2. forall x,y in G, f(x 	imes y) = f(x) 	imes f(y)
  3. forall x,y in G, f(x + y) = f(x) + f(y)

均成立,那麼我們把 f 稱為一個同態(homomorphism)。一般的加密函數都是雙射的,雙射的同態又稱為同構(isomorphism)。所以這麼說來,同態加密被稱為同構加密更加貼切。

全同態加密(Fully Homomorphic Encryption)

2009年,Craig Gentry在論文Fully Homomorphic Encryption Using Ideal Lattices中第一次提出了一種能夠對所有的運算進行同態加密的方法,這也是第一種同時滿足加法同態和乘法同態的加密方法。這裡的全同態指的是給定任意一種運算,可以使用論文中的方法直接構造出對應的同態加密後的運算。使用這種方法甚至可以把需要執行的運算步驟進行加密,也就是說給定要計算的函數 h(x) 和參數 x_0 ,這種方法不僅可以加密參數 x_0 ,還可以加密 h(x) ,讓計算的執行者無法得知 h(x) 中都進行了那些計算。

但是這種方法有個致命的缺點,計算複雜度過高。經過這種方法加密後再進行運算需要的時間比直接進行計算需要的時間高兩個數量級。

Somewhat Homomorphic Encryption

與FHE不同,Somewhat Homomorphic Encryption只考慮在幾種常見的運算上進行同態加密,但是這幾種運算的速度都跟直接進行運算的速度在同一量級。只要一個同態加密演算法滿足加同態和乘同態,我們就可以使用泰勒展開式來計算各種函數的值。這種加密方法有很多,以下是幾種比較流行的方法:

  • Efficient Homomorphic Encryption on Integer Vectors and Its Applications
  • Yet Another Somewhat Homomorphic Encryption (YASHE)
  • Somewhat Practical Fully Homomorphic Encryption (FV)
  • Fully Homomorphic Encryption without Bootstrapping

其中目前最好的方法是YASHE或者FV.YASHE,但是這兩種方法過於複雜,本文介紹的是第一種加密方案,Efficient Integer Vector。這種方案在整數向量上進行操作,能夠高效的實現整數向量的數乘、加減、內積、線性變換等操作。

Efficient Integer Vector

首先定義一些符號:

  • S:代表你的密鑰的矩陣
  • c:加密後的整數向量,密文
  • x:加密前的整數向量,明文
  • w :權重,一個標量,我們用這個值來對輸入的向量進行權重調整,提高信噪比。但是這個值也不能設置的過大,否則可能出現溢出錯誤。
  • E/e:額外的隨機雜訊,我們在調整過權重後的明文上加上雜訊,使得兩個在數值上差距不大的向量經過加密後得到的密文也有較大的差距。

接下來我們來看如何加密和解密:

S in Z^{m 	imes n} , c in Z^n	ext{x} in Z^n	ext{e} in Z^n

S	ext{c} = w	ext{x} + 	ext{e} , x = lfloor frac{Sc}{w} 
ceil,其中  lfloor frac{Sc}{w} 
ceil 表示把  frac{Sc}{w} 四捨五入到最近的整數。

因為e相對於 w	ext{x} 比較小,我們經過舍人之後就消除e的影響。

Addition in Efficient Integer Vector

使用相同的密鑰 S 對整數向量 	ext{x}_1	ext{x}_2 進行加密得到密文 	ext{c}_1	ext{c}_2, 即:

c_1 = inv(S)(	ext{w}x_1 + 	ext{e})

c_2 = inv(S)(	ext{w}x_2 + 	ext{e})

如果我們想把 x_1x_2 相加,只需要把 c_1c_2 相加即可。公式如下:

c_1 + c_2 = inv(S)[(	ext{w}x_1 + 	ext{w}x_2) + (e_1 + e_2)]

所以,對整數向量進行加減法時直接將密文進行加減就可以。

密鑰變換

密鑰變換使得我們可以把原來的密鑰變成我們指定的(滿足某些條件的)其他密鑰。當然,我們也需要對密文進行相應的修改使得修改後的密文用新的密鑰解碼後能夠得到與原來相同的明文。密鑰轉化在許多運算和分析中都十分有用,這將在下文中提及。因為這一步需要對密鑰進行操作,所以只能在本地運行。

假設我們的明文 x in Z^m ,密文 c in Z^n ,密鑰 S in Z^{m 	imes n} ,我們想將密鑰換成 S in Z^{m 	imes n} , 相應地,我們需要將密變成 c in Z^{n}並使得下面公式成立:

Sc  = Sc

為了完成這個工作,我們先把S 和 c 變成中間表示S* 和 c*,然後把S* 和 c*再變成S 和 c。S* 和 c* 是 S 和 c 的二進位表示。通過使用二進位表示,我們可以防止誤差增加過多,保證密文能夠被正確的解密。

第一步:將S, c變換成 S^*, c^*

c_k 是c中絕對值最大的一個元素,設 l 滿足 2^l > |c_k| 。我們令 c_i的二進位表示為[b_{i(l - 1)}, b_{i(l - 2)} ... b_{i(0)} ]^T ,使得 c_i = sum_{j = 0}^{l - 1}{b_{i(j)}2^j} 。例如對於 l = 3, c_i = 5 ,我們將其變為 b_i =[1, 0, 1] 。如果 c_i 是負數,我們取其絕對值的二進位表示,然後將每個 b_{i(j)} 前面加個負號。例如對於 l = 3, c_i = -6 ,我們將其表示為 b_i = [-1, -1, 0] 。然後,我們將 c^* 表示為 c^* = [b_1^T, b_2^T...,b_n^T]^T 。例如,取 l = 3, c = [1, -3] ,則 c^*=[0, 0, 1, 0, -1, -1]^T

然後,我們將 S 中的每個元素 S_{ij} 替換為 B_{ij} = [2^{l - 1}S_{ij}, 2^{l - 2}S_{ij}, ... ,2^{0}S_{ij}] 。例如將

S = left[ egin{matrix} 1 & -2 \ 5 & 4 end{matrix} 
ight] 變成 S^* = left[ egin{matrix} 4& 2& 1& -8& -4& -2 \ 20& 10& 5& 16& 8& 4 end{matrix} 
ight]

此時 B_{ij}b_i = S_{ij}c_i ,所以 S^*c^* = Sc

第二步:計算密鑰變換矩陣

我們接下來計算一個密鑰變換矩陣 M ,使得 M 滿足:

SM = S^* + E

這裡的E是一個隨機噪音矩陣。因為 S^* 中的元素乘了 2^{l - 1} ... 2^0 等值,而 E 沒有乘。所以通過這種方法,我們可以使 e = Ec^* 中的各個元素保持相對於 	ext{x} 中的元素比較小。從而防止誤差過大而解密錯誤。

為了簡單起見,我們將新的密鑰的形式限制為S』=left[I, T 
ight] , 其中 I 為m階單位矩陣, T 為用戶指定的某個矩陣。

此時,我們可以使 M=left[ egin{matrix} S^* - TA + E\ A end{matrix} 
ight] ,其中 A 是一個隨機的噪音矩陣,但為了保證安全性其中各個元素的絕對值不宜較小。 此時有SM = S^* - TA + E - TA = S^* + E

Mc^* 變換為 c ,即 c = Mc^* 。這樣可以得到

Sc = S^*c^* + Ec^*

線性變換:

G in Z^{m	imes n} ,如果想要求 G	ext{x} 的值,我們可以發現:

(GS)	ext{c}= wG	ext{x} + G	ext{e}

所以,我們可以把 	ext{c} 認為是 G	ext{x} 使用密鑰 GS 加密後得到的密文。此時,我們為了保密,可以將密鑰 GS 變成 S ,然後在本地計算一個密鑰變換矩陣 M ,然後將這個矩陣發送給雲端,在雲端計算 c = Mc 。這時如果用 Sc 進行解密就可以得到 G	ext{x}

帶權內積:

引理:對於長度為n向量 	ext{x}, 	ext{y} 和n階方陣 M

	ext{x}^TM	ext{y} = 	ext{vec}(M)^T	ext{vec(xy}^T) ,其中 	ext{vec}(X) 代表將矩陣 X 的每一行連接起來變成一個向量。

證明如下:

 	ext{vec}(M)^T	ext{vec(xy}^T) = sum_isum_j 	ext{x}_i M_{ij} 	ext{y}_j\ =sum_i(sum_j 	ext{x}_i M_i)_j cdot 	ext{y}_j\ =sum_j(	ext{x}^TM)	ext{y}_j\ =	ext{x}^TM	ext{y}

假設有明文 	ext{x}_1, 	ext{x}_2 和對應的使用 S_1, S_2 加密得到的密文 	ext{c}_1, 	ext{c}_2 。也就是 S_1	ext{c}_1 = w	ext{x}_1 + 	ext{e}_1S_2	ext{c}_2 = w	ext{x}_2 + 	ext{e}_2

我們提出如下假設:

使用密鑰 S = 	ext{vec}(S_1^THS_2)^T 解密密文 	ext{c}= lfloor frac{	ext{vec}(	ext{c}_1	ext{c}_2^T)}{w} 
ceil 得到明文 	ext{x} = 	ext{x}_1H	ext{x}_2 。也就是說對於某個新的誤差項 	ext{e} :

 	ext{vec}(S_1^THS_2)^Tlfloor frac{	ext{vec}(	ext{c}_1	ext{c}_2^T)}{w} 
ceil = w	ext{x}_1H	ext{x}_2 + 	ext{e}

證明.

首先我們通過令 w = 1 將其忽略,使用此前的引理,我們可以得到:

 	ext{vec}(S_1^THS_2)^T 	ext{vec}(	ext{c}_1	ext{c}_2^T)= 	ext{c}_1^TS_1^THS_2	ext{c}_2\ = (S_1	ext{c}_1)^THS_2	ext{c}_2\ = (w	ext{x}_1 + 	ext{e}_1 )^TH(w	ext{x}_2 + 	ext{e}_2 )\ =w^2	ext{x}_1H	ext{x}_2 + w(	ext{x}_1^TH	ext{e}_2 + 	ext{e}_1^TH	ext{x}_2) + 	ext{e}_1^TH	ext{e}_2

我們可以通過選擇一個比較大的 w ,使得:

lceil frac{	ext{vec}(S_1^THS_2)^T 	ext{vec}(	ext{c}_1	ext{c}_2^T)}{w} 
floor\ =w	ext{x}_1H	ext{x}_2 + (	ext{x}_1^TH	ext{e}_2 + 	ext{e}_1^TH	ext{x}_2) + frac{	ext{e}_1^TH	ext{e}_2}{w}\ = w	ext{x}_1H	ext{x}_2 + e

證明了上面的假設之後,我們就可以運用密鑰變換的方法把 	ext{vec}(S_1^THS_2)^T 變換成其他的密鑰 S ,同時使用密鑰變換矩陣 Mlfloor frac{	ext{vec}(	ext{c}_1	ext{c}_2^T)}{w} 
ceil 變成 	ext{c} 即可完成帶權內積。

推薦閱讀:

path-ORAM 及其他的tree-based ORAM
菲律賓網站被「黑」中國紅客與外國黑客20年升級對抗賽
使用C#實現文件加密、解密
用5個GPU構建密碼破解機【附詳細視頻】
密碼學I:流密碼基礎 - 定義及其應用

TAG:信息安全和密碼學 |