22The following Python implementation of Shamir's secret sharing is
33released into the Public Domain under the terms of CC0 and OWFa:
44https://creativecommons.org/publicdomain/zero/1.0/
5- http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0
5+ http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
66
77See the bottom few lines for usage. Tested on Python 2 and 3.
88"""
9+ from __future__ import annotations
910
1011import functools
1112import random
1213
1314_RINT = functools .partial (random .SystemRandom ().randint , 0 )
1415
1516
16- def _eval_at (poly , x , prime ) :
17+ def _eval_at (poly : list [ int ] , x : int , prime : int ) -> int :
1718 """
18- Evaluates polynomial (coefficient tuple) at x, used to generate a
19+ Evaluate polynomial (coefficient tuple) at x, used to generate a
1920 shamir pool in make_random_shares below.
2021 """
2122 accum = 0
@@ -33,7 +34,7 @@ def _extended_gcd(a: int, b: int) -> int:
3334 denominator modulo p and then multiplying the numerator by this
3435 inverse (Note: inverse of A is B such that A*B % p == 1). This can
3536 be computed via the extended Euclidean algorithm
36- http://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Computation
37+ http://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Computation.
3738 """
3839 x = 0
3940 last_x = 1
@@ -50,7 +51,7 @@ def _extended_gcd(a: int, b: int) -> int:
5051
5152def _divmod (num : int , den : int , p : int ) -> int :
5253 """
53- Compute num / den modulo prime p
54+ Compute num / den modulo prime p.
5455
5556 To explain this, the result will be such that:
5657 den * _divmod(num, den, p) % p == num
@@ -66,9 +67,11 @@ def _lagrange_interpolate(x: int, x_s: list[int], y_s: list[int], p: int) -> int
6667 k points will define a polynomial of up to kth order.
6768 """
6869 k = len (x_s )
69- assert k == len (set (x_s )), "points must be distinct"
70+ if k != len (set (x_s )):
71+ msg = "points must be distinct"
72+ raise ValueError (msg )
7073
71- def PI (vals ) : # upper-case PI -- product of inputs
74+ def _pi (vals : list [ int ]) -> int : # upper-case PI -- product of inputs
7275 accum = 1
7376 for v in vals :
7477 accum *= v
@@ -79,25 +82,23 @@ def PI(vals): # upper-case PI -- product of inputs
7982 for i in range (k ):
8083 others = list (x_s )
8184 cur = others .pop (i )
82- nums .append (PI (x - o for o in others ))
83- dens .append (PI (cur - o for o in others ))
85+ nums .append (_pi (x - o for o in others ))
86+ dens .append (_pi (cur - o for o in others ))
8487
85- den = PI (dens )
88+ den = _pi (dens )
8689 num = sum ([_divmod (nums [i ] * den * y_s [i ] % p , dens [i ], p ) for i in range (k )])
8790
8891 return (_divmod (num , den , p ) + p ) % p
8992
9093
9194def make_random_shares (secret : int , minimum : int , shares : int , prime : int ) -> list [tuple [int , int ]]:
92- """
93- Generates a random shamir pool for a given secret, returns share points.
94- """
95+ """Generate a random shamir pool for a given secret, returns share points."""
9596 if minimum > shares :
96- raise ValueError ("Pool secret would be irrecoverable." )
97+ msg = "Pool secret would be irrecoverable."
98+ raise ValueError (msg )
9799 poly = [secret ] + [_RINT (prime - 1 ) for i in range (minimum - 1 )]
98- points = [(i , _eval_at (poly , i , prime )) for i in range (1 , shares + 1 )]
100+ return [(i , _eval_at (poly , i , prime )) for i in range (1 , shares + 1 )]
99101
100- return points
101102
102103
103104def recover_secret (shares : list [tuple [int , int ]], prime : int ) -> int :
0 commit comments