Python + numpy实现同态加密算法

在实现之前,先了解一下什么是同态加密。

以下这个公式使我们要实现的同态加密版本
S c = w x + e x = ⌈ S c w ⌋ S \mathbf{c}=w \mathbf{x}+\mathbf{e} \quad \mathbf{x}=\left\lceil\frac{S \mathbf{c}}{w}\right\rfloor Sc=wx+ex=wSc

第一种加密

对称加密

如果密钥S是一个单位矩阵,那么c不过是输入x的一个重加权的、略带噪声的版本。

当S为单位矩阵时,相当于没有加密

当S为随机矩阵时,有加密

加解密使用同一key

import numpy as np

def generate_key(w,m,n):
    S = (np.random.rand(m,n) * w / (2 ** 16))# 可证明 max(S) < w
    return S# key,对称加密
def encrypt(x,S,m,n,w):
    assert len(x) == len(S)
    e = (np.random.rand(m))# 可证明 max(e) < w / 2
    c = np.linalg.inv(S).dot((w * x) + e)   
    return c
def decrypt(c,S,w):
    return (S.dot(c) / w).astype('int')

x = np.array([0,1,2,5])
m = len(x)
n = m
w = 16
S = generate_key(w,m,n)
c = encrypt(x,S,m,n,w)
decrypt(c,S,w)

array([0, 1, 2, 5])

print(x+x)
print(x*10)

[ 0 2 4 10]
[ 0 10 20 50]

decrypt(c+c,S,w)

array([ 0, 2, 4, 10])

decrypt(c*10,S,w)

array([ 0, 10, 20, 50])

x*x

array([0, 1, 4])

decrypt(c*c,S,w)

array([15296055, 6267577, 8584289])

第二种加密

论文作者没有显式地分配一对独立的“公钥”和“私钥”,相反,提出了一种“钥交换”技术,将私钥S替换为S’。更具体地,这一私钥交换技术涉及生成一个可以进行该变换的矩阵M。由于M具备将消息从未加密状态(单位矩阵密钥)转换为加密状态(随机而难以猜测的密钥),这个M矩阵正好可以用作我们的公钥!

基于开篇两个公式,如果密钥是一个单位矩阵,那么消息是未加密的。

基于开篇两个公式,如果密钥是一个随机矩阵,那么消息是加密的。

我们构造一个矩阵M将一个密钥转换为另一个私钥。

当矩阵M将单位矩阵转换为一个随机密钥时,根据定义,它使用单向加密方式加密了消息。

由于M充当了“单向加密”的角色,我们称它为“公钥”,并且可以像公钥一样分发它,因为它无法用于解密。

import numpy as np

def generate_key(w,m,n):
    S = (np.random.rand(m,n) * w / (2 ** 16)) # 可证明 max(S) < w
    return S

def encrypt(x,S,m,n,w):
    assert len(x) == len(S)
    e = (np.random.rand(m)) # 可证明 max(e) < w / 2
    c = np.linalg.inv(S).dot((w * x) + e)
    return c

def decrypt(c,S,w):
    return (S.dot(c) / w).astype('int')

def get_c_star(c,m,l):
    c_star = np.zeros(l * m,dtype='int')
    for i in range(m):
        b = np.array(list(np.binary_repr(np.abs(c[i]))),dtype='int')
        if(c[i] < 0):
            b *= -1
        c_star[(i * l) + (l-len(b)): (i+1) * l] += b
    return c_star

def switch_key(c,S,m,n,T):
    l = int(np.ceil(np.log2(np.max(np.abs(c)))))
    c_star = get_c_star(c,m,l)
    S_star = get_S_star(S,m,n,l)
    n_prime = n + 1
    S_prime = np.concatenate((np.eye(m),T.T),0).T
    A = (np.random.rand(n_prime - m, n*l) * 10).astype('int')
    E = (1 * np.random.rand(S_star.shape[0],S_star.shape[1])).astype('int')
    M = np.concatenate(((S_star - T.dot(A) + E),A),0)
    c_prime = M.dot(c_star)
    return c_prime,S_prime

def get_S_star(S,m,n,l):
    S_star = list()
    for i in range(l):
        S_star.append(S*2**(l-i-1))
    S_star = np.array(S_star).transpose(1,2,0).reshape(m,n*l)
    return S_star

def get_T(n):
    n_prime = n + 1
    T = (10 * np.random.rand(n,n_prime - n)).astype('int')
    return T

def encrypt_via_switch(x,w,m,n,T):
    c,S = switch_key(x*w,np.eye(m),m,n,T)
    return c,S

x = np.array([0,1,3,5])
m = len(x)
n = m
w = 16
S = generate_key(w,m,n)

y = np.array([3,3,3,3])
m = len(y)
n = m
w = 16
S = generate_key(w,m,n)

print(x * 10)
print(x + y)

[ 0 10 30 50]
[3 4 6 8]

T = get_T(n)
cx,S = encrypt_via_switch(x,w,m,n,T)
print(cx)
#T = get_T(n)
cy,S = encrypt_via_switch(y,w,m,n,T)
print(cy)

[-115. -122. -21. -35. 23.]
[-177. -222. -87. -177. 45.]

print(decrypt(cx,S,w))
print(decrypt(cy,S,w))

[0 1 3 5]
[3 3 3 3]

decrypt(cx * 10,S,w)

array([ 0, 10, 30, 50])

decrypt(cx + cy,S,w)

array([3, 4, 6, 8])

你可能感兴趣的:(Python,密码学)