How one can Share a Secret: Shamir’s Secret Sharing | by Jimin Kang | Jan, 2025

import random # in observe, this ought to be cryptographically safe
import numpy as np
from numpy.polynomial import polynomial as P
from prompt_inputs import accept_scheme_parameters, prompt_pooled_parties

# prime quantity to outline the finite area the place coefficients will likely be sampled from
# in observe, FIELD_SIZE > max(n, okay)
FIELD_SIZE = 65521

def generate_polynomial(d, okay):
“””
Parameters:
d: diploma of polynomial to be generated
okay: secret to outline polynomial y-intercept
Returns:
poly: vector of polynomial coefficients & intercept
ordered from intercept time period to largest diploma time period i.e. [k, a_{1}, a_{2},…, a_{t-1}]
“””
# generate random coeffcients from {0,…,p-1}
poly = [random.randint(0, FIELD_SIZE-1) for _ in range(d)]

# coefficient of largest diploma time period should be non-zero
poly[-1] = random.randint(1, FIELD_SIZE-1)

# place secret at y-intercept i.e. p(0) = okay
poly.insert(0, okay)

return poly

def compute_shares(poly, n):
“””
Parameters:
coeff: polynomial coefficients ordered from intercept time period to largest diploma time period i.e. [k, a_{1}, a_{2},…, a_{t-1}]
n: variety of events to distribute secret shares to
Returns:
shares: vector of computed shares
ordered by ascending order of social gathering index i.e. [s_{1}, s_{2},…, s_{n}]
“””
# consider polynomial at x in {1, 2,…, n}
x = np.arange(1, n + 1, 1)

# Generate the Vandermonde matrix
vandermonde = P.polyvander(x=x, deg=len(poly)-1)

# shares = vandermonde * poly
shares = vandermonde @ poly

return shares

def reconstruct_secret(shares, indices):
“””
Parameters:
shares: pooled share values
indices: events akin to pooled share values
Returns:
secret & vector containing polynomial coefficients and secret
“””
# Vandermonde matrix for pooled events
vandermonde = P.polyvander(x=indices, deg=len(indices)-1)

# coeff = inv(Vandermonde) * shares
poly = np.linalg.inv(vandermonde) @ np.array(shares)

# rounding to deal w/ floating pt. precision errors: wrapping integer lists into numpy arrays could promote integers into floats
# polynomial coefficients are integers in {0,…,p-1}
poly = [float(poly[0])] + [round(x) for x in poly[1:]]

print(f”Reconstructed Secret: {poly[0]}”)
print(f”Reconstructed Polynomial: {poly}”)

def display_scheme_info(okay, poly, shares):
“””
Show secret (okay), polynomial, and shares for the collaborating events within the (t, n) secret sharing scheme.
“””
print(f”Secret: {okay}”)
print(f”Polynomial: {poly}”)
print(“Shares:”)
for i, share in enumerate(shares):
print(f” Celebration {i+1}: {share}”)

def most important():
# outline scheme & compute/distribute shares
t, n, okay = accept_scheme_parameters()
poly = generate_polynomial(t-1, okay)
shares = compute_shares(poly, n)

display_scheme_info(okay, poly, shares)

# immediate for shares to pool
pooled_parties = prompt_pooled_parties(t, n)
pooled_shares = [shares[i-1] for i in pooled_parties]

# reconstruct secret from pooled shares
reconstruct_secret(pooled_shares, pooled_parties)