secret_sharing 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Code Climate](https://codeclimate.com/github/duse-io/secret_sharing_ruby/badges/gpa.svg)](https://codeclimate.com/github/duse-io/secret_sharing_ruby)
|
5
5
|
[![Inline docs](http://inch-ci.org/github/duse-io/secret_sharing_ruby.svg?branch=master)](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: []
|