同态加密算法简述

同态加密

如果我们有一个加密函数 f , 把明文A变成密文A’, 把明文B变成密文B’,也就是说 f(A) = A’ , f(B) = B’ 。另外我们还有一个解密函数 f1 能够将 f 加密后的密文解密成加密前的明文。

对于一般的加密函数,如果我们将A’和B’相加,得到C’。我们用f1 对C’进行解密得到的结果一般是毫无意义的乱码。

但是,如果 f 是个可以进行同态加密的加密函数, 我们对C’使用 f1 进行解密得到结果C, 这时候的C = A + B。这样,数据处理权与数据所有权可以分离,这样企业可以防止自身数据泄露的同时,利用云服务的算力。

同态分类

a) 如果满足 f(A)+f(B)=f(A+B) , 我们将这种加密函数叫做加法同态
b) 如果满足 f(A)×f(B)=f(A×B) ,我们将这种加密函数叫做乘法同态。

如果一个加密函数f只满足加法同态,就只能进行加减法运算

如果一个加密函数f只满足乘法同态,就只能进行乘除法运算;

如果一个加密函数同时满足加法同态和乘法同态,称为全同态加密那么这个使用这个加密函数完成各种加密后的运算(加减乘除、多项式求值、指数、对数、三角函数)。

第一个满足加法和乘法同态的同态加密方法直到2009年才由Craig Gentry提出。

同态加密算法

  1. RSA 算法对于乘法操作是同态的。
  2. Paillier 算法则是对加法同态的。
  3. Gentry算法则是全同态的。

Paillier算法

原理

  1. http://www.tcnj.edu/~hagedorn/papers/CapstonePapers/OKeeffe/CapstoneOKeeffeCryptography.pdf
  2. http://slideplayer.com/slide/8488065/

实现

java版本

/** 
* This program is free software: you can redistribute it and/or modify it 
* under the terms of the GNU General Public License as published by the Free 
* Software Foundation, either version 3 of the License, or (at your option) 
* any later version. 
* 
* This program is distributed in the hope that it will be useful, but WITHOUT 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
* more details. 
* 
* You should have received a copy of the GNU General Public License along with 
* this program. If not, see <http://www.gnu.org/licenses/>. 
*/  

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

/** 
 * Paillier Cryptosystem <br> 
 * <br> 
 * References: <br> 
 * [1] Pascal Paillier, 
 * "Public-Key Cryptosystems Based on Composite Degree Residuosity Classes," 
 * EUROCRYPT'99. URL: 
 * <a href="http://www.gemplus.com/smart/rd/publications/pdf/Pai99pai.pdf">http: 
 * //www.gemplus.com/smart/rd/publications/pdf/Pai99pai.pdf</a><br> 
 * 
 * [2] Paillier cryptosystem from Wikipedia. URL: 
 * <a href="http://en.wikipedia.org/wiki/Paillier_cryptosystem">http://en. 
 * wikipedia.org/wiki/Paillier_cryptosystem</a> 
 *  
 * @author Kun Liu (kunliu1@cs.umbc.edu) 
 * @version 1.0 
 */  
public class Paillier {  

