mirror of
https://github.com/Legrandin/pycryptodome.git
synced 2025-10-19 16:03:45 +00:00
Some clarifications for SecretSharing
This commit is contained in:
parent
967938f83a
commit
fd3c7f2a65
2 changed files with 65 additions and 23 deletions
|
@ -77,7 +77,8 @@ def _div_gf2(a, b):
|
||||||
class _Element(object):
|
class _Element(object):
|
||||||
"""Element of GF(2^128) field"""
|
"""Element of GF(2^128) field"""
|
||||||
|
|
||||||
# The irreducible polynomial defining this field is 1+x+x^2+x^7+x^128
|
# The irreducible polynomial defining
|
||||||
|
# this field is 1 + x + x^2 + x^7 + x^128
|
||||||
irr_poly = 1 + 2 + 4 + 128 + 2 ** 128
|
irr_poly = 1 + 2 + 4 + 128 + 2 ** 128
|
||||||
|
|
||||||
def __init__(self, encoded_value):
|
def __init__(self, encoded_value):
|
||||||
|
@ -178,43 +179,53 @@ class Shamir(object):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
k (integer):
|
k (integer):
|
||||||
The sufficient number of shares to reconstruct the secret (``k < n``).
|
The number of shares needed to reconstruct the secret.
|
||||||
n (integer):
|
n (integer):
|
||||||
The number of shares that this method will create.
|
The number of shares to create (at least ``k``).
|
||||||
secret (byte string):
|
secret (byte string):
|
||||||
A byte string of 16 bytes (e.g. the AES 128 key).
|
A byte string of 16 bytes (e.g. an AES 128 key).
|
||||||
ssss (bool):
|
ssss (bool):
|
||||||
If ``True``, the shares can be used with the ``ssss`` utility.
|
If ``True``, the shares can be used with the ``ssss`` utility
|
||||||
|
(without using the "diffusion layer").
|
||||||
Default: ``False``.
|
Default: ``False``.
|
||||||
|
|
||||||
Return (tuples):
|
Return (tuples):
|
||||||
``n`` tuples. A tuple is meant for each participant and it contains two items:
|
``n`` tuples, one per participant.
|
||||||
|
A tuple contains two items:
|
||||||
|
|
||||||
1. the unique index (an integer)
|
1. the unique index (an integer)
|
||||||
2. the share (a byte string, 16 bytes)
|
2. the share (16 bytes)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#
|
#
|
||||||
# We create a polynomial with random coefficients in GF(2^128):
|
# We create a polynomial with random coefficients in GF(2^128):
|
||||||
#
|
#
|
||||||
# p(x) = \sum_{i=0}^{k-1} c_i * x^i
|
# p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i
|
||||||
#
|
#
|
||||||
# c_0 is the encoded secret
|
# c_0 is the secret.
|
||||||
#
|
#
|
||||||
|
|
||||||
coeffs = [_Element(rng(16)) for i in range(k - 1)]
|
coeffs = [_Element(rng(16)) for i in range(k - 1)]
|
||||||
coeffs.append(_Element(secret))
|
coeffs.append(_Element(secret))
|
||||||
|
|
||||||
# Each share is y_i = p(x_i) where x_i is the public index
|
# Each share is y_i = p(x_i) where x_i
|
||||||
# associated to each of the n users.
|
# is the index assigned to the share.
|
||||||
|
|
||||||
def make_share(user, coeffs, ssss):
|
def make_share(user, coeffs, ssss):
|
||||||
idx = _Element(user)
|
idx = _Element(user)
|
||||||
|
|
||||||
|
# Horner's method
|
||||||
share = _Element(0)
|
share = _Element(0)
|
||||||
for coeff in coeffs:
|
for coeff in coeffs:
|
||||||
share = idx * share + coeff
|
share = idx * share + coeff
|
||||||
|
|
||||||
|
# The ssss utility actually uses:
|
||||||
|
#
|
||||||
|
# p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i + x^k
|
||||||
|
#
|
||||||
if ssss:
|
if ssss:
|
||||||
share += _Element(user) ** len(coeffs)
|
share += _Element(user) ** len(coeffs)
|
||||||
|
|
||||||
return share.encode()
|
return share.encode()
|
||||||
|
|
||||||
return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)]
|
return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)]
|
||||||
|
@ -225,11 +236,18 @@ class Shamir(object):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
shares (tuples):
|
shares (tuples):
|
||||||
The *k* tuples, each containin the index (an integer) and
|
The *k* tuples, each containing the index (an integer) and
|
||||||
the share (a byte string, 16 bytes long) that were assigned to
|
the share (a byte string, 16 bytes long) that were assigned to
|
||||||
a participant.
|
a participant.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pass exactly as many share as they are required,
|
||||||
|
and no more.
|
||||||
|
|
||||||
ssss (bool):
|
ssss (bool):
|
||||||
If ``True``, the shares were produced by the ``ssss`` utility.
|
If ``True``, the shares were produced by the ``ssss`` utility
|
||||||
|
(without using the "diffusion layer").
|
||||||
Default: ``False``.
|
Default: ``False``.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
|
@ -275,4 +293,5 @@ class Shamir(object):
|
||||||
numerator *= x_m
|
numerator *= x_m
|
||||||
denominator *= x_j + x_m
|
denominator *= x_j + x_m
|
||||||
result += y_j * numerator * denominator.inverse()
|
result += y_j * numerator * denominator.inverse()
|
||||||
|
|
||||||
return result.encode()
|
return result.encode()
|
||||||
|
|
|
@ -35,11 +35,13 @@ from unittest import main, TestCase, TestSuite
|
||||||
from binascii import unhexlify, hexlify
|
from binascii import unhexlify, hexlify
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash import SHAKE128
|
||||||
from Crypto.SelfTest.st_common import list_test_cases
|
from Crypto.SelfTest.st_common import list_test_cases
|
||||||
|
|
||||||
from Crypto.Protocol.SecretSharing import Shamir, _Element, \
|
from Crypto.Protocol.SecretSharing import Shamir, _Element, \
|
||||||
_mult_gf2, _div_gf2
|
_mult_gf2, _div_gf2
|
||||||
|
|
||||||
|
|
||||||
class GF2_Tests(TestCase):
|
class GF2_Tests(TestCase):
|
||||||
|
|
||||||
def test_mult_gf2(self):
|
def test_mult_gf2(self):
|
||||||
|
@ -129,6 +131,7 @@ class Element_Tests(TestCase):
|
||||||
y = x.inverse()
|
y = x.inverse()
|
||||||
self.assertEqual(int(x * y), 1)
|
self.assertEqual(int(x * y), 1)
|
||||||
|
|
||||||
|
|
||||||
class Shamir_Tests(TestCase):
|
class Shamir_Tests(TestCase):
|
||||||
|
|
||||||
def test1(self):
|
def test1(self):
|
||||||
|
@ -143,6 +146,8 @@ class Shamir_Tests(TestCase):
|
||||||
# Test recombine
|
# Test recombine
|
||||||
from itertools import permutations
|
from itertools import permutations
|
||||||
|
|
||||||
|
# Generated by ssss (index, secret, shares)
|
||||||
|
# in hex mode, without "diffusion" mode
|
||||||
test_vectors = (
|
test_vectors = (
|
||||||
(2, "d9fe73909bae28b3757854c0af7ad405",
|
(2, "d9fe73909bae28b3757854c0af7ad405",
|
||||||
"1-594ae8964294174d95c33756d2504170",
|
"1-594ae8964294174d95c33756d2504170",
|
||||||
|
@ -227,7 +232,12 @@ class Shamir_Tests(TestCase):
|
||||||
|
|
||||||
def test3(self):
|
def test3(self):
|
||||||
# Loopback split/recombine
|
# Loopback split/recombine
|
||||||
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
|
|
||||||
|
rng = SHAKE128.new(b"test3")
|
||||||
|
|
||||||
|
for _ in range(100):
|
||||||
|
|
||||||
|
secret = rng.read(16)
|
||||||
|
|
||||||
shares = Shamir.split(2, 3, secret)
|
shares = Shamir.split(2, 3, secret)
|
||||||
|
|
||||||
|
@ -239,13 +249,26 @@ class Shamir_Tests(TestCase):
|
||||||
|
|
||||||
def test4(self):
|
def test4(self):
|
||||||
# Loopback split/recombine (SSSS)
|
# Loopback split/recombine (SSSS)
|
||||||
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
|
|
||||||
|
rng = SHAKE128.new(b"test4")
|
||||||
|
|
||||||
|
for _ in range(10):
|
||||||
|
secret = rng.read(16)
|
||||||
|
|
||||||
shares = Shamir.split(2, 3, secret, ssss=True)
|
shares = Shamir.split(2, 3, secret, ssss=True)
|
||||||
|
|
||||||
secret2 = Shamir.combine(shares[:2], ssss=True)
|
secret2 = Shamir.combine(shares[:2], ssss=True)
|
||||||
self.assertEqual(secret, secret2)
|
self.assertEqual(secret, secret2)
|
||||||
|
|
||||||
|
for _ in range(10):
|
||||||
|
secret = rng.read(16)
|
||||||
|
|
||||||
|
shares = Shamir.split(3, 7, secret, ssss=True)
|
||||||
|
|
||||||
|
secret2 = Shamir.combine([shares[3], shares[4], shares[6]], ssss=True)
|
||||||
|
self.assertEqual(secret, secret2)
|
||||||
|
|
||||||
|
|
||||||
def test5(self):
|
def test5(self):
|
||||||
# Detect duplicate shares
|
# Detect duplicate shares
|
||||||
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
|
secret = unhexlify(b("000102030405060708090a0b0c0d0e0f"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue