Git Product home page Git Product logo

secret-sharing's Introduction

Secret Sharing

CircleCI PyPI PyPI PyPI Slack

A library for sharding and sharing secrets (like Bitcoin private keys), using shamir's secret sharing scheme.

Installation

>>> pip install secretsharing

Sample Usage

Hex Secrets

Splitting into shares

>>> from secretsharing import SecretSharer
>>> shares = SecretSharer.split_secret("c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a", 2, 3)
['1-58cbd30524507e7a198bdfeb69c8d87fd7d2c10e8d5408851404f7d258cbcea7', '2-ecdbdaea89d75f8e73bde77a46db821cd40f430d39a11c864e5a4868dcb403ed', '3-80ebe2cfef5e40a2cdefef0923ee2bb9d04bc50be5ee308788af98ff609c380a']

Recovering from shares

>>> SecretSharer.recover_secret(shares[0:2])
'c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a'

Plaintext Secrets

Splitting into shares

>>> from secretsharing import PlaintextToHexSecretSharer
>>> shares = PlaintextToHexSecretSharer.split_secret("correct horse battery staple", 2, 3)
['1-7da6b11af146449675780434f6589230a3435d9ab59910354205996f508b8d0d', '2-fb4d6235e28c892cea70367c15ec3cbfed4cf4a417bd01e9812980f3ac97ddc8', '3-78f41350d3d2cdc35f6868c3357fe74f37568bad79e0f39dc04d687808a42d5a']

Recovering from shares

>>> PlaintextToHexSecretSharer.recover_secret(shares[0:2])
'correct horse battery staple'

Bitcoin Private Keys

Note: Bitcoin private keys are in Base58 check format.

Splitting into reliably printable base58 shares

>>> from secretsharing import BitcoinToB58SecretSharer
>>> shares = BitcoinToB58SecretSharer.split_secret("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS", 2, 3)
['2-Bqni1ysZcXhFBhVVJLQgPimDUJrjBrzuvBmc6gPNPh1jyDcvM6uYUuH', '3-9xpMBerBCdHLKzCQ82fjVLfZ3Qt48sqa6nz1E3cc6eu3qUe58vaogU3', '4-85qzMKpnnisRUGuJwivnaxZtcWuP5tgEHQCQMQqqocnMhjfDvkG4t2o']

Recovering from base58 shares

>>> BitcoinToB58SecretSharer.recover_secret(shares[0:2])
'5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS'

Splitting into reliably transcribable base32 shares

>>> from secretsharing import BitcoinToB32SecretSharer
>>> shares = BitcoinToB32SecretSharer.split_secret("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS", 2, 3)
['B-RJ6Y56OSUWDY5VAAGC6XLSTM64CAJ2LPBNB7NKATJCWC7VSHIP5DQIVMR6OGJ4GB', 'C-CT5R24XAR5B732JWYQKSYOYBSF5VHI73HLY24QCFRJR5XUW64C4JWYN6SRGWVCUG', 'D-T54KX27OPEAGZ7TNK5WOFK4WFPZKEXUHNKPWLWDXZQNYPT3WPV3P5IGQTD7HAJDG']

Recovering from base32 shares

>>> BitcoinToB32SecretSharer.recover_secret(shares[0:2])
'5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS'  

Splitting into reliably transcribable zbase32 shares

>>> from secretsharing import BitcoinToZB32SecretSharer
>>> shares = BitcoinToZB32SecretSharer.split_secret("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS", 2, 3)
['b-aweuzkm9jmfgd7x4k595bzcm3er3epf4dprfwzpprqa3exbuocs9byn4owfuqbo', 'n-btetgqqu8doacarsbyfdzpyycyj6gfdeaaxrpfx33pdjk4ou1d5owjdmdi1iegm9', 'd-njh33f14q7smucmh8iq8uaewc8mzub3mzptrwsegfiz3hc1fozkkjtguc4trh6sq']

Recovering from zbase32 shares

>>> BitcoinToZB32SecretSharer.recover_secret(shares[0:2])
'5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS'    

Raw integers

Splitting into shares

>>> from secretsharing import secret_int_to_points, points_to_secret_int
>>> secret = 88985120633792790105905686761572077713049967498756747774697023364147812997770L
>>> shares = secret_int_to_points(secret, 2, 3)
[(1, 108834987130598118322155382953070549297972563210322923466700361825476188819879L), (2, 12892764390087251114834094135881113029625174256248535119246116278891435001755L), (3, 32742630886892579331083790327379584614547769967814710811249454740219810823864L)]

Recovering from shares

>>> points_to_secret_int(shares[0:2])
88985120633792790105905686761572077713049967498756747774697023364147812997770L

Custom formats

Splitting into shares