    /** 
     * p and q are two large primes. lambda = lcm(p-1, q-1) = 
     * (p-1)*(q-1)/gcd(p-1, q-1). 
     */  
    private BigInteger p, q, lambda;  
    /** 
     * n = p*q, where p and q are two large primes. 
     */  
    public BigInteger n;  
    /** 
     * nsquare = n*n 
     */  
    public BigInteger nsquare;  
    /** 
     * a random integer in Z*_{n^2} where gcd (L(g^lambda mod n^2), n) = 1. 
     */  
    private BigInteger g;  
    /** 
     * number of bits of modulus 
     */  
    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);  
    }  

    /** 
     * Sets up the public key and private key. 
     *  
     * @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 void KeyGeneration(int bitLengthVal, int certainty) {  
        bitLength = bitLengthVal;  
        /* 
         * Constructs two randomly generated positive BigIntegers that are 
         * probably prime, with the specified bitLength and certainty. 
         */  
        p = new BigInteger(bitLength / 2, certainty, new Random());  
        q = new BigInteger(bitLength / 2, certainty, new Random());  

        n = p.multiply(q);  
        nsquare = n.multiply(n);  

        g = new BigInteger("2");  
        lambda = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE))  
                .divide(p.subtract(BigInteger.ONE).gcd(q.subtract(BigInteger.ONE)));  
        /* check whether g is good. */  
        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);  
        }  
    }  

    /** 
     * Encrypts plaintext m. ciphertext c = g^m * r^n mod n^2. This function 
     * explicitly requires random input r to help with encryption. 
     *  
     * @param m 
     *            plaintext as a BigInteger 
     * @param r 
     *            random plaintext to help with encryption 
     * @return ciphertext as a BigInteger 
     */  
    public BigInteger Encryption(BigInteger m, BigInteger r) {  
        return g.modPow(m, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare);  
    }  

    /** 
     * Encrypts plaintext m. ciphertext c = g^m * r^n mod n^2. This function 
     * automatically generates random input r (to help with encryption). 
     *  
     * @param m 
     *            plaintext as a BigInteger 
     * @return ciphertext as a BigInteger 
     */  
    public BigInteger Encryption(BigInteger m) {  
        BigInteger r = new BigInteger(bitLength, new Random());  
        return g.modPow(m, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare);  

    }  

    /** 
     * Decrypts ciphertext c. plaintext m = L(c^lambda mod n^2) * u mod n, where 
     * u = (L(g^lambda mod n^2))^(-1) mod n. 
     *  
     * @param c 
     *            ciphertext as a BigInteger 
     * @return plaintext as a BigInteger 
     */  
    public BigInteger Decryption(BigInteger c) {  
        BigInteger u = g.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).modInverse(n);  
        return c.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n);  
    }  

    /** 
     * sum of (cipher) em1 and em2 
     *  
     * @param em1 
     * @param em2 
     * @return 
     */  
    public BigInteger cipher_add(BigInteger em1, BigInteger em2) {  
        return em1.multiply(em2).mod(nsquare);  
    }  

    /** 
     * main function 
     *  
     * @param str 
     *            intput string 
     */  
    public static void main(String[] str) {  
        /* instantiating an object of Paillier cryptosystem */  
        Paillier paillier = new Paillier();  
        /* instantiating two plaintext msgs */  
        BigInteger m1 = new BigInteger("20");  
        BigInteger m2 = new BigInteger("60");  
        /* encryption */  
        BigInteger em1 = paillier.Encryption(m1);  
        BigInteger em2 = paillier.Encryption(m2);  
        /* printout encrypted text */  
        System.out.println(em1);  
        System.out.println(em2);  
        /* printout decrypted text */  
        System.out.println(paillier.Decryption(em1).toString());  
        System.out.println(paillier.Decryption(em2).toString());  

        /* 
         * test homomorphic properties -> 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("original sum: " + sum_m1m2.toString());  
        // em1+em2,求密文数值的乘  
        BigInteger product_em1em2 = em1.multiply(em2).mod(paillier.nsquare);  
        System.out.println("encrypted sum: " + product_em1em2.toString());  
        System.out.println("decrypted sum: " + paillier.Decryption(product_em1em2).toString());  

        /* test homomorphic properties -> 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("original product: " + prod_m1m2.toString());  
        // em1的m2次方,再mod paillier.nsquare  
        BigInteger expo_em1m2 = em1.modPow(m2, paillier.nsquare);  
        System.out.println("encrypted product: " + expo_em1m2.toString());  
        System.out.println("decrypted product: " + paillier.Decryption(expo_em1m2).toString());  

        //sum test  
        System.out.println("--------------------------------");  
        Paillier p = new Paillier();  
        BigInteger t1 = new BigInteger("21");System.out.println(t1.toString());  
        BigInteger t2 = new BigInteger("50");System.out.println(t2.toString());  
        BigInteger t3 = new BigInteger("50");System.out.println(t3.toString());  
        BigInteger et1 = p.Encryption(t1);System.out.println(et1.toString());  
        BigInteger et2 = p.Encryption(t2);System.out.println(et2.toString());  
        BigInteger et3 = p.Encryption(t3);System.out.println(et3.toString());  
        BigInteger sum = new BigInteger("1");  
        sum = p.cipher_add(sum, et1);  
        sum = p.cipher_add(sum, et2);  
        sum = p.cipher_add(sum, et3);  
        System.out.println("sum: "+sum.toString());  
        System.out.println("decrypted sum: "+p.Decryption(sum).toString());  
        System.out.println("--------------------------------");  
    }  
}  

javascript版本

go版本

更多

https://zhuanlan.zhihu.com/p/31822335

阅读更多
换一批

没有更多推荐了,返回首页