secret_sharing 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/Gemfile +11 -6
- data/README.md +33 -19
- data/lib/secret_sharing.rb +1 -1
- data/lib/secret_sharing/polynomial.rb +9 -12
- data/lib/secret_sharing/version.rb +1 -1
- data/secret_sharing.gemspec +1 -1
- data/spec/polynomial_spec.rb +44 -5
- data/spec/secret_sharing_spec.rb +10 -0
- data/spec/spec_helper.rb +3 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZGRmOTk3Y2EyYTJhY2FiODk2YWYwODNlNWZlMzI5ZTJlY2M0MDk3Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZTVkODUxZjRkMGUzZWYyMzRkYzFiNTYyNWU2OWUyMzJjYzhkNjU3OA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MjY5OTQ3ZTU4NjA1MzhkMmY0MzkwM2U0NTVkYmJjOTg3MDMyZjIyNmUwZWUw
|
10
|
+
OGRmZDAzZWFjYzBiMDlkNzdhZmMyMjU5N2Y5MzNmOTA3ZTc2YTY3Zjg4ZDFk
|
11
|
+
NDRhYmZmZTc4NjFkY2FlOGRlZmQ1ZmZhZjdjOGI5MmRjYWE5NGM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Y2YwZjQ1YjVjMGJlOGU2YzVlZTA4NTJhZWEzMDFiYjRlNzU0NGQ1M2ViNjZj
|
14
|
+
NTQ0MTc4NjNmYjI1NWIyNTkwOWYzYmE2ZjBkOGRhMDQ3MTdjZTk2Zjk0YmY4
|
15
|
+
NTEyYzg1NzU2NDhkN2YwMTE2ZGQ0ZjE5MzY2Y2U1NjQ1ZTQ0MTQ=
|
data/Gemfile
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
+
gemspec
|
2
3
|
|
3
|
-
|
4
|
-
gem '
|
5
|
-
gem '
|
6
|
-
gem '
|
7
|
-
gem '
|
8
|
-
gem '
|
4
|
+
group :development, :test do
|
5
|
+
gem 'rake'
|
6
|
+
gem 'rspec'
|
7
|
+
gem 'mutant'
|
8
|
+
gem 'mutant-rspec'
|
9
|
+
gem 'yard'
|
10
|
+
gem 'rubocop', require: false
|
11
|
+
gem 'simplecov', require: false
|
12
|
+
gem 'coveralls', require: false
|
13
|
+
end
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[](https://codeclimate.com/github/duse-io/secret_sharing_ruby)
|
5
5
|
[](http://inch-ci.org/github/duse-io/secret_sharing_ruby)
|
6
6
|
|
7
|
-
#
|
7
|
+
# secret_sharing
|
8
8
|
|
9
9
|
> **Warning:** This implementation has not been tested in production nor has it
|
10
10
|
> been examined by a security audit. All uses are your own responsibility.
|
@@ -25,32 +25,46 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
$ gem install secret_sharing
|
27
27
|
|
28
|
-
##
|
28
|
+
## Implementation details
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
This implementation of shamir's secret sharing has initially been developed to
|
31
|
+
be used in [duse](https://duse.io/), however, it is designed to be used in any
|
32
|
+
other context just as well.
|
33
|
+
|
34
|
+
The representation of a share is simply `x-hex(y)`. We chose this
|
35
|
+
representation, mainly to make it easier for this library to become compatible
|
36
|
+
with other implementations, if we choose to.
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
secure)
|
38
|
+
For better approximation and equal length of the resulting shares, a zero
|
39
|
+
padding has been added. For example, if there are ten or more shares, then all
|
40
|
+
single digit shares have a prepending zero.
|
39
41
|
|
40
|
-
|
42
|
+
* `01-574060c9`
|
43
|
+
* `02-1fe7479f`
|
44
|
+
* ...
|
45
|
+
* `10-651e7e4b`
|
41
46
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
47
|
+
Also, when generating a random polynomial, we make sure the coefficients are
|
48
|
+
random, but never zero. If we would allow the coefficients to be zero, it could
|
49
|
+
result in a lower threshold than intended. For example, if the threshold is
|
50
|
+
three, then the degree of the polynomial would be two so in the form of
|
51
|
+
`f(x)=a0 + a1*x + a2*x^2`. If `a2` would be zero than the polynomial would be
|
52
|
+
of dergree one, which would result in a real threshold of two rather than
|
53
|
+
three.
|
46
54
|
|
47
|
-
|
48
|
-
|
49
|
-
|
55
|
+
## Usage
|
56
|
+
|
57
|
+
require 'secret_sharing'
|
58
|
+
shares = SecretSharing.split_secret('my secret', 2, 3)
|
59
|
+
# => ["1-437b3d6cce8e7b77adb75", "2-86f673fa74e31127903f6", "3-ca71aa881b37a6d772c77"]
|
60
|
+
length = shares.length
|
61
|
+
# => 3
|
62
|
+
secret = SecretSharing.recover_secret(shares[0..1])
|
63
|
+
# => 'my secret'
|
50
64
|
|
51
65
|
## Contributing
|
52
66
|
|
53
|
-
1. Fork it ( https://github.com/duse-io/
|
67
|
+
1. Fork it ( https://github.com/duse-io/secret_sharing_ruby/fork )
|
54
68
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
69
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
56
70
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/lib/secret_sharing.rb
CHANGED
@@ -43,16 +43,15 @@ module SecretSharing
|
|
43
43
|
(1..num_points).map do |x|
|
44
44
|
y = intercept
|
45
45
|
(1...@coefficients.length).each do |i|
|
46
|
-
|
47
|
-
term = (@coefficients[i] * exponentiation) % prime
|
48
|
-
y = (y + term) % prime
|
46
|
+
y = (y + @coefficients[i] * x ** i) % prime
|
49
47
|
end
|
50
48
|
Point.new(x, y)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
52
|
# Generate a random polynomial with a specific degree, defined x=0 value
|
55
|
-
# and an upper limit for the coefficients of the polynomial.
|
53
|
+
# and an upper limit for the coefficients of the polynomial. All
|
54
|
+
# coefficients generated are >= 1.
|
56
55
|
#
|
57
56
|
# Example
|
58
57
|
#
|
@@ -66,7 +65,7 @@ module SecretSharing
|
|
66
65
|
fail ArgumentError, 'Degree must be a non-negative number' if degree < 0
|
67
66
|
|
68
67
|
coefficients = (0...degree).reduce([intercept]) do |accumulator|
|
69
|
-
accumulator << SecureRandom.random_number(upper_bound)
|
68
|
+
accumulator << SecureRandom.random_number(upper_bound - 1) + 1
|
70
69
|
end
|
71
70
|
new coefficients
|
72
71
|
end
|
@@ -83,13 +82,11 @@ module SecretSharing
|
|
83
82
|
# @param num_points [Integer] number of points to generate
|
84
83
|
# @return [Polynomial] the generated polynomial
|
85
84
|
def self.points_from_secret(secret_int, point_threshold, num_points)
|
86
|
-
prime =
|
85
|
+
prime = Prime.large_enough_prime(secret_int)
|
87
86
|
fail ArgumentError, 'Threshold must be at least 2' if point_threshold < 2
|
88
87
|
fail ArgumentError, 'Threshold must be less than the total number of points' if point_threshold > num_points
|
89
88
|
|
90
|
-
polynomial =
|
91
|
-
secret_int,
|
92
|
-
prime)
|
89
|
+
polynomial = random(point_threshold - 1, secret_int, prime)
|
93
90
|
polynomial.points(num_points, prime)
|
94
91
|
rescue Prime::CannotFindLargeEnoughPrime
|
95
92
|
raise ArgumentError, 'Secret is too long'
|
@@ -97,8 +94,8 @@ module SecretSharing
|
|
97
94
|
|
98
95
|
# Modular lagrange interpolation
|
99
96
|
def self.modular_lagrange_interpolation(points)
|
100
|
-
y_values = Point.transpose(points)
|
101
|
-
prime =
|
97
|
+
_, y_values = Point.transpose(points)
|
98
|
+
prime = Prime.large_enough_prime(y_values.max)
|
102
99
|
points.reduce(0) do |f_x, point|
|
103
100
|
numerator, denominator = lagrange_fraction(points, point, prime)
|
104
101
|
lagrange_polynomial = numerator * mod_inverse(denominator, prime)
|
@@ -121,7 +118,7 @@ module SecretSharing
|
|
121
118
|
# inverse modulo
|
122
119
|
def self.mod_inverse(k, prime)
|
123
120
|
k = k % prime
|
124
|
-
r = egcd(prime, k.abs)
|
121
|
+
r = egcd(prime, k.abs).last
|
125
122
|
(prime + r) % prime
|
126
123
|
end
|
127
124
|
|
data/secret_sharing.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['flower-pot']
|
10
10
|
spec.email = ['fbranczyk@gmail.com']
|
11
11
|
spec.summary = 'Ruby implementation of sharmir\'s secret sharing'
|
12
|
-
spec.description = '
|
12
|
+
spec.description = 'Split and reconstruct secrets using the shamir\'s secret sharing algorithm'
|
13
13
|
spec.homepage = 'https://github.com/duse-io/secret_sharing_ruby'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
data/spec/polynomial_spec.rb
CHANGED
@@ -59,7 +59,13 @@ RSpec.describe SecretSharing::Polynomial do
|
|
59
59
|
it 'randomly generates coefficients' do
|
60
60
|
allow(SecureRandom).to receive(:random_number).and_return(3, 5, 2)
|
61
61
|
polynomial = SecretSharing::Polynomial.random(3, 5, 10)
|
62
|
-
expect(polynomial.coefficients).to eq [5,
|
62
|
+
expect(polynomial.coefficients).to eq [5, 4, 6 ,3]
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'ensures, that a coefficient is >= 1' do
|
66
|
+
allow(SecureRandom).to receive(:random_number).and_return(0, 0, 0)
|
67
|
+
polynomial = SecretSharing::Polynomial.random(3, 5, 10)
|
68
|
+
expect(polynomial.coefficients).to eq [5, 1, 1 ,1]
|
63
69
|
end
|
64
70
|
|
65
71
|
it 'uses the intercept as the first coefficient' do
|
@@ -79,11 +85,36 @@ RSpec.describe SecretSharing::Polynomial do
|
|
79
85
|
expect(points.length).to eq 4
|
80
86
|
end
|
81
87
|
|
82
|
-
it '
|
83
|
-
points = SecretSharing::Polynomial.points_from_secret(
|
84
|
-
|
85
|
-
|
88
|
+
it 'generates points according to the threshold parameter' do
|
89
|
+
points = SecretSharing::Polynomial.points_from_secret(10, 2, 4)
|
90
|
+
required_points = points[0, 2]
|
91
|
+
result = SecretSharing::Polynomial.modular_lagrange_interpolation(required_points)
|
92
|
+
expect(result).to eq 10
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'allows threshold and total number of points to be equal' do
|
96
|
+
points = SecretSharing::Polynomial.points_from_secret(10, 2, 2)
|
97
|
+
result = SecretSharing::Polynomial.modular_lagrange_interpolation(points)
|
98
|
+
expect(result).to eq 10
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'requires threshold points or more to reconstruct' do
|
102
|
+
points = SecretSharing::Polynomial.points_from_secret(234234, 3, 4)
|
103
|
+
required_points = points[0, 3]
|
104
|
+
secret = SecretSharing::Polynomial.modular_lagrange_interpolation(required_points)
|
86
105
|
expect(secret).to eq 234234
|
106
|
+
|
107
|
+
required_points = points[0, 4]
|
108
|
+
secret = SecretSharing::Polynomial.modular_lagrange_interpolation(required_points)
|
109
|
+
expect(secret).to eq 234234
|
110
|
+
|
111
|
+
required_points = points[0, 2]
|
112
|
+
secret = SecretSharing::Polynomial.modular_lagrange_interpolation(required_points)
|
113
|
+
expect(secret).not_to eq 234234
|
114
|
+
|
115
|
+
required_points = points[0, 1]
|
116
|
+
secret = SecretSharing::Polynomial.modular_lagrange_interpolation(required_points)
|
117
|
+
expect(secret).not_to eq 234234
|
87
118
|
end
|
88
119
|
|
89
120
|
it 'errors when the secret is to long' do
|
@@ -111,4 +142,12 @@ RSpec.describe SecretSharing::Polynomial do
|
|
111
142
|
)
|
112
143
|
end
|
113
144
|
end
|
145
|
+
|
146
|
+
describe '.egcd' do
|
147
|
+
context 'a=240 b=46' do
|
148
|
+
it 'returns a quotient of 2, s=-9 and t=47' do
|
149
|
+
expect(SecretSharing::Polynomial.egcd(240, 46)).to eq [2, -9, 47]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
114
153
|
end
|
data/spec/secret_sharing_spec.rb
CHANGED
@@ -37,4 +37,14 @@ RSpec.describe SecretSharing do
|
|
37
37
|
expect(SecretSharing.recover_secret(shares)).to eq 'secret'
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
context 'threshold 2 out of 11 shares' do
|
42
|
+
subject(:shares) { SecretSharing.split_secret('secret', 2, 11) }
|
43
|
+
|
44
|
+
it 'adds zero padding for shares 1 to 9' do
|
45
|
+
shares[0, 9].each_with_index do |share, index|
|
46
|
+
expect(share).to start_with "0#{index+1}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
40
50
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secret_sharing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- flower-pot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: Split and reconstruct secrets using the shamir's secret sharing algorithm
|
14
14
|
email:
|
15
15
|
- fbranczyk@gmail.com
|
16
16
|
executables: []
|