📜  用Python实现 Shamir 的秘密共享方案

📅  最后修改于: 2022-05-13 01:55:09.641000             🧑  作者: Mango

用Python实现 Shamir 的秘密共享方案

秘密共享方案用于通过将秘密分成片段股份在多个参与者股东之间分配秘密值。这样做的方式是防止单个股东对原始秘密有任何有用的知识。检索原始秘密的唯一方法是合并分配给参与者的共享。因此,秘密的控制是分布式的。这些方案是阈值密码系统的示例,其中涉及多方之间的秘密划分,使得多方(超过某个阈值数)必须合作重建秘密。

秘密分享

图 1n参与者之间秘密共享的描述

一般来说,一个秘密可以分成n股(对于n名股东),其中,成功重建至少需要t , (t < n)股。这种方案被称为 (t, n) 共享方案。从n 个参与者中,任何大小大于或等于t的股东子集都可以重新生成秘密。重要的是,即使有任何k (k < t)共享,也不会学习到有关原始秘密的新信息。

沙米尔秘密分享

Shamir Secret Sharing ( SSS ) 是由以色列著名密码学家Adi Shamir创建的秘密共享方案中最受欢迎的实现之一,他也为 RSA 算法的发明做出了贡献。 SSS 允许将秘密分成任意数量的份额并允许任意阈值(只要它小于参与者总数)。 SSS 基于多项式插值的数学概念,该概念指出,可以根据已知位于曲线上的 t 个或更多点的知识来重建 t-1 次多项式。
例如,要重建一条 1 次曲线(一条直线),我们需要至少 2 个点位于该直线上。相反,如果可用的唯一点的数量小于 (degree-of-curve + 1),则在数学上重建曲线是不可行的。可以想象有无限可能的直线可以由二维空间中的一个点形成。

SSS 背后的动机

通过将秘密嵌入多项式,可以应用多项式插值的概念来生成秘密共享方案。 p次的一般多项式可以表示如下:

P(x) = a_{1}x^{p}+a_{2}x^{p-1}+a_3x^{p-2}+...+a_{n-2}x^{2}+a_{n-1}x+a_{n}

在 P(x) 的表达式中,值 a_{1}、a_{2}、a_{3}、…、a_{n} 表示多项式的系数。因此,多项式的构造需要选择这些系数。请注意,实际上没有任何值被替换为x;多项式中的每一项都充当“占位符”来存储系数值。
一旦生成多项式,我们基本上可以仅通过位于曲线上的p+1个点来表示曲线。这遵循多项式插值原理。例如,如果我们可以访问至少 5 个位于其上的独特点,则可以重建 4 次曲线。为此,我们可以运行拉格朗日插值或任何其他类似的插值机制。

多项式插值示例

图 2:使用多项式插值重建曲线的示例

因此,如果我们将秘密值隐藏在这样一个多项式中,并使用曲线上的各个点作为共享,我们就会得到一个秘密共享方案。更准确地说,为了建立一个(t, n)秘密共享方案,我们可以构造一个t-1 次的多项式,并在曲线上选择n个点作为共享,这样只有在合并t或更多共享时才会重新生成多项式。秘密值 ( s ) 隐藏在多项式的常数项(0 次项的系数或曲线的 y 截距)中,只有在曲线重建成功后才能获得。

使用的算法

Shamir's Secret Sharing 使用多项式插值原理在以下两个阶段进行阈值共享:
第一阶段:股票的产生
此阶段涉及系统的设置以及共享的生成。

  1. 确定参与者数量(n)和阈值(t)的值以确保某些秘密值(s)
  2. 通过选择多项式的随机系数,构造一个次数为t-1的随机多项式P(x) 。将多项式中的常数项(零度项的系数)设置为等于秘密值s
  3. 要生成n股,随机选择多项式P(x)上的n个点
  4. 在参与者之间分配上一步中选择的坐标。这些充当系统中的份额

第二阶段:秘密的重构
为了重建秘密,至少需要t个参与者来集中他们的份额。

  1. 收集t股或更多股
  2. 使用插值算法从份额中重建多项式P'(x)拉格朗日插值是这种算法的一个例子
  3. 确定x = 0的重构多项式的值,即计算P'(0) 。该值揭示了恰好是原始秘密的多项式的常数项。因此,秘密被重建

下面是实现。

Python3
import random
from math import ceil
from decimal import Decimal
 
FIELD_SIZE = 10**5
 
 
def reconstruct_secret(shares):
    """
    Combines individual shares (points on graph)
    using Lagranges interpolation.
 
    `shares` is a list of points (x, y) belonging to a
    polynomial with a constant of our key.
    """
    sums = 0
    prod_arr = []
 
    for j, share_j in enumerate(shares):
        xj, yj = share_j
        prod = Decimal(1)
 
        for i, share_i in enumerate(shares):
            xi, _ = share_i
            if i != j:
                prod *= Decimal(Decimal(xi)/(xi-xj))
 
        prod *= yj
        sums += Decimal(prod)
 
    return int(round(Decimal(sums), 0))
 
 
def polynom(x, coefficients):
    """
    This generates a single point on the graph of given polynomial
    in `x`. The polynomial is given by the list of `coefficients`.
    """
    point = 0
    # Loop through reversed list, so that indices from enumerate match the
    # actual coefficient indices
    for coefficient_index, coefficient_value in enumerate(coefficients[::-1]):
        point += x ** coefficient_index * coefficient_value
    return point
 
 
def coeff(t, secret):
    """
    Randomly generate a list of coefficients for a polynomial with
    degree of `t` - 1, whose constant is `secret`.
 
    For example with a 3rd degree coefficient like this:
        3x^3 + 4x^2 + 18x + 554
 
        554 is the secret, and the polynomial degree + 1 is
        how many points are needed to recover this secret.
        (in this case it's 4 points).
    """
    coeff = [random.randrange(0, FIELD_SIZE) for _ in range(t - 1)]
    coeff.append(secret)
    return coeff
 
 
def generate_shares(n, m, secret):
    """
    Split given `secret` into `n` shares with minimum threshold
    of `m` shares to recover this `secret`, using SSS algorithm.
    """
    coefficients = coeff(m, secret)
    shares = []
 
    for i in range(1, n+1):
        x = random.randrange(1, FIELD_SIZE)
        shares.append((x, polynom(x, coefficients)))
 
    return shares
 
 
# Driver code
if __name__ == '__main__':
 
    # (3,5) sharing scheme
    t, n = 3, 5
    secret = 1234
    print(f'Original Secret: {secret}')
 
    # Phase I: Generation of shares
    shares = generate_shares(n, t, secret)
    print(f'Shares: {", ".join(str(share) for share in shares)}')
 
    # Phase II: Secret Reconstruction
    # Picking t shares randomly for
    # reconstruction
    pool = random.sample(shares, t)
    print(f'Combining shares: {", ".join(str(share) for share in pool)}')
    print(f'Reconstructed secret: {reconstruct_secret(pool)}')


输出:

Original Secret: 1234
Shares: (79761, 4753361900938), (67842, 3439017561016), (42323, 1338629004828), (68237, 3479175081966), (32818, 804981007208)
Combining shares: (32818, 804981007208), (79761, 4753361900938), (68237, 3479175081966)
Reconstructed secret: 1234

实际应用

秘密共享方案广泛用于需要分布式而不是集中式信任的密码系统。使用秘密共享的现实世界场景的突出示例包括:

  • 比特币基于阈值的签名
  • 安全多方计算
  • 具有多方计算的私有机器学习
  • 密码管理