如何通过PySeal库加密数据框列
How to encrypt data frame column through PySeal library
我正在研究全同态加密。由于只有完全同态加密才允许对加密数据执行计算,并且此机制由 PySeal 库提供,该库是 Microsoft SEAL 库的 python 分支版本。我的数据框中有 3 列。我想使用 PySeal 加密每一列的每个值,我可以对这些值进行计算。
df
| SNP | ID | Effect|
|:---- |:------:| -----:|
| 21515| 1 | 0.5 |
| 21256| 2 | 0.7 |
| 21286| 3 | 1.7 |
PySeal的相关文档:https://github.com/Lab41/PySEAL/blob/master/SEALPythonExamples/examples.py
有趣的问题,我可以帮助您将库与 pandas 一起使用,但不能帮助您设置像模数这样的安全加密参数。
首先让我们做一些导入:
import pandas
import seal
from seal import Ciphertext, \
Decryptor, \
Encryptor, \
EncryptionParameters, \
Evaluator, \
IntegerEncoder, \
FractionalEncoder, \
KeyGenerator, \
Plaintext, \
SEALContext
现在我们设置加密参数。我不知道如何正确设置这些值,但正确设置值对于实现适当的安全性很重要。文档中的引述:
It is critical to understand how these different parameters behave, how they affect the encryption scheme, performance, and the security level... due to the complexity of this topic, we highly recommend the user to directly consult an expert in homomorphic encryption and RLWE-based encryption schemes to determine the security of their parameter choices.
parms = EncryptionParameters()
parms.set_poly_modulus("1x^2048 + 1")
parms.set_coeff_modulus(seal.coeff_modulus_128(2048))
parms.set_plain_modulus(1 << 8)
context = SEALContext(parms)
接下来我们将设置密钥、编码器、加密器和解密器。
iEncoder = IntegerEncoder(context.plain_modulus())
fEncoder = FractionalEncoder(
context.plain_modulus(), context.poly_modulus(), 64, 32, 3)
keygen = KeyGenerator(context)
public_key = keygen.public_key()
secret_key = keygen.secret_key()
encryptor = Encryptor(context, public_key)
evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)
让我们设置一些方便的函数,我们将使用 DataFrames 来加密和解密。
def iencrypt(ivalue):
iplain = iEncoder.encode(ivalue)
out = Ciphertext()
encryptor.encrypt(iplain, out)
return out
def fencrypt(fvalue):
fplain = fEncoder.encode(fvalue)
out = Ciphertext()
encryptor.encrypt(fplain, out)
return out
最后,我们将定义一个可以与 pandas 一起使用的整数乘法运算。为了让这个答案简短,我们不会演示对浮点数的操作,但应该不难做到。
def i_multiplied(multiplier):
m_plain = iEncoder.encode(multiplier)
out = Ciphertext()
encryptor.encrypt(m_plain, out)
def aux(enc_value):
# this is an in-place operation, so there is nothing to return
evaluator.multiply(enc_value, out)
return aux
请注意,Evaluator.multiple 是一个就地操作,因此当我们将它与 DataFrame 一起使用时,它会改变内部的值!
现在让我们开始工作:
df = pandas.DataFrame(dict(
SNP=[21515, 21256, 21286],
ID=[1, 2, 3],
Effect=[0.5, 0.7, 1.7])
)
print("Input/Plaintext Values:")
print(df.head())
这将打印您的示例:
Input/Plaintext Values:
SNP ID Effect
0 21515 1 0.5
1 21256 2 0.7
2 21286 3 1.7
现在让我们制作一个加密的数据帧:
enc_df = pandas.DataFrame(dict(
xSNP=df['SNP'].apply(iencrypt),
xID=df['ID'].apply(iencrypt),
xEffect=df['Effect'].apply(fencrypt))
)
print("Encrypted Values:")
print(enc_df.head())
打印:
加密值:
_ xSNP
0 <seal.Ciphertext object at 0x7efcccfc2df8> <seal.Ciphertext object a
1 <seal.Ciphertext object at 0x7efcccfc2d88> <seal.Ciphertext object a
2 <seal.Ciphertext object at 0x7efcccfc2dc0> <seal.Ciphertext object a
这只是 DataFrame 中的一堆对象。
现在我们来做个手术
# multiply in place
enc_df[['xSNP','xID']].applymap(i_multiplied(2))
print("Encrypted Post-Op Values:")
print(enc_df.head())
此时您不会注意到打印的值有差异,因为我们所做的只是改变数据框中的对象,所以它只会打印相同的内存引用。
现在解密看看结果:
enc_df[['xSNP','xID']]=enc_df[['xSNP','xID']].applymap(idecrypt)
print("Decrypted Post-Op Values:")
print(enc_df[['xSNP','xID']].head())
这会打印:
Decrypted Post-Op Values:
xSNP xID
0 43030 2
1 42512 4
2 42572 6
这是您期望将整数列乘以 2 的结果。
要实际使用它,您必须先序列化加密的数据帧,然后再发送给另一方进行处理,然后返回给您进行解密。图书馆强制您使用 pickle 来执行此操作。从安全的角度来看,这是不幸的,因为你 should never unpickle untrusted data。服务器能否相信客户端不会在 pickle 序列化中放置任何令人讨厌的东西,并且客户端能否相信服务器在 returns 回答时不会做同样的事情?一般来说,两者的答案是否定的,更多 - 因为客户端已经不信任服务器,否则它不会使用同态加密!显然,这些 python 绑定更像是一种技术演示,但我认为值得指出这一限制。
库中有批量操作,我没有演示。这些在 DataFrame 的上下文中使用可能更有意义,因为它们对于许多值的操作应该具有更好的性能。
我正在研究全同态加密。由于只有完全同态加密才允许对加密数据执行计算,并且此机制由 PySeal 库提供,该库是 Microsoft SEAL 库的 python 分支版本。我的数据框中有 3 列。我想使用 PySeal 加密每一列的每个值,我可以对这些值进行计算。
df
| SNP | ID | Effect|
|:---- |:------:| -----:|
| 21515| 1 | 0.5 |
| 21256| 2 | 0.7 |
| 21286| 3 | 1.7 |
PySeal的相关文档:https://github.com/Lab41/PySEAL/blob/master/SEALPythonExamples/examples.py
有趣的问题,我可以帮助您将库与 pandas 一起使用,但不能帮助您设置像模数这样的安全加密参数。
首先让我们做一些导入:
import pandas
import seal
from seal import Ciphertext, \
Decryptor, \
Encryptor, \
EncryptionParameters, \
Evaluator, \
IntegerEncoder, \
FractionalEncoder, \
KeyGenerator, \
Plaintext, \
SEALContext
现在我们设置加密参数。我不知道如何正确设置这些值,但正确设置值对于实现适当的安全性很重要。文档中的引述:
It is critical to understand how these different parameters behave, how they affect the encryption scheme, performance, and the security level... due to the complexity of this topic, we highly recommend the user to directly consult an expert in homomorphic encryption and RLWE-based encryption schemes to determine the security of their parameter choices.
parms = EncryptionParameters()
parms.set_poly_modulus("1x^2048 + 1")
parms.set_coeff_modulus(seal.coeff_modulus_128(2048))
parms.set_plain_modulus(1 << 8)
context = SEALContext(parms)
接下来我们将设置密钥、编码器、加密器和解密器。
iEncoder = IntegerEncoder(context.plain_modulus())
fEncoder = FractionalEncoder(
context.plain_modulus(), context.poly_modulus(), 64, 32, 3)
keygen = KeyGenerator(context)
public_key = keygen.public_key()
secret_key = keygen.secret_key()
encryptor = Encryptor(context, public_key)
evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)
让我们设置一些方便的函数,我们将使用 DataFrames 来加密和解密。
def iencrypt(ivalue):
iplain = iEncoder.encode(ivalue)
out = Ciphertext()
encryptor.encrypt(iplain, out)
return out
def fencrypt(fvalue):
fplain = fEncoder.encode(fvalue)
out = Ciphertext()
encryptor.encrypt(fplain, out)
return out
最后,我们将定义一个可以与 pandas 一起使用的整数乘法运算。为了让这个答案简短,我们不会演示对浮点数的操作,但应该不难做到。
def i_multiplied(multiplier):
m_plain = iEncoder.encode(multiplier)
out = Ciphertext()
encryptor.encrypt(m_plain, out)
def aux(enc_value):
# this is an in-place operation, so there is nothing to return
evaluator.multiply(enc_value, out)
return aux
请注意,Evaluator.multiple 是一个就地操作,因此当我们将它与 DataFrame 一起使用时,它会改变内部的值!
现在让我们开始工作:
df = pandas.DataFrame(dict(
SNP=[21515, 21256, 21286],
ID=[1, 2, 3],
Effect=[0.5, 0.7, 1.7])
)
print("Input/Plaintext Values:")
print(df.head())
这将打印您的示例:
Input/Plaintext Values:
SNP ID Effect
0 21515 1 0.5
1 21256 2 0.7
2 21286 3 1.7
现在让我们制作一个加密的数据帧:
enc_df = pandas.DataFrame(dict(
xSNP=df['SNP'].apply(iencrypt),
xID=df['ID'].apply(iencrypt),
xEffect=df['Effect'].apply(fencrypt))
)
print("Encrypted Values:")
print(enc_df.head())
打印:
加密值:
_ xSNP
0 <seal.Ciphertext object at 0x7efcccfc2df8> <seal.Ciphertext object a
1 <seal.Ciphertext object at 0x7efcccfc2d88> <seal.Ciphertext object a
2 <seal.Ciphertext object at 0x7efcccfc2dc0> <seal.Ciphertext object a
这只是 DataFrame 中的一堆对象。
现在我们来做个手术
# multiply in place
enc_df[['xSNP','xID']].applymap(i_multiplied(2))
print("Encrypted Post-Op Values:")
print(enc_df.head())
此时您不会注意到打印的值有差异,因为我们所做的只是改变数据框中的对象,所以它只会打印相同的内存引用。
现在解密看看结果:
enc_df[['xSNP','xID']]=enc_df[['xSNP','xID']].applymap(idecrypt)
print("Decrypted Post-Op Values:")
print(enc_df[['xSNP','xID']].head())
这会打印:
Decrypted Post-Op Values:
xSNP xID
0 43030 2
1 42512 4
2 42572 6
这是您期望将整数列乘以 2 的结果。
要实际使用它,您必须先序列化加密的数据帧,然后再发送给另一方进行处理,然后返回给您进行解密。图书馆强制您使用 pickle 来执行此操作。从安全的角度来看,这是不幸的,因为你 should never unpickle untrusted data。服务器能否相信客户端不会在 pickle 序列化中放置任何令人讨厌的东西,并且客户端能否相信服务器在 returns 回答时不会做同样的事情?一般来说,两者的答案是否定的,更多 - 因为客户端已经不信任服务器,否则它不会使用同态加密!显然,这些 python 绑定更像是一种技术演示,但我认为值得指出这一限制。
库中有批量操作,我没有演示。这些在 DataFrame 的上下文中使用可能更有意义,因为它们对于许多值的操作应该具有更好的性能。