隐私求交(Private Set Intersection)是一种使用密码学方法,获取两份数据内容的交集的算法。PSI过程中不泄露任务交集以外的信息。
在隐语中,SPU设备支持三种隐私求交算法:
ECDH:半诚实模型, 基于公钥密码学,适用于小数据集。
KKRT:半诚实模型, 基于布谷鸟哈希(Cuckoo Hashing)以及高效不经意传输扩展(OT Extension),适用于大数据集。
BC22PCG:半诚实模型, 基于随机相关函数生成器。
1. ECDH-PSI (两方)
半诚实模型的DH-PSI协议在 Huberman, Franklin, and Hogg 中提出,但最早可以追溯到Meadows。DH-PSI协议对数据集中的数据进行指数(点乘)运算。
DH-PSI 协议基于判定Diffie-Hellman假设:
选取群 G, 和生成元 g
假设: 对于随机数 a,b,c 不能区分
可以选择的群包括有限域上的乘法群和椭圆曲线上的加法群。实际应用中,综合性能和安全方面比较,通常选取椭圆曲线群,例如: Curve25519 [Ber06]。
KKRT16-PSI
[KKRT16] 是半诚实 OT-based PSI协议,基于 OT Extension, BaRK-OPRF 和 CuckooHash。 [KKRT16] 是第一个在千万规模,长度(128 bits)数据集上,求交时间在1分钟之内的PSI协议.
隐语 SPU PSI 中使用了 [PSZ18] 提到的 3-way stash-less CuckooHash。
BC22 PCG-PSI
伪随机相关生成器(Pseudorandom Correlation Generator PCG), 是 Boyle等人在一系列论文 [BCG+19b], [BCGI18], [SGRR19], [BCG+19a], [CIK+20] 中引入的一种密码协议。PCG的优势在于可以将满足特定相关条件的随机数,在不影响安全的前提下进行压缩.
Boyle 等人设计了一系列满足特定相关性的高效PCG协议, 例如: vector oblivious linear evaluation (VOLE) 或者batch oblivious linear evaluation (BOLE)。这些基础的密码原语是现代安全多方计算中的核心组件,可以显著降低通信量。基于LPN假设,PCG/VOLE 函数,Receiver 和Sender得到一组满足线性关系的分量,通信量是亚线性的。
基于ecdh-OPRF的PSI协议
不经意伪随机函数(Oblivious Pseudorandom Function OPRF)是一个两方协议,客户端和服务端通过执行协议计算伪随机函数(Pseudorandom Function PRF)的结果。RFC 草案 [draft-irtf-cfrg-voprf-10] 基于素数阶群,给出了OPRF, VOPRF, and POPRF 的构造方案。
隐语PSI开发指南
代码:
import os
import sys
import time
import logging
import multiprocess
from absl import app
import spu
import secretflow as sf
#ray start --head --node-ip-address="xxx.xxx.56.xx" --port="25673" --include-dashboard=False --disable-usage-stats
# In case you have a running secretflow runtime already.
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
tls_config ={
"ca_cert": "/home/fate01/code/secretflow-code/certificate/cert/bob_ca.crt",
"cert": "/home/fate01/code/secretflow-code/certificate/cert/alice_ca.crt",
"key": "/home/fate01/code/secretflow-code/certificate/cert/alice_ca.key",
}
cluster_config ={
'parties': {
'alice': {
# replace with alice's real address.
'address': 'xxx.xxx.56.xx:9923',
'listen_addr': '0.0.0.0:9923'
},
'bob': {
# replace with bob's real address.
'address': 'xxx.xxx.56.xx:9924',
'listen_addr': '0.0.0.0:9924'
},
},
'self_party': 'alice'
}
sf.init(address='xxx.xxx.56.xx', cluster_config=cluster_config,tls_config=tls_config)
# sf.init(address='xxx.xxx.56.xx:25673', cluster_config=cluster_config)
alice= sf.PYU('alice')
bob= sf.PYU('bob')
# your code to run.
cluster_def={
'nodes': [
{
'party': 'alice',
'id': 'alice',
# Please choose an unused port.
'address': 'xxx.xxx.56.xx:25676',
'listen_addr': '0.0.0.0:25676'
},
{
'party': 'bob',
'id': 'bob',
# Please choose an unused port.
'address': xxx.xxx.56.xx:25176',
'listen_addr': '0.0.0.0:25176'
},
],
'runtime_config': {
'protocol': spu.spu_pb2.CHEETAH,
'field': spu.spu_pb2.FM32,
'sigmoid_mode': spu.spu_pb2.RuntimeConfig.SIGMOID_REAL,
}
}
link_desc = {
'recv_timeout_ms': 36000,
}
start = time.time()
spu = sf.SPU(cluster_def=cluster_def,link_desc=link_desc)
input_path = {
alice: '/home/fate01/code/secretflow-code/database/psi_alice.csv', bob: '1'}
output_path = {
alice: '.data/1_psi.csv', bob: '.data/2_psi.csv'}
spu.psi_csv('id', input_path, output_path, 'alice',protocol='ECDH_PSI_2PC',curve_type="CURVE_FOURQ",bucket_size=1<<30)
#spu.psi_csv('id', input_path, output_path, 'alice',protocol='BC22_PSI_2PC')
logging.info(f"IO times: {time.time() - start}s")