用Python和libOTe库,5分钟实现一个不经意传输(OT)协议Demo
用Python和libOTe库5分钟实现不经意传输(OT)协议Demo
想象一下这样的场景:你需要从服务器获取某个特定数据,但不想让服务器知道你选择了哪个数据;同时服务器也希望只提供你选择的数据,而不是全部泄露。这种看似矛盾的需求,正是**不经意传输(Oblivious Transfer, OT)**协议要解决的经典问题。
OT协议作为现代密码学的基石之一,在隐私计算、安全多方计算等领域有着广泛应用。今天我们将使用Python的libOTe库,快速实现一个1-out-of-2 OT协议的Demo,让你在5分钟内看到这个神奇协议的实际运行效果。
1. 环境准备与库安装
在开始编码前,我们需要准备好Python环境和必要的依赖库。libOTe是一个高效的OT协议实现库,支持多种OT变体。
首先确保你已安装Python 3.7或更高版本。然后通过pip安装libOTe:
pip install libote
此外,我们还需要一些辅助库:
pip install numpy cryptography
注意:libOTe在某些平台上可能需要额外的编译工具。如果安装遇到问题,可以尝试先安装CMake和g++/clang等编译器。
安装完成后,可以通过以下命令验证是否安装成功:
import libote
print(libote.__version__)
如果输出版本号而没有报错,说明环境已准备就绪。
2. 理解1-out-of-2 OT协议
在编写代码前,让我们快速回顾1-out-of-2 OT协议的基本原理:
- 发送方(Sender) :持有两个消息m₀和m₁
- 接收方(Receiver) :希望获取其中一个消息m_c(c∈{0,1}),但不透露c的选择
- 协议保证 :
- 接收方只能获取m_c,无法得知另一个消息
- 发送方无法确定接收方选择了哪个消息
这种协议在隐私保护数据查询、安全机器学习等场景中非常有用。下面我们将用libOTe实现这一协议。
3. 实现基础OT协议
libOTe提供了多种OT实现,我们先从最基本的Naor-Pinkas OT开始。创建一个新的Python文件 ot_demo.py ,添加以下代码:
import numpy as np
from libote import NaorPinkasOT, OTReceiver, OTSender
def run_naor_pinkas_ot():
# 初始化OT协议
ot = NaorPinkasOT()
# 发送方的两个消息
messages = [b"这是消息0", b"这是消息1"]
# 接收方的选择 (0或1)
choice = 1
# 模拟网络通信的简单缓冲区
send_buf = bytearray(1024)
recv_buf = bytearray(1024)
# 发送方和接收方初始化
sender = OTSender(ot)
receiver = OTReceiver(ot)
# 协议执行流程
# 第一步:接收方发送初始消息
receiver.send(send_buf)
recv_buf[:len(send_buf)] = send_buf
# 第二步:发送方处理接收方的消息并回复
sender.recv(recv_buf)
sender.send(send_buf, messages)
recv_buf[:len(send_buf)] = send_buf
# 第三步:接收方获取最终结果
result = receiver.recv(recv_buf, choice)
print(f"接收方选择获取消息{choice}, 实际获得: {result.decode()}")
if __name__ == "__main__":
run_naor_pinkas_ot()
运行这个脚本,你会看到接收方成功获取了选择的消息,而发送方并不知道接收方选择了哪个消息。
4. 使用更高效的OT扩展
基础OT协议虽然简单,但在实际应用中性能不够理想。libOTe提供了更高效的OT扩展实现,让我们看看如何改进:
from libote import IKNPOTExt
def run_ot_extension():
# 初始化OT扩展协议
ot_ext = IKNPOTExt()
# 批量处理128个OT
batch_size = 128
# 发送方准备128对消息
messages = [(f"消息{i}_0".encode(), f"消息{i}_1".encode())
for i in range(batch_size)]
# 接收方的128个选择 (0或1)
choices = np.random.randint(0, 2, batch_size, dtype=bool)
# 初始化发送方和接收方
sender = OTSender(ot_ext)
receiver = OTReceiver(ot_ext)
# 执行协议
# 1. 基础OT阶段
send_buf = bytearray(1024)
receiver.send(send_buf)
sender.recv(send_buf)
# 2. OT扩展阶段
sender.send(messages)
results = receiver.recv(choices)
# 验证结果
for i in range(5): # 只打印前5个结果
expected = messages[i][choices[i]].decode()
print(f"选择{choices[i]}, 获取: {results[i].decode()}, 应得: {expected}")
run_ot_extension()
OT扩展技术通过少量基础OT和对称加密操作,实现了大量OT的高效执行,性能比直接使用基础OT提升几个数量级。
5. 实际应用:隐私保护数据查询
让我们看一个更实际的例子:隐私保护的数据库查询。假设有一个医疗数据库,用户想查询自己的某项检测结果,但不想透露查询的是哪项检测。
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
class PrivacyPreservingQuery:
def __init__(self):
self.ot = IKNPOTExt()
def setup_database(self):
# 模拟医疗检测结果数据库
self.tests = {
"血糖": "血糖值: 5.2 mmol/L (正常)",
"胆固醇": "总胆固醇: 4.8 mmol/L (正常)",
"血压": "血压: 120/80 mmHg (正常)"
}
self.test_names = list(self.tests.keys())
def run_query(self, test_index):
# 数据库方(发送方)
def sender_process():
sender = OTSender(self.ot)
# 将每个检测结果转换为OT消息对
messages = []
for name in self.test_names:
# 使用HKDF派生密钥加密结果
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=b'medical record',
)
key = hkdf.derive(name.encode())
encrypted = bytes(a ^ b for a, b in zip(
self.tests[name].encode(), key))
# 每个检测名称对应一对(加密结果, 空消息)
messages.append((encrypted, b""))
# 执行OT协议
send_buf = bytearray(1024)
sender.recv(send_buf) # 接收初始消息
sender.send(messages) # 发送加密结果
return sender
# 用户方(接收方)
def receiver_process():
receiver = OTReceiver(self.ot)
# 发送初始消息
send_buf = bytearray(1024)
receiver.send(send_buf)
# 执行OT获取结果
choices = [False] * len(self.test_names)
choices[test_index] = True # 只选择感兴趣的检测
results = receiver.recv(choices)
# 解密结果
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=b'medical record',
)
key = hkdf.derive(self.test_names[test_index].encode())
decrypted = bytes(a ^ b for a, b in zip(results[test_index], key))
return decrypted.decode()
return sender_process(), receiver_process()
# 使用示例
ppq = PrivacyPreservingQuery()
ppq.setup_database()
# 用户想查询"胆固醇"结果(索引1)
_, result = ppq.run_query(1)
print("查询结果:", result)
这个例子展示了OT协议如何在实际应用中保护双方的隐私:用户获取了需要的检测结果,而数据库方不知道用���查询的是哪项检测。
6. 性能优化与注意事项
在实际使用OT协议时,性能是需要重点考虑的因素。以下是一些优化建议:
- 批量处理 :OT扩展技术最适合批量处理大量OT,尽量将多个OT合并执行
- 网络优化 :减少通信轮次,使用高效的序列化格式
- 参数选择 :根据安全需求选择适当的参数,不必过度安全
libOTe提供了一些内置的优化功能:
from libote import SilentOT
def run_silent_ot():
# 静默OT进一步优化了通信量
ot = SilentOT()
# 准备1000个OT
n = 1000
messages = [(os.urandom(32), os.urandom(32)) for _ in range(n)]
choices = np.random.randint(0, 2, n, dtype=bool)
sender = OTSender(ot)
receiver = OTReceiver(ot)
# 执行协议
receiver.send(bytearray(1024))
sender.recv(bytearray(1024))
sender.send(messages)
results = receiver.recv(choices)
# 验证
for i in range(n):
assert results[i] == messages[i][choices[i]]
run_silent_ot()
提示:在生产环境中使用OT协议时,还需要考虑恶意敌手安全、协议可组合性等高级特性。libOTe也支持这些功能,但配置会更复杂。
更多推荐
所有评论(0)