Paillier算法的實現

//本來以爲很難,確實,看了paillier算法的英文版說明,硬是沒看下去。不得不找一篇中文的關於paillier的講解,最後終於大概明白了pailler算法,下面是我的java實現

維基百科關於Pailler的解釋:點擊打開鏈接

package com.ljc;
/**
 * 密鑰生成:
 * 1、隨機選擇兩個大質數p和q滿足gcd(pq,(p-1)(q-1))=1。 這個屬性是保證兩個質數長度相等。
 * 2、計算 n = pq和λ= lcm (p - 1,q-1)。
 * 3、選擇隨機整數g使得gcd(L(g^lambda % n^2) , n) = 1,滿足g屬於n^2;
 * 4、公鑰爲(N,g)
 * 5、私鑰爲lambda。
 * :加密
 * 選擇隨機數r滿足
 * 計算密文
 * 其中m爲加密信息
 * 
 * 解密:
 * m = D(c,lambda) = ( L(c^lambda%n^2)/L(g^lambda%n^2) )%n;
 * 其中L(u) = (u-1)/n;
 */

import java.math.*;  
import java.util.*;  

public class Paillier {  

	//p,q是兩個隨機的質數, lambda = lcm(p-1, q-1);
	private BigInteger p, q, lambda;
	 
	// n = p*q
	public BigInteger n;   
	
	// nsquare就是n的平方   
	public BigInteger nsquare; 
	/** 
	 * 隨機選取一個整數 g,g屬於小於n的平方中的整數集,且 g 滿足:g的lambda次方對n的平方求模後減一後再除與n,
	 * 最後再將其與n求最大公約數,且最大公約數等於一。
	 * a random integer in Z*_{n^2} where gcd (L(g^lambda mod nsquare), n) = 1. 
	 */  
	private BigInteger g;  
	//bitLength 模量 
	private int bitLength;  

	/** 
	 * Constructs an instance of the Paillier cryptosystem. 
	 *  
	 * @param bitLengthVal 
	 *            number of bits of modulus 模量
	 * @param certainty 
	 *            The probability that the new BigInteger represents a prime 
	 *            number will exceed (1 - 2^(-certainty)). The execution time of 
	 *            this constructor is proportional to the value of this 
	 *            parameter. 
	 *帶參的構造方法
	 */  
	public Paillier(int bitLengthVal, int certainty) {  
		KeyGeneration(bitLengthVal, certainty);  
	}  

	/** 
	 * Constructs an instance of the Paillier cryptosystem with 512 bits of 
	 * modulus and at least 1-2^(-64) certainty of primes generation. 
	 * 構造方法
	 */  
	public Paillier() {  
		KeyGeneration(512, 64);  
	}  

