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

导读:本篇文章讲解 【安全多方计算】百万富翁问题,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

前导知识

判断素数

素数:除了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.2.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 = get_inverse(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更富有

总结

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/97117.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!