百万富翁问题实现

Web 前端密码加密是否有意义?​www.zhihu.com图标

在这个温柔问题下看到了 

@w2014

 的一些密码学有趣的定理,感觉很有意思,例如零知识证明、盲签名、百万富翁问题,进而看到了知道了这个方法,两个人不需要裁判就能玩暗军棋​daily.zhihu.com图标

这篇文章里关于百万富翁问题姚期智院士所给出的解法

本者刨根问底的好奇心,本人自己将该过程实现了一遍代码如下:

#!/usr/bin/env python
# coding -*- utf:8 -*-

import math
import random

'''
百万富翁问题实现

自己生成公钥私钥并解密加密
算法无安全性
'''


# 获取小于等于指定数的素数数组
def get_prime_arr(max):
    prime_array = []
    for i in range(2, max):
        if is_prime(i):
            prime_array.append(i)
    return prime_array


# 判断是否为素数
def is_prime(num):
    if num == 1:
        raise Exception('1既不是素数也不是合数')
    for i in range(2, math.floor(math.sqrt(num)) + 1):
        if num % i == 0:
            # print("当前数%s为非素数,其有因子%s" % (str(num), str(i)))
            return False
    return True


# 找出一个指定范围内与n互质的整数e
def find_pub_key(n, max_num):
    while True:
        # 这里是随机获取保证随机性
        e = random.randint(1, max_num)
        if gcd(e, n) == 1:
            break
    return e


# 求两个数的最大公约数
def gcd(a, b):
    if b == 0:
        return a
    else:
        return gcd(b, a % b)


# 根据e*d mod s = 1,找出d
def find_pri_key(e, s):
    for d in range(100000000):  # 随机太难找,就按顺序找到d,range里的数字随意
        x = (e * d) % s
        if x == 1:
            return d


# 生成公钥和私钥
def build_key():
    prime_arr = get_prime_arr(100)
    p = random.choice(prime_arr)
    # 保证p和q不为同一个数
    while True:
        q = random.choice(prime_arr)
        if p != q:
            break
    print("随机生成两个素数p和q. p=", p, " q=", q)
    n = p * q
    s = (p - 1) * (q - 1)
    e = find_pub_key(s, 100)
    print("根据e和(p-1)*(q-1))互质得到: e=", e)
    d = find_pri_key(e, s)
    print("根据(e*d) 模 ((p-1)*(q-1)) 等于 1 得到 d=", d)
    print("公钥:   n=", n, "  e=", e)
    print("私钥:   n=", n, "  d=", d)
    return n, e, d


# 加密
def rsa_encrypt(content, ned):
    # 密文B = 明文A的e次方 模 n, ned为公钥
    # content就是明文A,ned【1】是e, ned【0】是n
    B = pow(content, ned[1]) % ned[0]
    return B


# 解密
def rsa_decrypt(encrypt_result, ned):
    # 明文C = 密文B的d次方 模 n, ned为私钥匙
    # encrypt_result就是密文, ned【1】是d, ned【0】是n
    C = pow(encrypt_result, ned[1]) % ned[0]
    return C


if __name__ == '__main__':
    pbvk = build_key()
    pbk = (pbvk[0], pbvk[1])  # 公钥
    pvk = (pbvk[0], pbvk[2])  # 私钥

    # 生成两个亿万富翁
    i = random.randint(1, 9)
    j = random.randint(1, 9)
    print("王有%s亿,李有%s亿" % (i, j))

    x = random.randint(1, 100)
    print("随机选取的大整数x: %s" % (x))
    K = rsa_encrypt(x, pbk)
    print("大整数加密后得密文K: %s" % (K))
    c = K - j
    print("王收到数字c: %s" % (c))

    c_list = []
    for k in range(1, 11):
        t = rsa_decrypt(c + k, pvk)
        c_list.append(t)
    print("对c+1到c+10进行解密: %s" % c_list)

    # 选取合适大小的p,这里根据感觉写了100以内的随机数,生成的序列的值也要求小于100
    # 这个p是该算法的精华,在实际中选取p的策略要考虑到安全性和性能的因素
    d_list = []
    p = 0
    while True:
        # 每次选取p重置列表
        d_list = []
        p = random.randint(1, 100)
        for k in range(0, 10):
            if c_list[k] % p <= 100:
                d_list.append(c_list[k] % p)
            else:
                break
        if len(d_list) >= 10:
            break
    print("p的值为: %s" % p)
    print("除以p后的余数为: %s" % d_list)

    for k in range(i, 10):
        d_list[k] = d_list[k] + 1
    print("前i位不动后面数字+1后: %s" % d_list)
    print("第j个数字为: %s" % d_list[j - 1])
    print("x mod p为: %s" % (x % p))
    if d_list[j - 1] == x % p:
        print("i>=j,即王比李有钱或一样有钱")
        if i - j >= 0:
            print("验证成功")
        else:
            print("代码存在错误")
    else:
        print("i<j,即李比王有钱")
        if i - j < 0:
            print("验证成功")
        else:
            print("代码存在错误")

代码是基于Python3的,有兴趣的朋友可以直接在本地跑一下,希望结合代码能让感兴趣的朋友了解的更透彻。

完。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值