>>> from secretsharing import SecretSharer, base64_chars
>>> sharer_class = SecretSharer
>>> sharer_class.share_charset = base64_chars
>>> shares = sharer_class.split_secret("c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a", 2, 3)
['B-JpxCTUQ9D+q93JglQM9yRinI2Cyxe92FTBSYa93ppfY', 'C-HAmR0pjHuHwL4rozXnFY05ysIJVqtf3pob1HCMaaZUm', 'D-EXbhV+1SYQ1Z6NxBfBM/YQ+PaP4j8B5N92X1pa9LJJ0']

Recovering from shares

>>> sharer_class.recover_secret(shares[0:2])
'c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a'

secret-sharing's People

Contributors

eateroa avatar prusnak avatar shea256 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

secret-sharing's Issues

Inital 0 omitted in recovered secret

My original secret is 0ZOyJJ6q7Hc0f5f5C0XPTKZNgIc3g0QRi90fFGWa7qnws8LVUZ6sTYEFiyey3n+l and when I have it recovered, it becomes ZOyJJ6q7Hc0f5f5C0XPTKZNgIc3g0QRi90fFGWa7qnws8LVUZ6sTYEFiyey3n+l.

I use the PlaintextToHexSecretSharer exactly as described in README.md.

Would you, please, help me?

cannot import name 'base64_chars'

from secretsharing import PlaintextToHexSecretSharer as ssss
from secretsharing import SecretSharer
from secretsharing import base64_chars

I want to share Custom formats secrets, but Python3 told me
Traceback (most recent call last):
File "E:\python\exp.py", line 3, in <module>
from secretsharing import base64_chars
ImportError: cannot import name 'base64_chars'

Can u give me some suggestions?

Very long secrets

Hai,

is it possbile to have secrets longer than 500 chars (plaintext?)

Thx and greetings,

NameError: name 'long' is not defined

This is what I get:

