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