【安全多方计算】百万富翁问题

前导知识

判断素数

素数:除了1和它本身以外不再有其他的因数,且大于1的自然数。
定理:若x是素数,那么x的最小质因数y≤sqrt(x)sqrt(x)指对x开根号。

【代码实现】

import math
def is_prime(x: int):
    '''
    判断x是否为素数
    '''
    if x <= 1:
        raise ValueError("0和1既不是素数也不是合数,x应为大于1的正整数")
    for i in range(2, int(math.sqrt(x))+1):
        if x % i == 0:
            return False
    return True

欧几里得求最大公约数

g c d ( a , b ) = g c d ( b , a % b ) = … = g c d ( ∗ , 0 ) , ∗ 即为 a 和 b 的最大公约数 gcd(a, b) = gcd(b, a\%b) = … = gcd(*, 0), *即为a和b的最大公约数 gcd(a,b)=gcd(b,a%b)==gcd(,0),即为ab的最大公约数

图解计算过程

Created with Raphaël 2.3.0 开始 输入a, b a,b = b, a%b b=0? 输出最大公约数a 结束 yes no

【代码实现】

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)

Python的math库也内置了函数可以求解

import math
print(math.gcd(6,9))

扩展欧几里得求乘法逆元

两个不完全为0的整数a、b,存在满足 a x + b y = g c d ( a , b ) ax+by=gcd(a, b) ax+by=gcd(a,b)的一组解x、y。
g c d ( a , b ) = 1 gcd(a, b)=1 gcd(a,b)=1时,满足
a ∗ x = 1   m o d   b b ∗ y = 1   m o d   a a*x=1\ mod\ b \\ b*y=1\ mod\ a ax=1 mod bby=1 mod a
而求解x、y,我们使用扩展欧几里得算法。
g c d ( a , b ) = a ∗ x 1 + b ∗ y 1    ( 1 ) g c d ( b , a   m o d   b ) = b ∗ x 2 + ( a   m o d   b ) ∗ y 2    ( 2 ) g c d ( a   m o d   b , b   m o d ( a   m o d   b ) ) = ( a   m o d   b ) ∗ x 3 + ( b   m o d ( a   m o d   b ) ) ∗ y 3    ( 3 ) ⋮ g c d ( 1 , 0 ) = x n    ( n ) gcd(a,b)=a*x_1+b*y_1 \ \ (1) \\ gcd(b, a\ mod\ b)=b*x_2 + (a\ mod\ b)*y_2 \ \ (2) \\ gcd(a\ mod\ b, b\ mod(a\ mod\ b)) = (a\ mod\ b)*x_3 + (b\ mod(a\ mod\ b))*y_3 \ \ (3) \\ \vdots \\ gcd(1, 0) = x_n \ \ (n) gcd(a,b)=ax1+by1  (1)gcd(b,a mod b)=bx2+(a mod b)y2  (2)gcd(a mod b,b mod(a mod b))=(a mod b)x3+(b mod(a mod b))y3  (3)gcd(1,0)=xn  (n)
由(1)、(2)得 x 1 = y 2 , y 1 = x 2 − [ a b ] ∗ y 2 x_1=y_2, y1=x_2 -[\cfrac{a}{b}]*y_2 x1=y2,y1=x2[ba]y2,由此可得,递归出口是(n)中的 a = 1 , b = 0 a=1,b=0 a=1,b=0,我们可以就用代码实现求解了

def expandEuclid(a, b):
    '''
    a*x = 1 mod b
    b*y = 1 mod a
    已知a、b,返回x, y
    '''
    if b == 0:
        return 1, 0
    else:
        x2, y2 = expandEuclid(b, a % b)
        x1, y1 = y2, x2 - a // b * y2
    return x1, y1

