sss.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Package sss implements Shamir's Secret Sharing algorithm over GF(2^8).
  2. //
  3. // Shamir's Secret Sharing algorithm allows you to securely share a secret with
  4. // N people, allowing the recovery of that secret if K of those people combine
  5. // their shares.
  6. //
  7. // It begins by encoding a secret as a number (e.g., 42), and generating N
  8. // random polynomial equations of degree K-1 which have an X-intercept equal to
  9. // the secret. Given K=3, the following equations might be generated:
  10. //
  11. // f1(x) = 78x^2 + 19x + 42
  12. // f2(x) = 128x^2 + 171x + 42
  13. // f3(x) = 121x^2 + 3x + 42
  14. // f4(x) = 91x^2 + 95x + 42
  15. // etc.
  16. //
  17. // These polynomials are then evaluated for values of X > 0:
  18. //
  19. // f1(1) = 139
  20. // f2(2) = 896
  21. // f3(3) = 1140
  22. // f4(4) = 1783
  23. // etc.
  24. //
  25. // These (x, y) pairs are the shares given to the parties. In order to combine
  26. // shares to recover the secret, these (x, y) pairs are used as the input points
  27. // for Lagrange interpolation, which produces a polynomial which matches the
  28. // given points. This polynomial can be evaluated for f(0), producing the secret
  29. // value--the common x-intercept for all the generated polynomials.
  30. //
  31. // If fewer than K shares are combined, the interpolated polynomial will be
  32. // wrong, and the result of f(0) will not be the secret.
  33. //
  34. // This package constructs polynomials over the field GF(2^8) for each byte of
  35. // the secret, allowing for fast splitting and combining of anything which can
  36. // be encoded as bytes.
  37. //
  38. // This package has not been audited by cryptography or security professionals.
  39. package sss
  40. import (
  41. "crypto/rand"
  42. "errors"
  43. "io"
  44. )
  45. var (
  46. // ErrInvalidCount is returned when the count parameter is invalid.
  47. ErrInvalidCount = errors.New("N must be >= K")
  48. // ErrInvalidThreshold is returned when the threshold parameter is invalid.
  49. ErrInvalidThreshold = errors.New("K must be > 1")
  50. )
  51. // Split the given secret into N shares of which K are required to recover the
  52. // secret. Returns a map of share IDs (1-255) to shares.
  53. func Split(n, k byte, secret []byte) (map[byte][]byte, error) {
  54. return split(n, k, secret, rand.Reader)
  55. }
  56. // SplitUsingReader splits the given secret, as Split does, but using the
  57. // specified reader to create random polynomials. Use for deterministic
  58. // splitting; caller must ensure reader is cryptographically secure.
  59. func SplitUsingReader(
  60. n, k byte, secret []byte, reader io.Reader) (map[byte][]byte, error) {
  61. return split(n, k, secret, reader)
  62. }
  63. func split(n, k byte, secret []byte, randReader io.Reader) (map[byte][]byte, error) {
  64. if k <= 1 {
  65. return nil, ErrInvalidThreshold
  66. }
  67. if n < k {
  68. return nil, ErrInvalidCount
  69. }
  70. shares := make(map[byte][]byte, n)
  71. for _, b := range secret {
  72. p, err := generate(k-1, b, randReader)
  73. if err != nil {
  74. return nil, err
  75. }
  76. for x := byte(1); x <= n; x++ {
  77. shares[x] = append(shares[x], eval(p, x))
  78. }
  79. }
  80. return shares, nil
  81. }
  82. // Combine the given shares into the original secret.
  83. //
  84. // N.B.: There is no way to know whether the returned value is, in fact, the
  85. // original secret.
  86. func Combine(shares map[byte][]byte) []byte {
  87. var secret []byte
  88. for _, v := range shares {
  89. secret = make([]byte, len(v))
  90. break
  91. }
  92. points := make([]pair, len(shares))
  93. for i := range secret {
  94. p := 0
  95. for k, v := range shares {
  96. points[p] = pair{x: k, y: v[i]}
  97. p++
  98. }
  99. secret[i] = interpolate(points, 0)
  100. }
  101. return secret
  102. }