	/** 
	 * 產生公鑰【N,g】       私鑰lamada
	 * @param bitLengthVal 
	 *            number of bits of modulus. 
	 * @param certainty 
	 *            certainty - 調用方允許的不確定性的度量。
	 *            新的 BigInteger 表示素數的概率超出 (1 - 1/2certainty)。
	 *            此構造方法的執行時間與此參數的值是成比例的。
	 */  
	public void KeyGeneration(int bitLengthVal, int certainty) {  
		bitLength = bitLengthVal;  
		//構造兩個隨機生成的正 大質數,長度可能爲bitLength/2,它可能是一個具有指定 bitLength 的素數
		p = new BigInteger(bitLength / 2, certainty, new Random());  
		q = new BigInteger(bitLength / 2, certainty, new Random());  
		
		//n = p*q;
		n = p.multiply(q);  
		//nsquare = n*n;
		nsquare = n.multiply(n);  
        //隨機生成一個0~100的整數g
		g = new BigInteger( String.valueOf( (int) (  Math.random()*100 ) )); 
		
		//lamada=lcm(p-1,q-1),即lamada是p-1,q-1的最小公倍數
		//lamada=((p-1)*(q-1)) / gcd(p-1,q-1);
		lambda = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE))  //(p-1)*(q-1)
				.divide(p.subtract(BigInteger.ONE).gcd(q.subtract(BigInteger.ONE)));  
		//檢驗g是否符合公式的要求, gcd (L(g^lambda mod nsquare), n) = 1.
		if (g.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).gcd(n).intValue() != 1) {  
			System.out.println("g is not good. Choose g again.");  
			System.exit(1);  
		}  
	}  

	/** 
	 * @param m 明文m
	 * @param r 隨機的一個整數r
	 * @return 返回密文 
	 * 加密
	 */  
	public BigInteger Encryption(BigInteger m, BigInteger r) {  
		//c = (g^m)*(r^n)modnsquare
		return g.modPow(m, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare);  
	}  

	public BigInteger Encryption(BigInteger m) {  
		//構造一個隨機生成的 BigInteger,它是在 0 到 (2numBits - 1)(包括)範圍內均勻分佈的值。
		BigInteger r = new BigInteger(bitLength, new Random());  
		return g.modPow(m, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare);  

	}  

	/** 
	 * 利用私鑰lamada對密文c進行解密返回明文m
	 * 公式:m = ( L((c^lambda) mod nsquare) / L((g^lambda) mod nsquare) ) mod n
	 */  
	public BigInteger Decryption(BigInteger c) {
		BigInteger u1 = c.modPow(lambda, nsquare);
		BigInteger u2 = g.modPow(lambda, nsquare);
		return (u1.subtract(BigInteger.ONE).divide(n)).multiply(u2.subtract(BigInteger.ONE).divide(n).modInverse(n)).mod(n);
	}  

	/** 
	 * 兩個密文的和
	 * @param em1 
	 * @param em2 
	 * @return 
	 */  
	public BigInteger cipher_add(BigInteger em1, BigInteger em2) {  
		return em1.add(em2);  
	}  

	public static void main(String[] str) {  
		//實例化一個不用傳參的對象,用默認的數據
		Paillier paillier = new Paillier();  
		// 實例化兩個數據對象m1,m2,進行加密
		BigInteger m1 = new BigInteger("20");  
		BigInteger m2 = new BigInteger("60");  
		
		//加密  
		BigInteger em1 = paillier.Encryption(m1);  
		BigInteger em2 = paillier.Encryption(m2);  
		
		//輸出加密後的結果 
		System.out.println("m1加密後爲: "+em1);  
		System.out.println("m2加密後爲: "+em2);  
		
		//輸出解密後的結果  
		System.out.println("m1加密之後進行解密的結果= "+paillier.Decryption(em1).toString());  
		System.out.println("m2加密之後進行解密的結果= "+paillier.Decryption(em2).toString());  

		
		// 測試同態性     D(E(m1)*E(m2) mod n^2) = (m1 + m2) mod n
		   
		// m1+m2,求明文數值的和  
		BigInteger sum_m1m2 = m1.add(m2).mod(paillier.n);  
		System.out.println("明文的和 : " + sum_m1m2.toString());  
		// em1+em2,求密文數值的乘  
		BigInteger product_em1em2 = em1.multiply(em2).mod(paillier.nsquare);  
		System.out.println("密文的和: " + product_em1em2.toString());  
		System.out.println("解密後的 和: " + paillier.Decryption(product_em1em2).toString());  

		// 測試同態性 ->   D(E(m1)^m2 mod n^2) = (m1*m2) mod n   
		// m1*m2,求明文數值的乘  
		BigInteger prod_m1m2 = m1.multiply(m2).mod(paillier.n);  
		System.out.println("明文的乘積: " + prod_m1m2.toString());  
		// em1的m2次方,再mod paillier.nsquare  
		BigInteger expo_em1m2 = em1.modPow(m2, paillier.nsquare);  
		System.out.println("密文的結果: " + expo_em1m2.toString());  
		System.out.println("解密後的結果: " + paillier.Decryption(expo_em1m2).toString());  

		System.out.println("--------------------------------");  
		Paillier p = new Paillier();  
		BigInteger t1 = new BigInteger("21"); System.out.println("t1 = "+t1.toString());  
		BigInteger t2 = new BigInteger("50"); System.out.println("t2 = "+t2.toString());  
		BigInteger et1 = p.Encryption(t1); System.out.println("t1 Encryption = "+et1.toString());  
		BigInteger et2 = p.Encryption(t2); System.out.println("t2 Encryption = "+et2.toString());  
	
		System.out.println("明文和: "+t1.add(t2).toString());  
		System.out.println("加密後的和 : "+p.Encryption(t1.add(t2)).toString());
		System.out.println("解密後的和進行解密:"+p.Decryption(p.Encryption(t1.add(t2))));
		System.out.println("--------------------------------");  
	}  
} 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章