Traceback (most recent call last):
  File "/Users/Adam/PycharmProjects/SEVAS/local/key_management.py", line 5, in <module>
    from secretsharing import PlaintextToHexSecretSharer
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/secretsharing/__init__.py", line 12, in <module>
    from .sharing import *
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/secretsharing/sharing.py", line 14, in <module>
    from .primes import get_large_enough_prime
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/secretsharing/primes.py", line 35, in <module>
    STANDARD_PRIMES = calculate_mersenne_primes() + [
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/secretsharing/primes.py", line 25, in calculate_mersenne_primes
    prime = long(1)
NameError: name 'long' is not defined

Output isn't compatible with ssss

It would be reassuring if one could recover secrets using the ssss utility. However, it doesn't appear to work:

from secretsharing import PlaintextToHexSecretSharer
>>> PlaintextToHexSecretSharer.split_secret("hello", 3, 5)
['1-231aa4dc', '2-3224bff9', '3-134b1e74', '4-468dc04c', '5-4beca582']

$ ssss-combine -t3 -n5
Enter 3 shares separated by newlines:
Share [1/3]: 3-134b1e74
Share [2/3]: 4-468dc04c
Share [3/3]: 5-4beca582
WARNING: security level too small for the diffusion layer.
Resulting secret: ....
WARNING: binary data detected, use -x mode instead.
$ ssss-combine -t3 -n5 -x
Enter 3 shares separated by newlines:
Share [1/3]: 5-4beca582
Share [2/3]: 4-468dc04c
Share [3/3]: 3-134b1e74
WARNING: security level too small for the diffusion layer.
Resulting secret: a313fced

It's unclear to me how a313fced (which I assume is a hex representation of binary data) can correspond to the string "hello."

additive homomorphism in raw integer mode reconstructs irreliably

I wanted to use the additively homomorphic property of the secret sharing, so I wrote a little toy program to generate two sets of shares from two secrets, add them and reconstruct the sum from the new summed shares. The reconstruction works correctly only some of the time though. There also seems to be some pattern to the incorrect reconstruction.

This is the program:

from secretsharing import secret_int_to_points, points_to_secret_int

secret1 = 5
shares1 = secret_int_to_points(secret1, 2, 3)
print(secret1)
print(shares1)

secret2 = 7
shares2 = secret_int_to_points(secret2, 2, 3)
print(secret2)
print(shares2)

secretsum = [ (x1, (y1+y2)) for ((x1,y1),(x2,y2)) in zip(shares1, shares2) ]
print(secretsum)

plainsum = points_to_secret_int(secretsum[0:2])
print(plainsum)

I appended some of the outputs, with rough estimates of how often they occur:

With the two secrets being 5 and 7 about ~20% of the time I get a correct result.

5
[(1, 4L), (2, 3L), (3, 2L)]
7
[(1, 6L), (2, 5L), (3, 4L)]
[(1, 10L), (2, 8L), (3, 6L)]
12

Maybe ~60% of the time I get output similar to this:

5
[(1, 1L), (2, 4L), (3, 0L)]
7
[(1, 0L), (2, 0L), (3, 0L)]
[(1, 1L), (2, 4L), (3, 0L)]
5

And the other ~20% these two have popped up so far.

5
[(1, 6L), (2, 0L), (3, 1L)]
7
[(1, 4L), (2, 1L), (3, 5L)]
[(1, 10L), (2, 1L), (3, 6L)]
19
5
[(1, 2L), (2, 6L), (3, 3L)]
7
[(1, 2L), (2, 4L), (3, 6L)]
[(1, 4L), (2, 10L), (3, 9L)]
29

With secrets 4 and 8, ~80% of the time I get a correct result.

4
[(1, 5L), (2, 6L), (3, 0L)]
8
[(1, 14L), (2, 20L), (3, 26L)]
[(1, 19L), (2, 26L), (3, 26L)]
12

And ~20% of the time I get this.

4
[(1, 0L), (2, 3L), (3, 6L)]
8
[(1, 22L), (2, 5L), (3, 19L)]
[(1, 22L), (2, 8L), (3, 25L)]
5

Some secrets are corrupted

To reproduce:

>>> from secretsharing import SecretSharer
>>>
>>> secret = "04bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a"
>>> shares = SecretSharer.split_secret(secret, 2, 3)
>>> recovered = SecretSharer.recover_secret(shares[0:2])
>>> recovered == secret
False

This is due utilitybelt's charset_to_int behavior of dropping leading characters corresponding to a 0 in the charset when it is called on the secret.

If this is not the intended behavior from utilitybelt, a simple fix is to modify charset_to_int and int_to_charset to prepend a 1 to the returned value in order to preserve leading zeroes.

little bug

def init(self, secret_int):

This line is missing some parethesis. It should be

    ~~if not isinstance(secret_int, (int, long)) and secret_int >= 0:~~
    if not (isinstance(secret_int, (int, long)) and secret_int >= 0):
        raise ValueError("Secret must be a non-negative integer.")
    self._secret = secret_int

API to input the random values

Instead of drawing entropy automatically, is there an interface to input the random values?
What are the range of random values required?

Thank you.

Returning results of varying length

Depending on the secret, the shares have different length. Based on spec it should always be the same length as the original secret.

Correct length:

>>> SecretSharer.split_secret("205fcb5bd65d590c3b187a88bce077b9", 3, 5)
['1-26d92b6af22b9e72813806200d81f6d0', '2-6a71a977eeab9bb01a042934fd63299', '3-3fc998e17c9aaae5bc512fe283dd2b13', '4-5240a648eb3b71f2b14ace0da996e03f', '5-3e0c42cdcacd0ee1e08d1d14c103521d']

Longer than expected:

>>> SecretSharer.split_secret("c61b5432ae2436d8fc29ae38a205227c", 3, 5)
['1-63571f1a138698048c6cb5c743237939b0b1a021a5471a3c843eae8022a40db8', '2-66698be3fa70cdd2083df9367463f9c81193fadc6194c1494f264dc19b91d1ef', '3-937465db4bea1687373ca4d93c181abe8c26462e30d2bff5ce08bfd0cce6f21', '4-4bc04e87427012c7ce0e290ca13c10e5363cdcb529b05a5ead6d69327659e677', '5-2e04a460a38521f0180d15739cd3a773fa0363d3357e4c6740cce561d83436c8']

Possibility of different primes in point generation and recovery

The secret_int_to_points function chooses a prime just greater than secret_int and num_points. The reverse function points_to_secret_int chooses a prime just greater than all the y coordinates in the shares.

Suppose the prime in the first case was 8191 (say secret_int was 5000). Its possible that the y coordinates of all points generated is less than 127. If this happens, then the prime number chosen by the points_to_secret_int function is 127 instead of 8191. Won't this lead to inconsistencies in the recovery of the original secret? Am I missing something here?

incompatible with other implementations?

I was looking at using this to split some secrets. However, I wanted to be able to use multiple programs to create and restore these.

When I used the values from the README with http://point-at-infinity.org/ssss/, I don't get the expected results. Is there anything to do to make these compatible?

$ ssss-combine -t 2
Enter 2 shares separated by newlines:
Share [1/2]: 1-58cbd30524507e7a198bdfeb69c8d87fd7d2c10e8d5408851404f7d258cbcea7
Share [2/2]: 2-ecdbdaea89d75f8e73bde77a46db821cd40f430d39a11c864e5a4868dcb403ed
Resulting secret: : ...y.;ch`J..]H...19..r.MV.....
WARNING: binary data detected, use -x mode instead.

$ ssss-combine -t 2 -x
Enter 2 shares separated by newlines:
Share [1/2]: 1-58cbd30524507e7a198bdfeb69c8d87fd7d2c10e8d5408851404f7d258cbcea7
Share [2/2]: 2-ecdbdaea89d75f8e73bde77a46db821cd40f430d39a11c864e5a4868dcb403ed
Resulting secret: 3a20ed1e8a79d63b6368604ae1b65d48a3be893139fdec72c14d56df9deca4df

The expected resulting secret is c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.