Esempio n. 1
0
    def split(k, n, secret, ssss=False):
        """Split a secret into ``n`` shares.

        The secret can be reconstructed later using just ``k`` shares
        out of the original ``n``.
        Each share must be kept confidential to the person it was
        assigned to.

        Each share is associated to an index (starting from 1).

        Args:
          k (integer):
            The sufficient number of shares to reconstruct the secret (``k < n``).
          n (integer):
            The number of shares that this method will create.
          secret (byte string):
            A byte string of 16 bytes (e.g. the AES 128 key).
          ssss (bool):
            If ``True``, the shares can be used with the ``ssss`` utility.
            Default: ``False``.

        Return (tuples):
            ``n`` tuples. A tuple is meant for each participant and it contains two items:

            1. the unique index (an integer)
            2. the share (a byte string, 16 bytes)
        """

        #
        # We create a polynomial with random coefficients in GF(2^128):
        #
        # p(x) = \sum_{i=0}^{k-1} c_i * x^i
        #
        # c_0 is the encoded secret
        #

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

        # Each share is y_i = p(x_i) where x_i is the public index
        # associated to each of the n users.

        def make_share(user, coeffs, ssss):
            idx = _Element(user)
            share = _Element(0)
            for coeff in coeffs:
                share = idx * share + coeff
            if ssss:
                share += _Element(user)**len(coeffs)
            return share.encode()

        return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)]
    def split(k, n, secret):
        """Split a secret into *n* shares.

        The secret can be reconstructed later when *k* shares
        out of the original *n* are recombined. Each share
        must be kept confidential to the person it was
        assigned to.

        Each share is associated to an index (starting from 1),
        which must be presented when the secret is recombined.

        Args:
          k (integer):
            The number of shares that must be present in order to reconstruct
            the secret.
          n (integer):
            The total number of shares to create (larger than *k*).
          secret (byte string):
            The 16 byte string (e.g. the AES128 key) to split.

        Return:
            *n* tuples, each containing the unique index (an integer) and
            the share (a byte string, 16 bytes long) meant for a
            participant.
        """

        #
        # We create a polynomial with random coefficients in GF(2^128):
        #
        # p(x) = \sum_{i=0}^{k-1} c_i * x^i
        #
        # c_0 is the encoded secret
        #

        coeffs = [_Element(rng(16)) for i in range(k - 1)]
        coeffs.insert(0, _Element(secret))

        # Each share is y_i = p(x_i) where x_i is the public index
        # associated to each of the n users.

        def make_share(user, coeffs):
            share, x, idx = [_Element(p) for p in (0, 1, user)]
            for coeff in coeffs:
                share += coeff * x
                x *= idx
            return share.encode()

        return [(i, make_share(i, coeffs)) for i in range(1, n + 1)]
Esempio n. 3
0
    def split(k, n, secret):
        """Split a secret into *n* shares.

        The secret can be reconstructed later when *k* shares
        out of the original *n* are recombined. Each share
        must be kept confidential to the person it was
        assigned to.

        Each share is associated to an index (starting from 1),
        which must be presented when the secret is recombined.

        Args:
          k (integer):
            The number of shares that must be present in order to reconstruct
            the secret.
          n (integer):
            The total number of shares to create (larger than *k*).
          secret (byte string):
            The 16 byte string (e.g. the AES128 key) to split.

        Return:
            *n* tuples, each containing the unique index (an integer) and
            the share (a byte string, 16 bytes long) meant for a
            participant.
        """

        #
        # We create a polynomial with random coefficients in GF(2^128):
        #
        # p(x) = \sum_{i=0}^{k-1} c_i * x^i
        #
        # c_0 is the encoded secret
        #

        coeffs = [_Element(rng(16)) for i in xrange(k - 1)]
        coeffs.insert(0, _Element(secret))

        # Each share is y_i = p(x_i) where x_i is the public index
        # associated to each of the n users.

        def make_share(user, coeffs):
            share, x, idx = [_Element(p) for p in (0, 1, user)]
            for coeff in coeffs:
                share += coeff * x
                x *= idx
            return share.encode()

        return [(i, make_share(i, coeffs)) for i in xrange(1, n + 1)]
    def combine(shares):
        """Recombine a secret, if enough shares are presented.

        Args:
          shares (tuples):
            At least *k* tuples, each containin the index (an integer) and
            the share (a byte string, 16 bytes long) that were assigned to
            a participant.

        Return:
            The original secret, as a byte string (16 bytes long).
        """

        #
        # Given k points (x,y), the interpolation polynomial of degree k-1 is:
        #
        # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x)
        #
        # where:
        #
        # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} }
        #          \frac{x - x_m}{x_j - x_m}
        #
        # However, in this case we are purely intersted in the constant
        # coefficient of L(x).
        #

        shares = [[_Element(y) for y in x] for x in shares]

        result = _Element(0)
        k = len(shares)
        for j in range(k):
            x_j, y_j = shares[j]

            coeff_0_l = _Element(0)
            while not int(coeff_0_l):
                coeff_0_l = _Element(rng(16))
            inv = coeff_0_l.inverse()

            for m in range(k):
                x_m = shares[m][0]
                if m != j:
                    t = x_m * (x_j + x_m).inverse()
                    coeff_0_l *= t
            result += y_j * coeff_0_l * inv
        return result.encode()
Esempio n. 5
0
    def combine(shares):
        """Recombine a secret, if enough shares are presented.

        Args:
          shares (tuples):
            At least *k* tuples, each containin the index (an integer) and
            the share (a byte string, 16 bytes long) that were assigned to
            a participant.

        Return:
            The original secret, as a byte string (16 bytes long).
        """

        #
        # Given k points (x,y), the interpolation polynomial of degree k-1 is:
        #
        # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x)
        #
        # where:
        #
        # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} }
        #          \frac{x - x_m}{x_j - x_m}
        #
        # However, in this case we are purely intersted in the constant
        # coefficient of L(x).
        #

        shares = [[_Element(y) for y in x] for x in shares]

        result = _Element(0)
        k = len(shares)
        for j in xrange(k):
            x_j, y_j = shares[j]

            coeff_0_l = _Element(0)
            while not int(coeff_0_l):
                coeff_0_l = _Element(rng(16))
            inv = coeff_0_l.inverse()

            for m in xrange(k):
                x_m = shares[m][0]
                if m != j:
                    t = x_m * (x_j + x_m).inverse()
                    coeff_0_l *= t
            result += y_j * coeff_0_l * inv
        return result.encode()