Shamir门限秘密共享方案 秘密分配及还原过程详解 【橘小白】

Shamir(t,w)门限方案,(0 < t <= w)
用途:
假设我们存在一个秘密S,把秘密S进行特定运算,得到w个秘密碎片Si(0 < i <= w),交给w个人保存,当至少t个人同时拿出自己所拥有的秘密碎片Si时,即可还原出最初的秘密S。

秘密碎片生成:
构造一个多项式
在这里插入图片描述
其中,S为我们的秘密,p为素数,且S < p
取w个不相等的x,带入F(x)中,得到w组(xi,yi),分配给w个人
公开p,销毁多项式,每个人负责保密自己的(xi,yi)

秘密恢复:

当x=0时,F(0)=S,即可恢复出S
将t组(xi,yi)带入下式即可
在这里插入图片描述
其中,负一次方为该项模p的逆
将t组(xi,yi)带入即可得到S

示例
假设我们有w=4个人,设定至少t=3人才能恢复秘密。
秘密S=2,p=23
构造
在这里插入图片描述
取x1=1,x2=2,x3=3,x4=4
带入得y1=7,y2=16, y3=6,y4=0
利用3组进行恢复(1,7) (3,6) (4,0)
在这里插入图片描述
计算可得到S=2

最后再附一个简单的恢复脚本

# coding:utf-8


def oj(a, n):   # 求逆的函数
    a = a % n
    s = [0, 1]
    while a != 1:
        if a == 0:
            return 0
        q = n/a
        t = n % a
        n = a
        a = t
        s += [s[-2] - q * s[-1]]
    return s[-1]

p = 23
m = ((4, 0),
     (3, 6),
     (2, 16))
r = (
    m[0][1] * (0 - m[1][0]) * (0 - m[2][0]) * oj((m[0][0] - m[1][0]) * (m[0][0] - m[2][0]), p) +
    m[1][1] * (0 - m[0][0]) * (0 - m[2][0]) * oj((m[1][0] - m[0][0]) * (m[1][0] - m[2][0]), p) +
    m[2][1] * (0 - m[0][0]) * (0 - m[1][0]) * oj((m[2][0] - m[0][0]) * (m[2][0] - m[1][0]), p)
     ) % p
print r

更新一个相对完整的脚本python3写的,变量名基本上与文章中含义一致



import Crypto.Util.number as numb
import random


# 求逆的函数,之前的版本用python2写的,这次用的python3,只把整除符号改了一下
def oj(a, n):
    a = a % n
    s = [0, 1]
    while a != 1:
        if a == 0:
            return 0
        q = n // a
        t = n % a
        n = a
        a = t
        s += [s[-2] - q * s[-1]]
    return s[-1]


# max_length 为p的长度,同时也是秘密的最大长度
# secret_is_text =0 默认输入时文本, 非0时认为是数字
# p 默认为0, 会根据max_length 自动生成,不为0时直接使用,需要保证p为素数, 函数内没有素性检验
def create(max_length=513, secret_is_text=0, p=0):
    if not p:
        p = numb.getPrime(max_length)

    w = int(input("请输入秘密保存人数:"))
    t = int(input("请输入秘密恢复所需人数:"))
    while not (t > 0 and t <= w):
        t = int(input("请重新输入:"))
    s = input("请输入你的秘密:")

    if secret_is_text:
        s = numb.bytes_to_long(s.encode("utf-8"))
    else:
        try:
            s = int(s)
        except Exception as e:
            s = numb.bytes_to_long(s.encode("utf-8"))

    x_list = list()
    a_list = list()
    i = w
    while i > 0:
        x = random.randint(p // 2, p)  # 该范围没有特定限制,如果想让xi,yi取小一点儿的话可把范围写小点儿,但是要大于w
        if x not in x_list:
            x_list.append(x)
            i -= 1

    for a in range(t):
        a_list.append(random.randint(p // 2, p))  # 同上

    result = list()
    for x in x_list:
        y = s
        for a_n in range(t):
            a = a_list[i]
            y += a * pow(x, i + 1, p)
        result.append((x, y))
    return t, p, result


# get_text=1 默认恢复为字符串,若想得到数字填0
def restore(p, information, get_text=1):

    x_list = list()
    y_list=list()
    for x, y in information:
        x_list.append(x)
        y_list.append(y)

    s = 0
    for x_i in range(len(x_list)):
        tmp_num = y_list[x_i]
        x_i_j = 1
        for x_j in range(len(x_list)):
            if x_i != x_j:
                tmp_num = tmp_num * (0 - x_list[x_j]) % p
                x_i_j *= x_list[x_i] - x_list[x_j]
        tmp_num = tmp_num * oj(x_i_j, p) % p
        s += tmp_num

    s = s % p
    print(s)
    if get_text:
        try:
            s = numb.long_to_bytes(s)
            s = s.decode("utf-8")
        except Exception as e:
            print(e)

    return s


t, p, result = create()             #result为秘密碎片的列表
print(result)
print(restore(p, result[:t]))     #这里我取了result的前t个,实际中可以取任意t个。






  • 46
    点赞
  • 194
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值