1. 隐语实现PIR总体介绍
隐匿查询(Private Information Retrieval PIR)定义
- 按服务器数量分类
- 单服务器方案(Single Server)
- 多服务器方案(Multi-Server)
- 按查询类型分类
- Index PIR
- Keyword PIR
隐语目前支持:
Single Server Index PIR:SealPIR
Single Server Keyword:Labeled PSI
1.1 隐语PIR调用接口:pir_setup
reports = spu.pir_setup(
server='bob',
input_path='/path/B_PIR_DATA.csv',#服务端数据文件路径,建议绝对路径
key_columns='id',#Key对应的列名
label_columns=['register_date','age'],#Label对应的列名。多列,用逗号隔开
oprf_key_path='/path/oprf_key.bin',#服务端ecc密钥文件,32B,二进制文件
setup_path='/path/setup_path',
num_per_query=1,#每次查询的id数量
label_max_len=18#Label数据拼接后填充到固定的长度大小
)
1.2 隐语PIR调用接口:pir_query
#client--alice
alice_config={
'input_path':'/path/A_PIR_ID.csv',#查询id对应的csv文件路径
'key_columns':'id',#key对应的列名
'output_path':'/path/sf_pir_out.csv',#PIR查询结果输出的文件路径
}
#server
bob_config = {
oprf_key_path='/path/oprf_key.bin',#服务端ecc密钥文件,32B,二进制文件
setup_path='/path/setup_path',#预处理阶段结果输出路径
}
query_config={
alice:alice_config
bob:bob_config
}
reports=spu.pir_query(
server='bob',
config=query_config
)
2. Index PIR-SealPIR介绍
Index PIR 是一种隐私信息检索(Private Information Retrieval, PIR)技术,它允许用户从服务器检索特定数据项而不泄露他们所查询的内容。在基于索引的PIR中,用户可以通过索引值来秘密地获取数据库中的记录,而服务器无法知道用户实际请求的是哪个索引对应的记录。
SealPIR 则是一种具体实现隐私信息检索的协议,它基于同态加密(Homomorphic Encryption, HE)技术,特别是在SEAL(Simple Encrypted Arithmetic Library)框架下实现的一种高效PIR方案。SealPIR使得用户可以在不解密服务器数据库的情况下,对加密数据执行查询操作,并获得加密形式的查询结果,然后用户可以安全地解密得到所需的真实数据,整个过程保证了用户的查询隐私。
SealPIR结合了现代密码学的进步,尤其是同态加密技术的优势,提供了一种更为安全和高效的隐私保护机制,适用于那些对数据隐私有严格要求的场景,比如云存储环境下的数据查询服务等。随着同态加密技术的不断成熟,基于此类技术的PIR协议如SealPIR,在隐私保护和效率之间找到了更好的平衡点,从而推动了隐私计算领域的发展。
3. Keyword PIR-Labeled PSI介绍
Labeled PSI (Private Set Intersection with Labeling) 是Keyword PIR中的一种具体技术实现,主要用于解决两个或多方参与者的私人集合交集问题,但增加了关键词标签的功能。在Labeled PSI中,每个参与者不仅拥有一个元素集合,而且这些元素还带有标签(关键词)。当两个参与者希望找出他们的集合中共有的元素(及对应的标签)时,可以使用Labeled PSI协议来完成这一任务,且过程中不会暴露各自的非共有元素信息。
Labeled PSI通常基于密码学技术,例如基于多方计算(MPC)、同态加密(HE)、混淆电路(Garbled Circuits)或其他零知识证明(Zero-Knowledge Proofs)的方法来设计。其中,某些Labeled PSI方案可能会利用插值多项式或其他数学工具进行优化,以便更高效地处理大规模数据集上的关键词匹配查询。
例如,Labeled PSI可能的工作流程包括:
用户将关键词加密并构建查询对象。
数据持有者用类似的技术加密其数据库中的关键词。
双方通过交互协议计算出在各自加密数据中有交集的关键词,而不揭露任何一方的具体关键词列表或多余的交集信息。
4. 代码实践
4.1. 查询一个没有使用的端口
import socket
from contextlib import closing
from typing import cast
def unused_tcp_port() -> int:
"""return an unused port"""
with closing(socket.socket(socket.AF_INET,socket.SOCK_STREAM)) as sock:
sock.bind(("",0))
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
return cast(int,sock.getsockname()[1])
print(unused_tcp_port())
4.2. 初始化alice节点
import secretflow as sf
cluster_conf = {
'parties': {
'alice': {
'address': 'ip:8000',#对外使用的地址
'listen_addr': '0.0.0.0:59181'#对内的
},
'bob': {
'address': 'ip:8001',#对外使用的地址
'listen_addr': '0.0.0.0:8001'#对内的
},
},
'self_party': 'alice'
}
sf.shutdown()
sf.init(address='local', cluster_config=cluster_conf)
4.3. 初始化bob节点
import secretflow as sf
cluster_conf = {
'parties': {
'alice': {
'address': 'ip:8000',#对外使用的地址
'listen_addr': '0.0.0.0:59181'#对内的
},
'bob': {
'address': 'ip:8001',#对外使用的地址
'listen_addr': '0.0.0.0:8001'#对内的
},
},
'self_party': 'bob'
}
sf.shutdown()
sf.init(address='local', cluster_config=cluster_conf)
4.4. 初始化spu
import spu
import secretflow as sf
spu_conf = {
"nodes": [
{
"party": "alice",
"address": "alice:8001",
"listen_addr": "alice:8001",
},
{
"party": "bob",
"address": "bob:8001",
"listen_addr": "bob:8001",
},
],
"runtime_config": {
"protocol": spu.spu_pb2.SEMI2K,
"field": spu.spu_pb2.FM128,
"sigmoid_mode": spu.spu_pb2.RuntimeConfig.SIGMOID_REAL,
},
}
spu = sf.SPU(
cluster_def=spu_conf,
link_desc={
"connect_retry_times":60,
"connect_retry_interval_ms":1000
}
)
4.5.RIP
alice做服务端,bob作为客户端。
进入alice的secretnote服务器端运行命令: openssl rand 32 > ~/alice_oprf_key
准备数据
# alice端
import pandas as pd
from pathlib import Path
alice_df = pd.DataFrame({
"name":["alice","bob","carol","tony"],
"age":[11,13,14,26]
})
alice_df.to_csv(f"{str(Path.home())}/alice_pir_input.csv",index=False)
# bob端
import pandas as pd
from pathlib import Path
bob_df = pd.DataFrame({
"name":["tony","bob"],
})
bob_df.to_csv(f"{str(Path.home())}/bob_pir_query.csv",index=False)
import spu
spu.pir_setup(
server="alice",
input_path=f"{str(Path.home())}/alice_pir_input.csv",
key_columns=["name"],
label_columns=["age"],
oprf_key_path=f"{str(Path.home())}/alice_oprf_key",
setup_path=f"{str(Path.home())}/alice_setup",#中间结果存储路径
num_per_query=1,
label_max_len=20,
bucket_size=1000000
)
spu.pir_query(
server='alice',
client='bob',
server_setup_path=f"{str(Path.home())}/alice_setup",
client_key_colums=["name"],
client_input_path=f"{str(Path.home())}/bob_pir_query.csv",
client_output_path=f"{str(Path.home())}/bob_pir_result.csv",
)