BFV算法原理
个人感觉 这个视频 讲得很好
上面是根据视频看得重点。
不关心编码,加密的大致步骤如下
源自 https://zhuanlan.zhihu.com/p/638191070
密钥生成
加密多项式m
解密
图片加密
注意:同态性只针对密文,图片只是密文的一种呈现,不具同态性
BFV同态加密,基于Pyfhel库实现,详细参考 Pyfhel的官方说明
主程序中修改image_path = "kun.jpg"
为你要加密的图片,可实现对图片的BFV加解密。
from PIL import Image
import numpy as np
from Pyfhel import Pyfhel
def enc_au(img_array, key):
# 2*2的数组线性化
img_L = img_array.flatten().tolist()
img_array= np.array(img_L,dtype=np.int64) #一维数组
#bfv编码和加密
ptxt_img = key.encodeInt(img_array)
ctxt_img = key.encryptPtxt(ptxt_img)
# 将ctxt 转化为 图片列表
cimg_bytes= ctxt_img.to_bytes()
cimg_L = [byte for byte in cimg_bytes] #bytes 转化为数组 数值在 0 到 256 范围内
#图片数组是一维的,转化为二维数组
one_dimensional_list = cimg_L
side_length = int(len(one_dimensional_list) ** 0.5) # 计算最接近正方形的边长
padding_count = side_length - (len(one_dimensional_list) % side_length) # 计算最后一行需要填充的个数
one_dimensional_list += [0] * (padding_count-1) # 在一维列表末尾填充0
one_dimensional_list += [padding_count]
two_dimensional_list = [one_dimensional_list[i:i+side_length] for i in range(0, len(one_dimensional_list), side_length)]
cimg_array = np.array(two_dimensional_list)
cimg_array = cimg_array.astype(np.uint8)
return cimg_array
def dec_au(encrypted_img_array, key):
enc_arr = encrypted_img_array.astype(np.int64)
enc_arr = encrypted_img_array.tolist()
enc_L = encrypted_img_array.flatten().tolist()
num_del = enc_L[-1]
enc_L = enc_L[:-1]
# 去除末尾的256
for j in range(num_del-1):
enc_L = enc_L[:-1]
flag = True
while ( flag == True):
for i in range(256):
if (enc_L[-i-1] != 0):
flag = False
break
if flag == True:
for i in range(256):
enc_L = enc_L[:-1]
else: break
byte_string = bytes(enc_L)
#创建ctxt2用于存储图片密文
ptxt2 = key.encode(2) # plaintexts created from arrays shorter than 'n' are filled with zeros.
ctxt2 = key.encrypt(ptxt2) # Alternatively you can use HE.encryptInt(arr2)
ctxt2.from_bytes(byte_string)
rctxt = key.decryptInt(ctxt2 )
one_dimensional_list = rctxt.tolist()
side_length = 128
two_dimensional_list = [one_dimensional_list[i:i+side_length] for i in range(0, len(one_dimensional_list), side_length)]
mimg_array = np.array(two_dimensional_list)
mimg_array = mimg_array.astype(np.uint8)
return mimg_array
def image_encrypt(image_path, key):
# 加载 RGB 图片
rgb_image = Image.open(image_path)
# 转换为灰度图
gray_image = rgb_image.convert('L')
# 映射到 256 灰度级
gray_image_256 = gray_image.point(lambda x: round(x * 255 / 255))
img = gray_image_256.resize((128, 128)) # 调整大小
img_array = np.array(img)
# 加密过程
encrypted_img_array = enc_au(img_array, key)
aaa=encrypted_img_array.tolist()
encrypted_img = Image.fromarray(encrypted_img_array)
encrypted_img.save("encrypted_image.png")
print("2.Image encrypted and saved as encrypted_image.png\n")
def image_decrypt(encrypted_image_path, key):
encrypted_img = Image.open(encrypted_image_path)
encrypted_img = encrypted_img.convert('L')
encrypted_img_array = np.array(encrypted_img)
# 解密过程
decrypted_img_array = dec_au(encrypted_img_array, key)
decrypted_img = Image.fromarray(decrypted_img_array)
decrypted_img.save("decrypted_image.png")
print("3.Image decrypted and saved as decrypted_image.png\n")
def Create_bfvkey():
HE = Pyfhel() # Creating empty Pyfhel object
bfv_params = {
'scheme': 'BFV', # can also be 'bfv'
'n': 2**14, # Polynomial modulus degree, the num. of slots per plaintext,
# of elements to be encoded in a single ciphertext in a
# 2 by n/2 rectangular matrix (mind this shape for rotations!)
# Typ. 2^D for D in [10, 16]
't': 256, # Plaintext modulus. Encrypted operations happen modulo t
# Must be prime such that t-1 be divisible by 2^N.
't_bits': 20, # Number of bits in t. Used to generate a suitable value
# for t. Overrides t if specified.
'sec': 128, # Security parameter. The equivalent length of AES key in bits.
# Sets the ciphertext modulus q, can be one of {128, 192, 256}
# More means more security but also slower computation.
}
HE.contextGen(**bfv_params) # Generate context for bfv scheme
HE.keyGen() # Key Generation: generates a pair of public/secret keys
# HE.relinKeyGen() # Relinearization key generation
print("\n1. Pyfhel FHE context generation")
print(f"\t{HE}\n")
return HE
# 主程序
key = Create_bfvkey()
image_path = "kun.jpg"
# pkey = 123
# skey = 123
# 加密原始图像
image_encrypt(image_path, key)
# 解密加密后的图像
encrypted_image_path = "encrypted_image.png"
image_decrypt(encrypted_image_path, key)