生成公钥和私钥

  1. 随机生成两个大素数 p 、 q ( p ! = q ) p、q(p!=q) pq(p!=q)
  2. n = p ∗ q ,   s = ( p − 1 ) ∗ ( q − 1 ) n=p*q,\ s=(p-1)*(q-1) n=pq, s=(p1)(q1)
  3. 随机取一个大整数 e e e 2 ≤ e ≤ s − 1 2≤e≤s-1 2es1 g c d ( e , s ) = 1 gcd(e, s) = 1 gcd(e,s)=1
  4. 用扩展欧几里得算法求 e e e的乘法逆元 d ( e ∗ d = 1   m o d   s , d > 0 ) d(e*d=1\ mod\ s, d>0) d(ed=1 mod s,d>0)
  5. 公钥为 ( n , e ) (n, e) (n,e),私钥为 ( n , d ) (n, d) (n,d)

百万富翁问题

问题

  有两个喜欢攀比的百万富翁Alice和Bob。有一天他们相遇了,他们想要跟对方比比看谁更有钱,但是又不想让对方知道自己有多少钱。
  问:如果在不借助第三方的情况下,知道谁更有钱?

解决思路

Alice Bob 财富为i 财富为j 选择一个随机大整数x 约定加密算法(此处我们约定RSA公钥加密算法) 同意并确认 loop 生成公钥(e, n)和私钥(d, n) 发送公钥(e, n) 根据公钥和加密函数E,计算C = E(x) 发送C-i 根据私钥和解密函数D,计算Y(u) = D(C-i+u) (0<u<=100) 选择一个小于x的大整数p 将Y(u) mod p得到Z(u)。对于所有的u,满足0<Z(u)<p-1,若不满足则更换p重新计算 loop 将Z(u)从第j-1位开始向右均+1得到K(u) 将K(u)和p发给Alice 将K[i-1]与x mod p进行比较。如果相等,则说明i<j,即Alice不如Bob富有 若不相等,则说明i>=j,说明Alice比BOb富有或者和Bob一样富有 Alice Bob

代码实现

Python的简单实现代码如下(i和j的取值为1-10)

import random
import math
# Alice的财富为i,Bob的财富为j,取值为0~10
# Alice选择一个随机大整数x
# Alice和Bob约定使用RSA算法
# Bob用RSA算法生成公钥和私钥,将公钥发给Alice
# Alice使用Bob的公钥加密x得C=E(x),并发送C-i给Bob
# Bob使用私钥计算Y(u) = D(C-i+u) (1<=u<=10)
# Bob随机取一个小于x的大整数p,将Y(u) mod p得到Z(u),验证对所有Z(u)都满足0<Z(u)<p-1。若不满足则更换p重新计算
# 再将Z(u)从第j-1位开始向右均+1得到K(u),然后将K(u)和p发给Alice
# Alice将K[i-1]与(x mod p)进行比较,如果相等,则说明i<j,即Alice不如Bob富有;若不相等,则说明i>=j,说明Alice比BOb富有或者和Bob一样富有


def is_prime(x: int):
    '''
    判断x是否为素数
    '''
    if x <= 1:
        raise ValueError("0和1既不是素数也不是合数,x应为大于1的正整数")
    for i in range(2, int(math.sqrt(x))+1):
        if x % i == 0:
            return False
    return True


def get_inverse(a, b):
    '''
    a*x = 1 mod b
    b*y = 1 mod a
    已知a、b,返回x, y
    '''
    if b == 0:
        return 1, 0
    else:
        x2, y2 = get_inverse(b, a % b)
        x1, y1 = y2, x2 - a // b * y2
    return x1, y1


def create_key():
    '''
    创建公钥和私钥
    '''
    while True:
        p = random.randint(10**1, 10**2)
        if is_prime(p):
            break
    while True:
        q = random.randint(10**1, 10**2)
        if is_prime(q) and q != p:
            break
    n, s = p*q, (p-1)*(q-1)
    print(f"n={n}, s={s}")
    while True:
        e = random.randint(2, s-1)
        if math.gcd(e, s) == 1:
            d = get_inverse(e, s)[0]
            if d > 0:
                break
    return [(n, e), (n, d)]


