双线性映射(密码学常用算法)
Java密碼學原型算法實現(xiàn)——第三部分:雙線性對
背景介紹
技術博客已經好久沒更新了。倒不是因為沒得寫,是因為實在是太忙了,而且研究也到了一個瓶頸期,需要大量閱讀文獻。
本來打算很長一段時間都不更新博客了,甚至打算等我畢業(yè)工作后再更新一些有價值的博客,但是最近在CSDN私信上和知乎上經常收到求救帖子,希望我能寫一個jPBC使用方法的博客。甚至實驗室的碩士生們也在各種咨詢我相關的問題。于是,我打算一勞永逸,寫一篇有關jPBC使用的博客。希望這個博客出來后,能解決絕大多數(shù)人的問題吧…
本篇博客期望解決的問題:
質數(shù)階雙線性群(Prime-Order Bilinear Groups); 合數(shù)階雙線性群(Composite-Order Bilinear Groups); 如何使用jPBC庫執(zhí)行雙線性群運算,包括:
指數(shù)群Z 的加法和乘法; 雙線性群G 的乘法和指數(shù)冪; 目標群GT 的乘法和指數(shù)冪 雙線性群G 映射到目標群GT 的對(Pairing)運算; 使用jPBC庫的一些注意事項。
本篇博客不會涉及到的問題:
如何配置jPBC庫到Eclipse中;這方面的內容請參考我的另一篇博客:jPBC 2.0.0配置與測試(補充版); 有關雙線性對的數(shù)學知識;這方面我在第二章會稍微介紹一下,但是不會詳談,因為內容太多了。 對偶雙線性群向量空間群(Dual Pairing Vector Space,DPVS);這個群在理論上被用于替代合數(shù)階雙線性群。其可以在保證同等安全性的條件下,使雙線性對運算時間較短,而代價是存儲開銷會變大。這個工具在2012年得到了廣泛的應用。但是這兩年普遍認為這個工具的進一步應用場景有限,而且表示并不直觀,還不如和合數(shù)階雙線性群好用。jPBC 2.0.0實際上提供了DPVS的實現(xiàn),也是正確的。有興趣的朋友們可以自己研究一下,我在這里就不詳述了。 如何使用jPBC 2.0.0的多線性對(Multilinear Maps)函數(shù)庫;這方面我自己一直沒找時間測試一下多線性對函數(shù)庫,實際上近期我也不太想測試這個庫,主要有兩方面的原因。現(xiàn)在所構造出來的多線性對并非密碼學中的理想多線性對(Ideal Multilinear Maps),而是候選多線性對(Candidate Multilinear Maps),后者在使用上有很多的限制。 jPBC 2.0.0實現(xiàn)的多線性對是[CLT-14]的方案,但這個方案已經被證明是不安全的了。
雙線性群簡介
這里我直接引用自己的二篇水文來介紹(都是湊數(shù)用的…)選擇密文安全的身份及廣播加密方案,密碼學報,Experimental performance comparisons between (H) IBE schemes over composite-order and prime-order bilinear groups,IBCAST 2014。
質數(shù)階雙線性群(Prime-Order Bilinear Groups)
質數(shù)雙線性群可以由五元組(p,G1,G2,GT,e)來描述。五元組中p是一個與給定安全常數(shù)λ相關的大質數(shù),G1,G2,GT均是階為p的乘法循環(huán)群,e為雙線性映射e:G1×G2→GT,它滿足以下3個條件:
雙線性(Bilinearity):對于任意的g∈G1 ,h∈G2 ,a,b∈Zp ,有e(ga,hb)=e(g,h)ab ; 非退化性(Non-degeneracy):至少存在元素g1∈G1,g2∈G2 ,滿足e(g1,g2)≠1 ; 可計算性(Efficiency):對于任意的u∈G1,v∈G2 ,存在一個與給定安全常數(shù)λ 相關的多項式時間算法,可以高效地計算e(u,v) ;現(xiàn)在的密碼學相關論文中,習慣將G1,G2設置為乘法循環(huán)群。但是,基于橢圓曲線的雙線性群構造中,G1,G2是加法群。所以在大約2005年以前的論文中,雙線性群一般寫成加法群形式。jPBC中將G1,G2表示稱為了乘法循環(huán)群,因此在實現(xiàn)寫成加法群形式的方案時,要注意將加法群改成乘法群的寫法再進行實現(xiàn)。如何修改呢?很簡單,把加法群中的加法運算寫成乘法運算、把加法群中的乘法運算寫成冪指數(shù)運算即可。
合數(shù)階雙線性群(Composite-Order Bilinear Groups)
合數(shù)階雙線性群和質數(shù)階雙線性群很類似,區(qū)別是G1,G2,GT的階數(shù)是一個合數(shù)N,其中N是一些大質數(shù)的乘積,如N=p1p2?pn。同樣,e為雙線性映射e:G1×G2→GT,它滿足雙線性性、非退化性以及可計算性。
與質數(shù)階雙線性群不同,合數(shù)階雙線性群中,GN有階數(shù)分別為p1,p2,?,pn的子群Gp1,?,Gpn。這些子群進一步滿足正交特性。
對于所有的hi∈Gpi和hj∈Gpj,如果i≠j,那么e(hi,hj)=1
簡單地說就是,子群之間進行雙線性運算的結果必為1。
一些說明
首先,由于雙線性群現(xiàn)在的構造是基于橢圓曲線的,而橢圓曲線上的元素是由坐標(x,y)表示的,所以如果我們將G1,G2的結果輸出到Java的控制臺,我們得到的是一個坐標。不過,GT是一個普通的Z群,所以其元素的表示是一個數(shù)。
其次,在密碼學中,如果G1=G2,我們稱這個雙線性群是對稱雙線性群(Symmetric Bilinear Group),否則稱之為非對稱雙線性群(Asymmetric Bilinear Group)。
是否為對稱雙線性群由選取的橢圓曲線種類決定。一般認為,非對稱雙線性群要比對稱雙線性群更安全。特別地,現(xiàn)在已經證明一些特定的對稱雙線性群是不安全的了。
現(xiàn)在jPBC可以使用的曲線為如下幾類:
Type A Type A1 Type D Type E Type F Type G現(xiàn)在密碼學實現(xiàn)基本只使用Type A和Type A1的。前者為對稱質數(shù)階雙線性群,后者為合數(shù)階對稱雙線性群。本博客也只在這兩類曲線上實驗。其他類曲線的實現(xiàn)類似。由于是對稱雙線性群,本博客中G1,G2統(tǒng)一寫為G。
雙線性群初始化
在jPBC中,雙線性群的使用都是通過叫做Pairing的對象來實現(xiàn)的。雙線性群的初始化在jPBC中就是對Pairing對象的初始化。雙線性群有兩種初始化的方法。第一種是通過代碼動態(tài)產生一個雙線性群,第二種是從文件中讀取參數(shù)而產生群。
通過代碼動態(tài)產生
動態(tài)產生的方法非常簡單,大概有如下步驟:指定橢圓曲線的種類、產生橢圓曲線參數(shù)、初始化Pairing。Type A曲線需要兩個參數(shù):rBit是Zp中階數(shù)p的比特長度;qBit是G中階數(shù)的比特長度。代碼為:
TypeACurveGenerator pg = new TypeACurveGenerator(rBit, qBit); PairingParameters typeAParams = pg.generate(); Pairing pairing = PairingFactory.getPairing(typeAParams);Type A1曲線需要二個參數(shù):numPrime是階數(shù)N中有幾個質數(shù)因子;qBit是每個質數(shù)因子的比特長度。注意,Type A1涉及到的階數(shù)很大,其參數(shù)產生的時間也比較長。代碼為:
TypeA1CurveGenerator pg = new TypeA1CurveGenerator(numPrime, qBit); PairingParameters typeA1Params = pg.generate(); Pairing pairing = PairingFactory.getPairing(typeA1Params);通過文件讀取產生
我們也可以選擇事先產生好參數(shù),存放在文件中。以后再初始化的時候,直接從文件中讀取參數(shù),就可以非常快速的初始化雙線性群。
PairingParameters支持toString()函數(shù)。實際上,我們可以直接將PairingParametersd的toString()存放在文件中。讀取的時候,通過讀取文件就可以直接初始化雙線性群了。
Type A曲線從文件中讀取參數(shù)初始化的代碼為:
TypeACurveGenerator pg = new TypeACurveGenerator(rBit, qBit); PairingParameters typeAParams = pg.generate(); //將參數(shù)寫入文件a.properties中,我用了Princeton大學封裝的文件輸出庫 Out out = new Out("a.properties"); out.println(typeAParams); //從文件a.properties中讀取參數(shù)初始化雙線性群 Pairing pairing = PairingFactory.getPairing("a.properties");Type A1曲線從文件中讀取參數(shù)初始化的代碼為:
TypeA1CurveGenerator pg = new TypeA1CurveGenerator(numPrimes, qBit); PairingParameters typeA1Params = pg.generate(); //將參數(shù)寫入文件a1.properties中,同樣使用了Princeton大學封裝的文件輸出庫 Out out = new Out("a1.properties"); out.println(typeA1Params); //從文件a1.properties中讀取參數(shù)初始化雙線性群 Pairing pairing = PairingFactory.getPairing("a1.properties");產生雙線性群中的隨機數(shù)
Type A中產生隨機數(shù)的方法很簡單,代碼為:
//隨機產生一個Z_p群的元素 Element Z_p = pairing.getZr().newRandomElement().getImmutable(); //隨機產生一個G_1群的元素 Element G_1 = pairing.getG1().newRandomElement().getImmutable(); //隨機產生一個G_2群的元素 Element G_2 = pairing.getG2().newRandomElement().getImmutable(); //隨機產生一個G_T群的元素 Element G_T = pairing.getGT().newRandomElement().getImmutable();Type A1中產生隨機數(shù)的方法稍微有點麻煩。對于ZN和GT方法和Type A一樣。代碼為:
//隨機產生一個Z_N群的元素 Element Z_N = pairing.getZr().newRandomElement().getImmutable(); //隨機產生一個G_T群的元素 Element G_T = pairing.getGT().newRandomElement().getImmutable();但是對于G就不同了。因為G有子群Gpi,Type A1產生隨機數(shù)時需要指定生成元,橢圓曲線的參數(shù),產生哪個子群的元素,以及Type A1一共有多少個子群。
假定我們產生的Type A1共有n個子群,這n個子群的階分別為p1,?,pn,產生隨機數(shù)的代碼如下:
TypeA1CurveGenerator pg = new TypeA1CurveGenerator(numPrimes, qBit); PairingParameters typeA1Params = pg.generate(); Pairing pairing = PairingFactory.getPairing(typeA1Params);//設定并存儲一個生成元。由于橢圓曲線是加法群,所以G群中任意一個元素都可以作為生成元 Element generator = pairing.getG1().newRandomElement().getImmutable(); //隨機產生一個G_p_1中的元素 Element G_p_1 = ElementUtils.getGenerator(pairing, generator, typeA1Params, 0, numPrimes).getImmutable(); //隨機產生一個G_p_2中的元素 Element G_p_2 = ElementUtils.getGenerator(pairing, generator, typeA1Params, 1, numPrimes).getImmutable(); // ...... //隨機產生一個G_p_n中的元素 Element G_p_n = ElementUtils.getGenerator(pairing, generator, typeA1Params, 1, numPrimes).getImmutable();將指定的元素哈希到雙線性群中
由于雙線性群最初是用在基于身份的加密(Identity-Based Encryption)系統(tǒng)中,我們經常會需要將一個特定的String或者byte[]哈希到雙線性群中。
jPBC支持將byte[]哈希到雙線性群的Z,G,GT中。但是,jPBC說明文檔中沒有提到的是,byte[]數(shù)組長度不能太長,如果過長會拋出異常。因此,我建議首先將byte[]用一個SHA256或者其他通用哈希函數(shù)哈希到固定長度,再用jPBC提供的函數(shù)哈希到雙線性群上。在這里我略去SHA256步驟,直接給出哈希到Z,G,GT群的代碼:
//將byte[] byteArray_Z_p哈希到Z_p群 Element hash_Z_p = pairing.getZr().newElement().setFromHash(byteArray_Z_p, 0, byteArray_Z_p.length); //將byte[] byteArray_G_1哈希到G_1群 Element hash_G_1 = pairing.getG1().newElement().setFromHash(byteArray_G_1, 0, byteArray_G_1.length); //將byte[] byteArray_G_2哈希到G_2群 Element hash_G_2 = pairing.getG2().newElement().setFromHash(byteArray_G_2, 0, byteArray_G_2.length); //將byte[] byteArray_G_T哈希到G_T群 Element hash_G_T = pairing.getGT().newElement().setFromHash(byteArray_G_T, 0, byteArray_G_T.length);注意,對于Type A1來說,這個代碼無法指定哈希到指定子群Gpi中。解決方法是將byte[]先哈希到Z群,然后利用G,GT的生成元計算冪指數(shù),從而達到哈希到G,GT上的效果。
雙線性群的運算
雙線性群之間有如下運算:
- G相關運算:GZ, G×G;
- GT相關運算:GZT, GT×GT;
- Z相關運算:Z+Z, Z×Z;
- Pairing運算
做運算的時候要注意一下幾點:
Java的運算結果都是產生一個新的Element來存儲,所以我們需要把運算結果賦值給一個新的Element; Java在進行相關運算時,參與運算的Element值可能會改變。所以,如果需要在運算過程中保留參與運算的Element值,在存儲的時候一定要調用getImmutable(),具體方法見代碼中的初始化相關參數(shù)部分。 其實為了保險起見,防止Element在運算的過程中修改了Element原本的數(shù)值,可以使用Element.duplicate()方法。這個方法將返回一個與Element數(shù)值完全一樣的Element,但是是個新的Element對象。舉例來說,如果做G1×G1 的運算,可以寫成: Element G_1_m_G_1 = G_1.duplicate().mul(G_1_p.duplicate()); G 和G 其實也是可以進行冪指數(shù)運算的,即GG ,調用的函數(shù)為Element e1.pow(Element e2)。特別注意,我們再寫G 群的Z 次方運算時,用的函數(shù)為powZn(),而不是pow(),這個調用錯誤很容易使得程序的運算結果不正確。代碼如下:
//初始化相關參數(shù) Element G_1 = pairing.getG1().newRandomElement().getImmutable(); Element G_2 = pairing.getG2().newRandomElement().getImmutable(); Element Z = pairing.getZr().newRandomElement().getImmutable(); Element G_T = pairing.getGT().newRandomElement().getImmutable();Element G_1_p = pairing.getG1().newRandomElement().getImmutable(); Element G_2_p = pairing.getG2().newRandomElement().getImmutable(); Element Z_p = pairing.getZr().newRandomElement().getImmutable(); Element G_T_p = pairing.getGT().newRandomElement().getImmutable();//G_1的相關運算 //G_1 multiply G_1 Element G_1_m_G_1 = G_1.mul(G_1_p); //G_1 power Z Element G_1_e_Z = G_1.powZn(Z);//G_2的相關運算 //G_2 multiply G_2 Element G_2_m_G_2 = G_2.mul(G_2_p); //G_2 power Z Element G_2_e_Z = G_2.powZn(Z);//G_T的相關運算 //G_T multiply G_T Element G_T_m_G_T = G_T.mul(G_T_p); //G_T power Z Element G_T_e_Z = G_T.powZn(Z);//Z的相關運算 //Z add Z Element Z_a_Z = Z.add(Z_p); //Z multiply Z Element Z_m_Z = Z.mul(Z_p);//Pairing運算 Element G_p_G = pairing.pairing(G_1, G_2);總結
以上是生活随笔為你收集整理的双线性映射(密码学常用算法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 河南思维监控文件服务器,LKJ数据远程载
- 下一篇: CentOS上安装Selenium和go