Skip to content

Commit fd3c7f2

Browse files
committed
Some clarifications for SecretSharing
1 parent 967938f commit fd3c7f2

File tree

2 files changed

+65
-23
lines changed

2 files changed

+65
-23
lines changed

lib/Crypto/Protocol/SecretSharing.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ def _div_gf2(a, b):
7777
class _Element(object):
7878
"""Element of GF(2^128) field"""
7979

80-
# The irreducible polynomial defining this field is 1+x+x^2+x^7+x^128
80+
# The irreducible polynomial defining
81+
# this field is 1 + x + x^2 + x^7 + x^128
8182
irr_poly = 1 + 2 + 4 + 128 + 2 ** 128
8283

8384
def __init__(self, encoded_value):
@@ -178,43 +179,53 @@ def split(k, n, secret, ssss=False):
178179
179180
Args:
180181
k (integer):
181-
The sufficient number of shares to reconstruct the secret (``k < n``).
182+
The number of shares needed to reconstruct the secret.
182183
n (integer):
183-
The number of shares that this method will create.
184+
The number of shares to create (at least ``k``).
184185
secret (byte string):
185-
A byte string of 16 bytes (e.g. the AES 128 key).
186+
A byte string of 16 bytes (e.g. an AES 128 key).
186187
ssss (bool):
187-
If ``True``, the shares can be used with the ``ssss`` utility.
188+
If ``True``, the shares can be used with the ``ssss`` utility
189+
(without using the "diffusion layer").
188190
Default: ``False``.
189191
190192
Return (tuples):
191-
``n`` tuples. A tuple is meant for each participant and it contains two items:
193+
``n`` tuples, one per participant.
194+
A tuple contains two items:
192195
193196
1. the unique index (an integer)
194-
2. the share (a byte string, 16 bytes)
197+
2. the share (16 bytes)
195198
"""
196199

197200
#
198201
# We create a polynomial with random coefficients in GF(2^128):
199202
#
200-
# p(x) = \sum_{i=0}^{k-1} c_i * x^i
203+
# p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i
201204
#
202-
# c_0 is the encoded secret
205+
# c_0 is the secret.
203206
#
204207

205208
coeffs = [_Element(rng(16)) for i in range(k - 1)]
206209
coeffs.append(_Element(secret))
207210

208-
# Each share is y_i = p(x_i) where x_i is the public index
209-
# associated to each of the n users.
211+
# Each share is y_i = p(x_i) where x_i
212+
# is the index assigned to the share.
210213

211214
def make_share(user, coeffs, ssss):
212215
idx = _Element(user)
216+
217+
# Horner's method
213218
share = _Element(0)
214219
for coeff in coeffs:
215220
share = idx * share + coeff
221+
222+
# The ssss utility actually uses:
223+
#
224+
# p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i + x^k
225+
#
216226
if ssss:
217227
share += _Element(user) ** len(coeffs)
228+
218229
return share.encode()
219230

220231
return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)]
@@ -225,11 +236,18 @@ def combine(shares, ssss=False):
225236
226237
Args:
227238
shares (tuples):
228-
The *k* tuples, each containin the index (an integer) and
239+
The *k* tuples, each containing the index (an integer) and
229240
the share (a byte string, 16 bytes long) that were assigned to
230241
a participant.
242+
243+
.. note::
244+
245+
Pass exactly as many share as they are required,
246+
and no more.
247+
231248
ssss (bool):
232-
If ``True``, the shares were produced by the ``ssss`` utility.
249+
If ``True``, the shares were produced by the ``ssss`` utility
250+
(without using the "diffusion layer").
233251
Default: ``False``.
234252
235253
Return:
@@ -275,4 +293,5 @@ def combine(shares, ssss=False):
275293
numerator *= x_m
276294
denominator *= x_j + x_m
277295
result += y_j * numerator * denominator.inverse()
296+
278297
return result.encode()

lib/Crypto/SelfTest/Protocol/test_SecretSharing.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
from binascii import unhexlify, hexlify
3636

3737
from Crypto.Util.py3compat import *
38+
from Crypto.Hash import SHAKE128
3839
from Crypto.SelfTest.st_common import list_test_cases
3940

4041
from Crypto.Protocol.SecretSharing import Shamir, _Element, \
4142
_mult_gf2, _div_gf2
4243

44+
4345
class GF2_Tests(TestCase):
4446

4547
def test_mult_gf2(self):
@@ -129,6 +131,7 @@ def test4(self):
129131
y = x.inverse()
130132
self.assertEqual(int(x * y), 1)
131133

134+
132135
class Shamir_Tests(TestCase):
133136

134137
def test1(self):
@@ -143,6 +146,8 @@ def test2(self):
143146
# Test recombine
144147
from itertools import permutations
145148

149+
# Generated by ssss (index, secret, shares)
150+
# in hex mode, without "diffusion" mode
146151
test_vectors = (
147152
(2, "d9fe73909bae28b3757854c0af7ad405",
148153
"1-594ae8964294174d95c33756d2504170",
@@ -227,24 +232,42 @@ def get_share(p):
227232

228233
def test3(self):
229234
# Loopback split/recombine
230-
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
231235

232-
shares = Shamir.split(2, 3, secret)
236+
rng = SHAKE128.new(b"test3")
237+
238+
for _ in range(100):
239+
240+
secret = rng.read(16)
241+
242+
shares = Shamir.split(2, 3, secret)
233243

234-
secret2 = Shamir.combine(shares[:2])
235-
self.assertEqual(secret, secret2)
244+
secret2 = Shamir.combine(shares[:2])
245+
self.assertEqual(secret, secret2)
236246

237-
secret3 = Shamir.combine([ shares[0], shares[2] ])
238-
self.assertEqual(secret, secret3)
247+
secret3 = Shamir.combine([ shares[0], shares[2] ])
248+
self.assertEqual(secret, secret3)
239249

240250
def test4(self):
241251
# Loopback split/recombine (SSSS)
242-
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
243252

244-
shares = Shamir.split(2, 3, secret, ssss=True)
253+
rng = SHAKE128.new(b"test4")
254+
255+
for _ in range(10):
256+
secret = rng.read(16)
257+
258+
shares = Shamir.split(2, 3, secret, ssss=True)
259+
260+
secret2 = Shamir.combine(shares[:2], ssss=True)
261+
self.assertEqual(secret, secret2)
262+
263+
for _ in range(10):
264+
secret = rng.read(16)
265+
266+
shares = Shamir.split(3, 7, secret, ssss=True)
267+
268+
secret2 = Shamir.combine([shares[3], shares[4], shares[6]], ssss=True)
269+
self.assertEqual(secret, secret2)
245270

246-
secret2 = Shamir.combine(shares[:2], ssss=True)
247-
self.assertEqual(secret, secret2)
248271

249272
def test5(self):
250273
# Detect duplicate shares

0 commit comments

Comments
 (0)