def encrypt(content, pbkey):
    return pow(content, pbkey[1]) % pbkey[0]


def decrypt(encrypt_content, pvkey):
    return pow(encrypt_content, pvkey[1]) % pvkey[0]


def main():
    i = int(input("Alice: "))
    j = int(input("Bob: "))
    while True:
        x = random.randint(10**1, 10**2)
        if is_prime(x):
            break
    print(f"随机整数x={x}")
    pbk, pvk = create_key()
    print(f"公钥(n, e)=({pbk[0]}, {pbk[1]})\t私钥(n, d)=({pvk[0]}, {pvk[1]})")
    C = encrypt(x, pbk)
    print(f"Alice发送C-i={C-i}给Bob")
    Y = [decrypt(C-i+u, pvk) for u in range(1, 11)]
    print(f"Y={Y}")
    p = random.randint(10**1, x-1)
    while True:
        Z = list(map(lambda a: a % p, Y))
        if max(Z) < p-1 and min(Z) > 0:
            break
        # p = random.randint(min(10**2, min(Y)), max(10**3, min(Y)))
        p = random.randint(10**1, x-1)
    print(f"p={p}\nZ={Z}")
    for u in range(10):
        Z[u] = Z[u] + 1 if u >= j-1 else Z[u]
    print(f"K={Z}")
    if Z[i-1] == x % p:
        if i < j:
            print("Bob更富有")
        else:
            print("验证错误,i应该大于j,Alice可能更富有,也可能和Bob一样富有")
    else:
        if i >= j:
            print("Alice可能更富有,也可能和Bob一样富有")
        else:
            print("验证错误,j应该大于i,Bob更富有才对")


if __name__ == '__main__':
    main()

【样例输入】
3 2

【样例输出】
随机整数x=83
n=2449, s=2340
公钥(e, n)=(943, 2449) 私钥(d, n)=(67, 2449)
Alice发送C-i=2003给Bob
Y=[1382, 1499, 83, 1889, 96, 1141, 739, 1131, 2246, 1918]
p=69
Z=[2, 50, 14, 26, 27, 37, 49, 27, 38, 55]
K=[2, 51, 15, 27, 28, 38, 50, 28, 39, 56]
Alice可能更富有,也可能和Bob一样富有

【样例输入】
3 3

【样例输出】
随机整数x=29
n=649, s=580
公钥(e, n)=(91, 649) 私钥(d, n)=(51, 649)
Alice发送C-i=576给Bob
Y=[16, 50, 29, 19, 306, 197, 132, 441, 13, 377]
p=23
Z=[16, 4, 6, 19, 7, 13, 17, 4, 13, 9]
K=[16, 4, 7, 20, 8, 14, 18, 5, 14, 10]
Alice可能更富有,也可能和Bob一样富有

【样例输入】
4 6

【样例输出】
随机整数x=47
n=2117, s=2016
公钥(e, n)=(223, 2117) 私钥(d, n)=(895, 2117)
Alice发送C-i=220给Bob
Y=[746, 2114, 1205, 47, 1193, 1271, 81, 1834, 1701, 101]
p=30
Z=[26, 14, 5, 17, 23, 11, 21, 4, 21, 11]
K=[26, 14, 5, 17, 23, 12, 22, 5, 22, 12]
Bob更富有

总结

  我以为,百万富翁问题是安全多方计算中的一种模型框架,以公钥加密安全通信和标记的方式实现双方数值的比较,重点在于模型本身,具体的实现可以根据现有的技术进行改良,提升安全性和可靠性。
  本人也是这方面的初学者,看到网上的资源比较少因此写了这篇博客,有很多地方认识还不够,如果有不对的地方还请帮忙指正。

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值