从二选一OT到GMW协议的python实现
https://github.com/junyu33/GMW-python
implementation
2 out of 1 OT
我们先写好通过 socket 连接 Alice 和 Bob 的模板:
- Alice
1 | #!/usr/bin/python3 |
- Bob
1 | #!/usr/bin/python3 |
然后由于 socket 的等待时间略为冗长,我们将其缩短为2秒,并将初始化 socket 操作打包为一个函数:
1 | # alice.py |
然后准备实现 2 out of 1 OT 协议,显然兰老师在课堂上讲的那个协议不是抵御半恶意敌手的,因此我参照这篇文章实现了一个可以抵御的版本,基于求解离散对数的困难性:
简要描述以下协议的原理,我们考虑:
- Alice 拥有
, , 和密钥 - Bob 拥有值
,和密钥 , Bob 想获得 - Alice 和 Bob 事先统一
,并且 是一个大素数, 是 的一个原根。
那么 OT 协议可以通过如下方式演绎:
- Alice 给 Bob 发送
- 因为离散对数问题不存在高效接发,Bob 无法破译
,但可以基于 生成
- Bob 给 Alice 发送
,同样,Alice 也无法知道发来的是 还是 ,从而无法得到 Bob 选择的 . - Alice 生成
,其中外层括号表示二元组, 表示按位异或。 - Alice 给 Bob 发送
,相同原因,Bob 无法破译 - Bob 解密
,分为以下两种情况(这里中括号类似于数组下标): 时, ;而 Bob 无法解密 ,因为 ,而 Bob 不知道 . 时, ;而 Bob 无法解密 ,因为 ,而 Bob 不知道 . - 因此,Bob只能解密
,而不能解密 .
1 | # alice.py |
1 | # bob.py |
最后,为了方便之后代码的编写,我们可以将先前的代码 OOP 化:
1 | class Alice_2in1_OT: |
1 | class Bob_2in1_OT: |
2 out of 1 -> n out of 1 OT
我们考虑 Alice 持有
- Alice 生成
,随机生成 , . - 第二步, Alice 和 Bob 进行
次 操作。在第 次操作中, Alice 提供 和 。若 , Bob 选择前者; 若 , Bob 选择后者。 - 第三步, Bob 通过第 1 次至第
次 获得的 , 以及第 次获得的 即可解密 。
我们来分析上述
该实现的时间复杂度为
按照该链接的讲义,我们可以较为轻松的写出根据 2 out of 1 OT 拓展为 n out of 1 OT 的代码。有了 2in1 这一层的抽象,nin1 的实现就要简单得多了:
1 | class Alice_nin1_OT: |
1 | class Bob_nin1_OT: |
为了求稳起见,我先测试了连续两次进行 2 in 1 OT 情况,此时出现了与socket连接有关的错误,具体报错如下:
1 | ~/Desktop/old_desktop/scu/新技术专题/code master !2 21:03:47 |
从而导致Bob这边也会报 timeout 的错误:
1 | ~/Desktop/old_desktop/scu/新技术专题/code master !2 21:03:47 |
我仔细观察了一下错误信息,发现第一次的 OT
是没有问题的。我猜想问题出在了关闭 socket
连接后马上又重新打开连接时会拒绝访问(可能是 socket
的冷却时间(2s,定义于__init__
方法)还没到就进行了下一次连接)。方便起见,我把
socket 连接抽出来,作为函数参数导入进 Alice_nin1_OT
和
Bob_nin1_OT
类,并删除了run_protocol()
中关闭socket连接的代码,问题得到解决。
GMW protocol
按照上个链接的讲义,我们可以实现一个简单的安全多方计算的协议。这里选取的电路
1 | def AND(a, b): |
我们考虑最基础的情况, Alice 和 Bob 拥有一个比特的输入
- Alice 随机生成
, 并发送 给 Bob。我们将 称为 的分享值。由于 的随机性, Bob 无法破译 。 - Bob 随机生成
, 并发送 给 Alice。由于 的随机性, Alice 无法破译 。 - Alice 随机生成
, 并枚举 的所有可能值。由于 , 所以 一共有四个可能值, 即 。 - Alice 和 Bob 进行
。Alice 提供 , Bob 提供 所对应的 值。 保证了 Bob 只获得最终结果 , 以及 Alice 无从知晓 从而无从知晓 。 - Bob 将
。 - Alice 和 Bob 可以 reveal
来获得 的真实值。不难验证,
按照以上的步骤描述,我们可以写出GMW协议的具体实现:
1 | def run_protocol(self): |
1 | def run_protocol(self): |
经过测试发现可以一次性成功运行,这样我们就实现了一个完整的GMW协议。
对 GMW protocol 的改进
当然,这份代码作为一份大作业的话,工作量似乎还不太够。因此我接着打算把这份代码扩展到更多 bit 的比较,并添加加法功能。
比较多位
首先我打算
1 | def XOR(a, b): |
此时网上似乎没有讲义给我参考,我得自己魔改协议实现多位比较的功能。首先,我得把输入转化成八根wire
的形式,这里使用list
来表示:
1 | def number2list(self, number): |
然后我需要调用一次
1 | # alice.py |
并修改
1 | # alice.py |
1 | # bob.py |
实验证明,我对 python
的执行效率过于乐观,等待了2分钟也没有输出结果。于是我通过二分法,发现在
增加模 32 的加法功能
在数电课程中,我们都学过全加器的实现方式:
1 | def sum_perbit(bit1, bit2, carry_in): |
因此多位全加也很简单:
1 | # little endian |
因为输出是一个列表,我们还需要在 Alice 处实现一个将 wire
转换为数字的函数:
1 | def list2number(self, l): |
很可惜,我最初在这个函数的实现写了个bug(准确来说是加的顺序写反了,写成了res <<= 1; res += l[i]
),导致我调试了20分钟。我还一度以为
GMW
协议的电路不能实现加法运算,因为异或和加法不满足分配律,结果还是自己代码写错了,唉。
在修改comm_bit
(此时应当为
1 | def run_sum_protocol(self): |
因此,整个 GMW 的实现就大功告成了,接下来贴出最终代码:
- gates
1 | #!/usr/bin/python3 |
- Alice
1 | #!/usr/bin/python3 |
- Bob
1 | #!/usr/bin/python3 |