secret_sharing 0.0.1
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 +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +5 -0
- data/.yardops +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +68 -0
- data/LICENSE +22 -0
- data/README.md +55 -0
- data/Rakefile +8 -0
- data/lib/secret_sharing.rb +55 -0
- data/lib/secret_sharing/charset.rb +226 -0
- data/lib/secret_sharing/point.rb +63 -0
- data/lib/secret_sharing/polynomial.rb +123 -0
- data/lib/secret_sharing/prime.rb +44 -0
- data/lib/secret_sharing/share.rb +74 -0
- data/lib/secret_sharing/version.rb +4 -0
- data/secret_sharing.gemspec +19 -0
- data/spec/charset_spec.rb +36 -0
- data/spec/point_spec.rb +22 -0
- data/spec/polynomial_spec.rb +22 -0
- data/spec/prime_spec.rb +7 -0
- data/spec/secret_sharing_spec.rb +19 -0
- data/spec/share_spec.rb +9 -0
- data/spec/spec_helper.rb +55 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d1f9dc3ed57b5e31acda563d2a75bb39f17cda8
|
4
|
+
data.tar.gz: 38914666ac426bcdd7765ab4d04b9cd4209e48aa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 05149dab9a3f6afceb1d52a72f15742bd4d5de9a06580d7abb8389d40b96a5de5af908c207e11cd5dc3c66f8c525fcf7c240a3882a1cf2a183327dd87e21b946
|
7
|
+
data.tar.gz: 1c6b21a99d780e527b9de6858a9f8bd9a3d3480904d8bc108b99d05dae446583157569be5d15f1da9c507600feb5748b92736aa1064bb2429a25409386003ac8
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Style/AsciiComments:
|
2
|
+
Enabled: false # not to comment in another language than english but to be
|
3
|
+
# able to write tests for non ascii characters
|
4
|
+
|
5
|
+
Documentation:
|
6
|
+
Enabled: false # this is handled by yard and it is annoying since rubocop does
|
7
|
+
# not notice if a top level class documentation has already
|
8
|
+
# been created (https://github.com/bbatsov/rubocop/issues/691)
|
data/.travis.yml
ADDED
data/.yardops
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
lib/**/*.rb --no-private --markup markdown - README.md LICENSE
|
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in secret_sharing.gemspec
|
4
|
+
gem 'bundler', '~> 1.6'
|
5
|
+
gem 'rake', group: [:development, :test]
|
6
|
+
gem 'rspec', group: [:development, :test]
|
7
|
+
gem 'yard', group: :development
|
8
|
+
gem 'rubocop', require: false, group: :development
|
9
|
+
gem 'simplecov', require: false, group: [:development, :test]
|
10
|
+
gem 'coveralls', require: false, group: [:development, :test]
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ast (2.0.0)
|
5
|
+
astrolabe (1.3.0)
|
6
|
+
parser (>= 2.2.0.pre.3, < 3.0)
|
7
|
+
coveralls (0.7.1)
|
8
|
+
multi_json (~> 1.3)
|
9
|
+
rest-client
|
10
|
+
simplecov (>= 0.7)
|
11
|
+
term-ansicolor
|
12
|
+
thor
|
13
|
+
diff-lcs (1.2.5)
|
14
|
+
docile (1.1.5)
|
15
|
+
mime-types (2.4.2)
|
16
|
+
multi_json (1.10.1)
|
17
|
+
netrc (0.8.0)
|
18
|
+
parser (2.2.0.pre.5)
|
19
|
+
ast (>= 1.1, < 3.0)
|
20
|
+
slop (~> 3.4, >= 3.4.5)
|
21
|
+
powerpack (0.0.9)
|
22
|
+
rainbow (2.0.0)
|
23
|
+
rake (10.3.2)
|
24
|
+
rest-client (1.7.2)
|
25
|
+
mime-types (>= 1.16, < 3.0)
|
26
|
+
netrc (~> 0.7)
|
27
|
+
rspec (3.1.0)
|
28
|
+
rspec-core (~> 3.1.0)
|
29
|
+
rspec-expectations (~> 3.1.0)
|
30
|
+
rspec-mocks (~> 3.1.0)
|
31
|
+
rspec-core (3.1.7)
|
32
|
+
rspec-support (~> 3.1.0)
|
33
|
+
rspec-expectations (3.1.2)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.1.0)
|
36
|
+
rspec-mocks (3.1.3)
|
37
|
+
rspec-support (~> 3.1.0)
|
38
|
+
rspec-support (3.1.2)
|
39
|
+
rubocop (0.26.1)
|
40
|
+
astrolabe (~> 1.3)
|
41
|
+
parser (>= 2.2.0.pre.4, < 3.0)
|
42
|
+
powerpack (~> 0.0.6)
|
43
|
+
rainbow (>= 1.99.1, < 3.0)
|
44
|
+
ruby-progressbar (~> 1.4)
|
45
|
+
ruby-progressbar (1.6.0)
|
46
|
+
simplecov (0.9.1)
|
47
|
+
docile (~> 1.1.0)
|
48
|
+
multi_json (~> 1.0)
|
49
|
+
simplecov-html (~> 0.8.0)
|
50
|
+
simplecov-html (0.8.0)
|
51
|
+
slop (3.6.0)
|
52
|
+
term-ansicolor (1.3.0)
|
53
|
+
tins (~> 1.0)
|
54
|
+
thor (0.19.1)
|
55
|
+
tins (1.3.3)
|
56
|
+
yard (0.8.7.4)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
ruby
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
bundler (~> 1.6)
|
63
|
+
coveralls
|
64
|
+
rake
|
65
|
+
rspec
|
66
|
+
rubocop
|
67
|
+
simplecov
|
68
|
+
yard
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 flower-pot
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
[](https://travis-ci.org/duse-io/secret_sharing_ruby)
|
2
|
+
[](https://coveralls.io/r/duse-io/secret_sharing_ruby)
|
3
|
+
[](https://codeclimate.com/github/duse-io/secret_sharing_ruby)
|
4
|
+
|
5
|
+
# SecretSharing
|
6
|
+
|
7
|
+
> **Warning:** This implementation has not been tested in production nor has it
|
8
|
+
> been examined by a security audit. All uses are your own responsibility.
|
9
|
+
|
10
|
+
A ruby implementation of shamir's secret sharing.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'secret_sharing'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install secret_sharing
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
require 'secret_sharing'
|
29
|
+
shares = SecretSharing.split_secret('secret', 2, 3) # => [...]
|
30
|
+
length = shares.length # => 3
|
31
|
+
secret = SecretSharing.recover_secret(shares[0..1]) # => 'my secret'
|
32
|
+
|
33
|
+
This implementation can also handle non-ascii characters, however, the charset
|
34
|
+
will be visible in the calculated shares. Thus splitting ascii only strings is
|
35
|
+
"more" secure. (but always remember, shamir's secret sharing alone is not
|
36
|
+
secure)
|
37
|
+
|
38
|
+
## Compatible libraries
|
39
|
+
|
40
|
+
Since this implementation is special in some ways most [Shamir’s Secret
|
41
|
+
Sharing](http://de.wikipedia.org/wiki/Shamir%E2%80%99s_Secret_Sharing)
|
42
|
+
libraries are not compatible. The only library that is compatible as of now is
|
43
|
+
[duse-io/secret-sharing-dart](https://github.com/duse-io/secret-sharing-dart).
|
44
|
+
|
45
|
+
We do have [integration
|
46
|
+
tests](https://github.com/duse-io/lib-integration-tests) that make sure the
|
47
|
+
libraries work with each other.
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it ( https://github.com/duse-io/secret_sharing/fork )
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'secret_sharing/version'
|
2
|
+
require 'secret_sharing/point'
|
3
|
+
require 'secret_sharing/polynomial'
|
4
|
+
require 'secret_sharing/prime'
|
5
|
+
require 'secret_sharing/charset'
|
6
|
+
require 'secret_sharing/share'
|
7
|
+
|
8
|
+
# A ruby implementation of Shamir's Secret Sharing. This module is the only
|
9
|
+
# connection to be consumed by a user. Do not use any other class/module of
|
10
|
+
# this library unless you really know what you are doing.
|
11
|
+
module SecretSharing
|
12
|
+
# Split a secret using Shamir's Secret Sharing algorithm.
|
13
|
+
#
|
14
|
+
# Example
|
15
|
+
#
|
16
|
+
# SecretSharing.split_secret('secret', 2, 3)
|
17
|
+
# # => ["tcesr-1-4e16", "tcesr-2-1105", "tcesr-3-1d3f3"]
|
18
|
+
#
|
19
|
+
# @param secret_string [String] Secret to split.
|
20
|
+
# @param share_threshold [Integer] Number of shares to recover the secret.
|
21
|
+
# @param num_shares [Integer] Total number of shares to generate.
|
22
|
+
#
|
23
|
+
# @return [Array] Array of shares that can be used to recover the secret.
|
24
|
+
def split_secret(secret_string, share_threshold, num_shares)
|
25
|
+
charset = Charset.by_string secret_string
|
26
|
+
secret_int = charset.s_to_i(secret_string)
|
27
|
+
points = Polynomial.points_from_secret(secret_int,
|
28
|
+
share_threshold,
|
29
|
+
num_shares)
|
30
|
+
points.map do |point|
|
31
|
+
Share.new(charset, point).to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Recover a secret with an array of string shares generated with
|
36
|
+
# {#split_secret}.
|
37
|
+
#
|
38
|
+
# Example
|
39
|
+
#
|
40
|
+
# SecretSharing.recover_secret(["tcesr-1-4e16", "tcesr-2-1105"])
|
41
|
+
# # => "secret"
|
42
|
+
#
|
43
|
+
# @param raw_shares [Array] Shares (array of strings) to recover the secret
|
44
|
+
#
|
45
|
+
# @return [String] Recovered secret in a string representation.
|
46
|
+
def recover_secret(raw_shares)
|
47
|
+
shares = raw_shares.map { |raw_share| Share.from_string raw_share }
|
48
|
+
points = shares.map(&:point)
|
49
|
+
secret_int = Polynomial.modular_lagrange_interpolation(points)
|
50
|
+
shares.first.charset.i_to_s(secret_int)
|
51
|
+
end
|
52
|
+
|
53
|
+
module_function :split_secret,
|
54
|
+
:recover_secret
|
55
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module SecretSharing
|
4
|
+
# This module is used to create or retrieve a charset to use.
|
5
|
+
module Charset
|
6
|
+
# Decides which charset fits the provided string best and creates a custom
|
7
|
+
# charset if no predefined charset fits the usecase.
|
8
|
+
#
|
9
|
+
# Example
|
10
|
+
#
|
11
|
+
# SecretSharing::Charset.by_string 'test'
|
12
|
+
# # => #<SecretSharing::ASCIICharset @charset=[...]>
|
13
|
+
#
|
14
|
+
# Or with a custom charset
|
15
|
+
#
|
16
|
+
# SecretSharing::Charset.by_string 'testä'
|
17
|
+
# # => #<SecretSharing::DynamicCharset @charset=["s", "e", "ä", "t"]>
|
18
|
+
#
|
19
|
+
# @param string [String] The string to evaluate the charset for.
|
20
|
+
# @return A charset that has at least the methods #s_to_i and #i_to_s.
|
21
|
+
def by_string(string)
|
22
|
+
return ASCIICharset.new if ASCIICharset.new.subset?(string)
|
23
|
+
DynamicCharset.from_string string
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieves a charset based on its string representation.
|
27
|
+
#
|
28
|
+
# Example
|
29
|
+
#
|
30
|
+
# SecretSharing::Charset.by_charset_string ''
|
31
|
+
# # => #<SecretSharing::ASCIICharset @charset=[...]>
|
32
|
+
#
|
33
|
+
# Or in case of a custom charset
|
34
|
+
#
|
35
|
+
# SecretSharing::Charset.by_charset_string 'tesä'
|
36
|
+
# # => #<SecretSharing::DynamicCharset @charset=["t", "e", "s", "ä"]>
|
37
|
+
#
|
38
|
+
# @param charset_string [String] The string to evaluate the charset for.
|
39
|
+
# @return A charset that has at least the methods #s_to_i and #i_to_s.
|
40
|
+
def by_charset_string(charset_string)
|
41
|
+
return ASCIICharset.new if charset_string.empty?
|
42
|
+
DynamicCharset.new(charset_string.chars)
|
43
|
+
end
|
44
|
+
|
45
|
+
module_function :by_string,
|
46
|
+
:by_charset_string
|
47
|
+
end
|
48
|
+
|
49
|
+
module Charset
|
50
|
+
# This objects of this class can represent a custom charset whenever the
|
51
|
+
# predefined charsets do not fit a situation.
|
52
|
+
class DynamicCharset
|
53
|
+
# A new instance of DynamicCharset. The constructor should only be used
|
54
|
+
# when you know what you are doing. Usually you only want to use this
|
55
|
+
# constructor when you recreate a charset and the order of the charset is
|
56
|
+
# important. The "null-byte" character is prepended to be the first
|
57
|
+
# character in the charset to avoid loosing the first character of the
|
58
|
+
# charset when it is also the first character in a string to convert.
|
59
|
+
#
|
60
|
+
# Example
|
61
|
+
#
|
62
|
+
# SecretSharing::Charset::DynamicCharset.new ['a', 'b', 'c']
|
63
|
+
# # => #<SecretSharing::Charset::DynamicCharset @charset=[...]>
|
64
|
+
#
|
65
|
+
# @param charset [Array] array of characters to use for the charset.
|
66
|
+
def initialize(charset)
|
67
|
+
@charset = charset.unshift("\u0000")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Create a charset based on a string to encode.
|
71
|
+
#
|
72
|
+
# Example
|
73
|
+
#
|
74
|
+
# SecretSharing::Charset::DynamicCharset.from_string 'test'
|
75
|
+
# # => #<SecretSharing::Charset::DynamicCharset @charset=['e','t','s']>
|
76
|
+
#
|
77
|
+
# @param string [String] a string to encode with the charset to generate
|
78
|
+
# @return [DynamicCharset] shuffled charset to encode strings to ints
|
79
|
+
def self.from_string(string)
|
80
|
+
DynamicCharset.new string.chars.shuffle.uniq
|
81
|
+
end
|
82
|
+
|
83
|
+
# Calculate a string from an integer.
|
84
|
+
#
|
85
|
+
# Example
|
86
|
+
#
|
87
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
88
|
+
# charset.i_to_s 6
|
89
|
+
# # => "ab"
|
90
|
+
#
|
91
|
+
# @param x [Integer] integer to convert to string
|
92
|
+
# @return [String] converted string
|
93
|
+
def i_to_s(x)
|
94
|
+
unless x.is_a?(Integer) && x >= 0
|
95
|
+
fail ArgumentError, 'x must be a non-negative integer'
|
96
|
+
end
|
97
|
+
|
98
|
+
output = ''
|
99
|
+
while x > 0
|
100
|
+
x, codepoint = x.divmod(length)
|
101
|
+
output.prepend(codepoint_to_char(codepoint))
|
102
|
+
end
|
103
|
+
output
|
104
|
+
end
|
105
|
+
|
106
|
+
# Calculate an integer from a string.
|
107
|
+
#
|
108
|
+
# Example
|
109
|
+
#
|
110
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
111
|
+
# charset.s_to_i "ab"
|
112
|
+
# # => 6
|
113
|
+
#
|
114
|
+
# @param string [Integer] integer to convert to string
|
115
|
+
# @return [String] converted string
|
116
|
+
def s_to_i(string)
|
117
|
+
string.chars.reduce(0) do |output, char|
|
118
|
+
output * length + char_to_codepoint(char)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Convert an integer into its string representation according to the
|
123
|
+
# charset. (only one character)
|
124
|
+
#
|
125
|
+
# Example
|
126
|
+
#
|
127
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
128
|
+
# charset.codepoint_to_char 1
|
129
|
+
# # => "a"
|
130
|
+
#
|
131
|
+
# @param codepoint [Integer] Codepoint to retrieve the character for
|
132
|
+
# @return [String] Retrieved character
|
133
|
+
def codepoint_to_char(codepoint)
|
134
|
+
char = @charset[codepoint]
|
135
|
+
return char unless char.nil?
|
136
|
+
fail ArgumentError, "Codepoint #{codepoint} does not exist in charset"
|
137
|
+
end
|
138
|
+
|
139
|
+
# Convert a single character into its integer representation according to
|
140
|
+
# the charset.
|
141
|
+
#
|
142
|
+
# Example
|
143
|
+
#
|
144
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
145
|
+
# charset.char_to_codepoint 'a'
|
146
|
+
# # => 1
|
147
|
+
#
|
148
|
+
# @param c [String] Character to retrieve its codepoint in the charset
|
149
|
+
# @return [Integer] Codepoint within the charset
|
150
|
+
def char_to_codepoint(c)
|
151
|
+
codepoint = @charset.rindex c
|
152
|
+
return codepoint unless codepoint.nil?
|
153
|
+
error_msg = "Character \"#{c}\" not part of the supported charset"
|
154
|
+
fail ArgumentError, error_msg
|
155
|
+
end
|
156
|
+
|
157
|
+
# Total length of the charset
|
158
|
+
#
|
159
|
+
# Example
|
160
|
+
#
|
161
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
162
|
+
# charset.length
|
163
|
+
# # => 4
|
164
|
+
def length
|
165
|
+
@charset.length
|
166
|
+
end
|
167
|
+
|
168
|
+
# Adds a string representation of the charset to the string, which can
|
169
|
+
# later be used to recreate the charset.
|
170
|
+
#
|
171
|
+
# Example
|
172
|
+
#
|
173
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
174
|
+
# charset.add_to_point('1-2')
|
175
|
+
# # => "abc-1-2"
|
176
|
+
#
|
177
|
+
# @param point_string [String] string to prepend to
|
178
|
+
# @return [String] string representation of charset-point_string
|
179
|
+
def add_to_point(point_string)
|
180
|
+
"#{@charset[1...length].join}-#{point_string}"
|
181
|
+
end
|
182
|
+
|
183
|
+
# Check if the provided string can be represented by the charset.
|
184
|
+
#
|
185
|
+
# Example
|
186
|
+
#
|
187
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
188
|
+
# charset.subset? 'd'
|
189
|
+
# # => false
|
190
|
+
# charset.subset? 'a'
|
191
|
+
# # => true
|
192
|
+
#
|
193
|
+
# @param string [String] Character to retrieve the for codepoint
|
194
|
+
# @return [TrueClass|FalseClass]
|
195
|
+
def subset?(string)
|
196
|
+
(Set.new(string.chars.uniq) - Set.new(@charset)).empty?
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Charset that can represent any string that only consists of ASCII
|
201
|
+
# characters.
|
202
|
+
class ASCIICharset < DynamicCharset
|
203
|
+
# An instance of an ASCIICharset is just a DynamicCharset with the ASCII
|
204
|
+
# characters.
|
205
|
+
def initialize
|
206
|
+
super((1..127).to_a.map(&:chr))
|
207
|
+
end
|
208
|
+
|
209
|
+
# Adds a string representation of the charset to the string (empty string
|
210
|
+
# in case of ASCII, since it is the default charset), which can later be
|
211
|
+
# used to recreate the charset.
|
212
|
+
#
|
213
|
+
# Example
|
214
|
+
#
|
215
|
+
# charset = SecretSharing::Charset.by_charset_string 'abc'
|
216
|
+
# charset.add_to_point('1-2')
|
217
|
+
# # => "abc-1-2"
|
218
|
+
#
|
219
|
+
# @param point_string [String] string to prepend to
|
220
|
+
# @return [String] string representation of charset-point_string
|
221
|
+
def add_to_point(point_string)
|
222
|
+
point_string
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SecretSharing
|
2
|
+
# This class is used to store a two dimensional point consisting of integers.
|
3
|
+
class Point
|
4
|
+
attr_accessor :x, :y
|
5
|
+
|
6
|
+
# Create a Point object.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# Point.new(1, 2)
|
11
|
+
# # => #<Point: @x=1 @y=2>
|
12
|
+
#
|
13
|
+
# @param x [Integer] The x value of the point
|
14
|
+
# @param y [Integer] The y value of the point
|
15
|
+
def initialize(x, y)
|
16
|
+
@x = x
|
17
|
+
@y = y
|
18
|
+
end
|
19
|
+
|
20
|
+
# A nicer inspection of a point object than by default.
|
21
|
+
#
|
22
|
+
# @return [String] String representation of a Point
|
23
|
+
#
|
24
|
+
# Examples
|
25
|
+
#
|
26
|
+
# SecretSharing::Point.new(1, 2).inspect
|
27
|
+
# # => "#<Point: @x=1 @y=2>"
|
28
|
+
def inspect
|
29
|
+
"#<Point: @x=#{x} @y=#{y}>"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"#{x}-#{y.to_s(16)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_string(point_string)
|
37
|
+
x_string, y_string = point_string.split '-'
|
38
|
+
Point.new x_string.to_i, y_string.to_i(16)
|
39
|
+
end
|
40
|
+
|
41
|
+
# An implementation similar to Array#transpose for Arrays of Points
|
42
|
+
#
|
43
|
+
# @return [Array] Two Arrays in an Array
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# point1 = SecretSharing::Point.new(1, 2)
|
48
|
+
# point2 = SecretSharing::Point.new(3, 4)
|
49
|
+
# points = [point1, point2]
|
50
|
+
# Point.transpose(points)
|
51
|
+
# # => [[1, 3], [2, 4]]
|
52
|
+
def self.transpose(points)
|
53
|
+
x_values = []
|
54
|
+
y_values = []
|
55
|
+
|
56
|
+
points.each do |point|
|
57
|
+
x_values << point.x
|
58
|
+
y_values << point.y
|
59
|
+
end
|
60
|
+
[x_values, y_values]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module SecretSharing
|
4
|
+
# The polynomial is used to represent the required random polynomials used in
|
5
|
+
# Shamir's Secret Sharing algorithm.
|
6
|
+
class Polynomial
|
7
|
+
# Create a new instance of a Polynomial with n coefficients, when having
|
8
|
+
# the polynomial in standard polynomial form.
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# Polynomial.new [1, 2, 3]
|
13
|
+
# # => #<SecretSharing::Polynomial:0x0000000 @coefficients=[1, 2, 3]>
|
14
|
+
#
|
15
|
+
# @param coefficients [Array] an array of integers as the coefficients
|
16
|
+
def initialize(coefficients)
|
17
|
+
@coefficients = coefficients
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generate points on the polynomial, that can be used to reconstruct the
|
21
|
+
# polynomial with.
|
22
|
+
#
|
23
|
+
# Example
|
24
|
+
#
|
25
|
+
# SecretSharing::Polynomial.new([1, 2, 3, 4]).points(3, 7)
|
26
|
+
# # => [#<Point: @x=1 @y=3>, #<Point: @x=2 @y=0>, #<Point: @x=3 @y=2>]
|
27
|
+
#
|
28
|
+
# @param num_points [Integer] number of points to generate
|
29
|
+
# @param prime [Integer] prime for calculation in finite field
|
30
|
+
# @return [Array] array of calculated points
|
31
|
+
def points(num_points, prime)
|
32
|
+
(1..num_points).map do |x|
|
33
|
+
y = @coefficients[0]
|
34
|
+
(1...@coefficients.length).each do |i|
|
35
|
+
exponentiation = x**i % prime
|
36
|
+
term = (@coefficients[i] * exponentiation) % prime
|
37
|
+
y = (y + term) % prime
|
38
|
+
end
|
39
|
+
Point.new(x, y)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Generate a random polynomial with a specific degree, defined x=0 value
|
44
|
+
# and an upper limit for the coefficients of the polynomial.
|
45
|
+
#
|
46
|
+
# Example
|
47
|
+
#
|
48
|
+
# Polynomial.random(2, 3, 7)
|
49
|
+
# # => #<SecretSharing::Polynomial:0x0000000 @coefficients=[3, 0, 4]>
|
50
|
+
#
|
51
|
+
# @param degree [Integer] degree of the polynomial to generate
|
52
|
+
# @param intercept [Integer] the y value for x=0
|
53
|
+
# @param upper_bound [Integer] the highest value of a single coefficient
|
54
|
+
def self.random(degree, intercept, upper_bound)
|
55
|
+
fail ArgumentError, 'Degree must be a non-negative number' if degree < 0
|
56
|
+
|
57
|
+
coefficients = (0...degree).reduce([intercept]) do |accumulator, _i|
|
58
|
+
accumulator << SecureRandom.random_number(upper_bound)
|
59
|
+
end
|
60
|
+
Polynomial.new coefficients
|
61
|
+
end
|
62
|
+
|
63
|
+
# Generate points from a secret integer.
|
64
|
+
#
|
65
|
+
# Example
|
66
|
+
#
|
67
|
+
# SecretSharing::Polynomial.points_from_secret(123, 2, 3)
|
68
|
+
# # => [#<Point: @x=1 @y=109>, #<Point: @x=2 @y=95>, #<Point: @x=3 @y=81>]
|
69
|
+
#
|
70
|
+
# @param secret_int [Integer] the secret to divide into points
|
71
|
+
# @param point_threshold [Integer] number of points to reconstruct
|
72
|
+
# @param num_points [Integer] number of points to generate
|
73
|
+
# @return [Polynomial] the generated polynomial
|
74
|
+
def self.points_from_secret(secret_int, point_threshold, num_points)
|
75
|
+
prime = SecretSharing::Prime.large_enough_prime([secret_int, num_points])
|
76
|
+
fail ArgumentError, 'Secret is too long' if prime.nil?
|
77
|
+
fail ArgumentError, 'Threshold must be at least 2' if point_threshold < 2
|
78
|
+
fail ArgumentError, 'Threshold must be less than the total number of points' if point_threshold > num_points
|
79
|
+
|
80
|
+
polynomial = SecretSharing::Polynomial.random(point_threshold - 1,
|
81
|
+
secret_int,
|
82
|
+
prime)
|
83
|
+
polynomial.points(num_points, prime)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Modular lagrange interpolation
|
87
|
+
def self.modular_lagrange_interpolation(points)
|
88
|
+
y_values = Point.transpose(points)[1]
|
89
|
+
prime = SecretSharing::Prime.large_enough_prime(y_values)
|
90
|
+
points.reduce(0) do |f_x, point|
|
91
|
+
numerator, denominator = lagrange_fraction(points, point, prime)
|
92
|
+
lagrange_polynomial = numerator * mod_inverse(denominator, prime)
|
93
|
+
(prime + f_x + (point.y * lagrange_polynomial)) % prime
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# part of the lagrange interpolation
|
98
|
+
def self.lagrange_fraction(points, current, prime)
|
99
|
+
numerator, denominator = 1, 1
|
100
|
+
points.each do |point|
|
101
|
+
if point != current
|
102
|
+
numerator = (numerator * (0 - point.x)) % prime
|
103
|
+
denominator = (denominator * (current.x - point.x)) % prime
|
104
|
+
end
|
105
|
+
end
|
106
|
+
[numerator, denominator]
|
107
|
+
end
|
108
|
+
|
109
|
+
# inverse modulo
|
110
|
+
def self.mod_inverse(k, prime)
|
111
|
+
k = k % prime
|
112
|
+
r = egcd(prime, k.abs)[2]
|
113
|
+
(prime + r) % prime
|
114
|
+
end
|
115
|
+
|
116
|
+
# extended Euclidean algorithm
|
117
|
+
def self.egcd(a, b)
|
118
|
+
return [b, 0, 1] if a == 0
|
119
|
+
g, y, x = egcd(b % a, a)
|
120
|
+
[g, x - b.div(a) * y, y]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SecretSharing
|
2
|
+
# This module is used to generate/calculate/retrieve primes.
|
3
|
+
module Prime
|
4
|
+
# Retrieves the next largest prime for the largest number in batch
|
5
|
+
#
|
6
|
+
# Example
|
7
|
+
#
|
8
|
+
# Prime.large_enough_prime [1, 2, 3, 4]
|
9
|
+
# # => 7
|
10
|
+
#
|
11
|
+
# @param batch [Array] a list of integers
|
12
|
+
# @return [Integer] the next largest prime or nil if numbers too large
|
13
|
+
def large_enough_prime(batch)
|
14
|
+
standard_primes = mersenne_primes + [
|
15
|
+
# smallest 257, 321 and 385 bit primes
|
16
|
+
2**256 + 297, 2**320 + 27, 2**384 + 231
|
17
|
+
].sort
|
18
|
+
|
19
|
+
standard_primes.each do |prime|
|
20
|
+
greater_than_prime = Array.new(batch).select { |i| i if i > prime }
|
21
|
+
return prime if greater_than_prime.empty?
|
22
|
+
end
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Calculates the first 15 mersenne primes
|
29
|
+
def mersenne_primes
|
30
|
+
mersenne_prime_exponents = [
|
31
|
+
2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279
|
32
|
+
]
|
33
|
+
mersenne_prime_exponents.map do |exp|
|
34
|
+
prime = 1
|
35
|
+
prime *= 2**exp
|
36
|
+
prime -= 1
|
37
|
+
prime
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module_function :mersenne_primes,
|
42
|
+
:large_enough_prime
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SecretSharing
|
2
|
+
# A share is an object that encapsulates the properties of a share created by
|
3
|
+
# Shamir's Secret Sharing algorithm.
|
4
|
+
class Share
|
5
|
+
attr_reader :charset, :point
|
6
|
+
|
7
|
+
# Create a share object
|
8
|
+
#
|
9
|
+
# Example
|
10
|
+
#
|
11
|
+
# charset = SecretSharing::ASCIICharset.new
|
12
|
+
# point = SecretSharing::Point.new 1, 2
|
13
|
+
# SecretSharing::Share.new charset, point
|
14
|
+
# # => #<SecretSharing::Share:0x0000000 @charset=..., @point=...>
|
15
|
+
#
|
16
|
+
# @param charset [SecretSharing::Charset::DynamicCharset]
|
17
|
+
# @param point [SecretSharing::Point]
|
18
|
+
def initialize(charset, point)
|
19
|
+
@charset = charset
|
20
|
+
@point = point
|
21
|
+
end
|
22
|
+
|
23
|
+
# A string representation of a share.
|
24
|
+
#
|
25
|
+
# Example
|
26
|
+
#
|
27
|
+
# charset = SecretSharing::ASCIICharset.new
|
28
|
+
# point = SecretSharing::Point.new 1, 2
|
29
|
+
# SecretSharing::Share.new(charset, point).to_s
|
30
|
+
# # => "1-2"
|
31
|
+
#
|
32
|
+
def to_s
|
33
|
+
charset.add_to_point(point.to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Creates a share object from its string representation.
|
37
|
+
#
|
38
|
+
# Example
|
39
|
+
#
|
40
|
+
# SecretSharing::Share.from_string "1-2"
|
41
|
+
# # => #<SecretSharing::Share:0x0000000 @charset=..., @point=...>
|
42
|
+
#
|
43
|
+
def self.from_string(share_string)
|
44
|
+
charset_string, point_string = parse share_string
|
45
|
+
charset = Charset.by_charset_string charset_string
|
46
|
+
point = Point.from_string(point_string)
|
47
|
+
Share.new(charset, point)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Parses the string representation of a share into charset and point
|
51
|
+
# coordinates out of a string representation of a share. Since the charset
|
52
|
+
# part can have a "-" in it it must be parsed backwards and not just
|
53
|
+
# splitted by "-".
|
54
|
+
#
|
55
|
+
# Example
|
56
|
+
#
|
57
|
+
# SecretSharing::Share.parse '1-2'
|
58
|
+
# # => ['', '1-2']
|
59
|
+
#
|
60
|
+
# @param share_string [String] a string representation of a share
|
61
|
+
# @return an array in form of [charset_string, point_string]
|
62
|
+
#
|
63
|
+
def self.parse(share_string)
|
64
|
+
charset_string, point_string = '', ''
|
65
|
+
number_of_dashes = 0
|
66
|
+
share_string.chars.reverse.each do |char|
|
67
|
+
charset_string.prepend(char) if number_of_dashes >= 2
|
68
|
+
number_of_dashes += 1 if char == '-'
|
69
|
+
point_string.prepend(char) if number_of_dashes <= 1
|
70
|
+
end
|
71
|
+
[charset_string, point_string]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'secret_sharing/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'secret_sharing'
|
8
|
+
spec.version = SecretSharing::VERSION
|
9
|
+
spec.authors = ['flower-pot']
|
10
|
+
spec.email = ['fbranczyk@gmail.com']
|
11
|
+
spec.summary = 'Ruby implementation of sharmir\'s secret sharing'
|
12
|
+
spec.description = 'Divide, share and reconstruct secrets.'
|
13
|
+
spec.homepage = 'https://github.com/duse-io/secret_sharing_ruby'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.test_files = `git ls-files spec`.split($INPUT_RECORD_SEPARATOR)
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
describe SecretSharing::Charset do
|
4
|
+
context 'encode and decode' do
|
5
|
+
it 'should be able to decode randomly generated encoded strings' do
|
6
|
+
50.times do
|
7
|
+
str = SecureRandom.base64(100)
|
8
|
+
charset = SecretSharing::Charset.by_charset_string(str)
|
9
|
+
encoded = charset.s_to_i(str)
|
10
|
+
decoded = charset.i_to_s(encoded)
|
11
|
+
expect(decoded).to eq(str)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should throw errors when characters that are not in charset' do
|
16
|
+
encoder = SecretSharing::Charset.by_charset_string('test')
|
17
|
+
expect { encoder.codepoint_to_char(5) }.to raise_error(ArgumentError)
|
18
|
+
expect { encoder.char_to_codepoint('r') }.to raise_error(ArgumentError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should throw an error when trying to convert negative numbers' do
|
22
|
+
encoder = SecretSharing::Charset.by_charset_string('test')
|
23
|
+
expect { encoder.i_to_s(-1) }.to raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should throw an error when trying to convert something non-integer' do
|
27
|
+
encoder = SecretSharing::Charset.by_charset_string('test')
|
28
|
+
expect { encoder.i_to_s('error') }.to raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return the correct charset for ""' do
|
32
|
+
charset = SecretSharing::Charset.by_charset_string('')
|
33
|
+
expect(charset).to be_a SecretSharing::Charset::ASCIICharset
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/point_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
describe SecretSharing::Point do
|
2
|
+
it 'should follow the ruby convention when inspecting' do
|
3
|
+
point = SecretSharing::Point.new(1, 2)
|
4
|
+
expect(point.inspect).to eq('#<Point: @x=1 @y=2>')
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'should correctly stringify a point' do
|
8
|
+
expect(SecretSharing::Point.new(1, 2).to_s).to eq('1-2')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should correctly create a point from a correctly formatted string' do
|
12
|
+
expect(SecretSharing::Point.new(1, 2).to_s).to eq('1-2')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should be able to recreate a point from its string representation' do
|
16
|
+
point = SecretSharing::Point.new(1, 2)
|
17
|
+
string = point.to_s
|
18
|
+
reconstructed_point = SecretSharing::Point.from_string string
|
19
|
+
expect(reconstructed_point.x).to eq(point.x)
|
20
|
+
expect(reconstructed_point.y).to eq(point.y)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe SecretSharing::Charset do
|
2
|
+
it 'should error when trying to generate a polynomial with negative degree' do
|
3
|
+
random_generator = -> { SecretSharing::Polynomial.random(-1, 1, 12) }
|
4
|
+
expect(&random_generator).to raise_error(ArgumentError)
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'should error when the secret is to long' do
|
8
|
+
secret = 2**10_000
|
9
|
+
block = -> { SecretSharing::Polynomial.points_from_secret(secret, 2, 3) }
|
10
|
+
expect(&block).to raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should error when the point threshold is too small' do
|
14
|
+
block = -> { SecretSharing::Polynomial.points_from_secret(123, 1, 3) }
|
15
|
+
expect(&block).to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should error when the point threshold is larger than total points' do
|
19
|
+
block = -> { SecretSharing::Polynomial.points_from_secret(123, 3, 2) }
|
20
|
+
expect(&block).to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
end
|
data/spec/prime_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
describe SecretSharing do
|
4
|
+
it 'should encrypt and decrypt correctly' do
|
5
|
+
50.times do
|
6
|
+
secret = SecureRandom.base64(130)
|
7
|
+
num_of_shares = 2 + SecureRandom.random_number(100)
|
8
|
+
shares = SecretSharing.split_secret(secret, 2, num_of_shares)
|
9
|
+
expect(SecretSharing.recover_secret(shares[0..1])).to eq(secret)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should work with non ascii characters as well' do
|
14
|
+
secret = 'κόσμε'
|
15
|
+
num_of_shares = 2 + SecureRandom.random_number(100)
|
16
|
+
shares = SecretSharing.split_secret(secret, 2, num_of_shares)
|
17
|
+
expect(SecretSharing.recover_secret(shares[0..1])).to eq(secret)
|
18
|
+
end
|
19
|
+
end
|
data/spec/share_spec.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
describe SecretSharing::Share do
|
2
|
+
it 'correctly parses a string representation of a share' do
|
3
|
+
expect(SecretSharing::Share.parse('$$ASCII-1-2')).to eq(['$$ASCII', '1-2'])
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'correctly parses a share when charset contains a "-"' do
|
7
|
+
expect(SecretSharing::Share.parse('tes--1-2')).to eq(['tes-', '1-2'])
|
8
|
+
end
|
9
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
4
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
5
|
+
# files.
|
6
|
+
#
|
7
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
8
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
9
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
10
|
+
# individual file that may not need all of that loaded. Instead, consider
|
11
|
+
# making a separate helper file that requires the additional dependencies and
|
12
|
+
# performs the additional setup, and require it from the spec files that
|
13
|
+
# actually need it.
|
14
|
+
#
|
15
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
16
|
+
# users commonly want.
|
17
|
+
#
|
18
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
19
|
+
|
20
|
+
unless ENV['CI']
|
21
|
+
require 'simplecov'
|
22
|
+
SimpleCov.start
|
23
|
+
end
|
24
|
+
|
25
|
+
if ENV['CI']
|
26
|
+
require 'coveralls'
|
27
|
+
Coveralls.wear!
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'secret_sharing'
|
31
|
+
|
32
|
+
RSpec.configure do |config|
|
33
|
+
# rspec-expectations config goes here. You can use an alternate
|
34
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
35
|
+
# assertions if you prefer.
|
36
|
+
config.expect_with :rspec do |expectations|
|
37
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
38
|
+
# and `failure_message` of custom matchers include text for helper methods
|
39
|
+
# defined using `chain`, e.g.:
|
40
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
41
|
+
# # => "be bigger than 2 and smaller than 4"
|
42
|
+
# ...rather than:
|
43
|
+
# # => "be bigger than 2"
|
44
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
45
|
+
end
|
46
|
+
|
47
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
48
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
49
|
+
config.mock_with :rspec do |mocks|
|
50
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
51
|
+
# a real object. This is generally recommended, and will default to
|
52
|
+
# `true` in RSpec 4.
|
53
|
+
mocks.verify_partial_doubles = true
|
54
|
+
end
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: secret_sharing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- flower-pot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Divide, share and reconstruct secrets.
|
14
|
+
email:
|
15
|
+
- fbranczyk@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- ".rspec"
|
22
|
+
- ".rubocop.yml"
|
23
|
+
- ".travis.yml"
|
24
|
+
- ".yardops"
|
25
|
+
- Gemfile
|
26
|
+
- Gemfile.lock
|
27
|
+
- LICENSE
|
28
|
+
- README.md
|
29
|
+
- Rakefile
|
30
|
+
- lib/secret_sharing.rb
|
31
|
+
- lib/secret_sharing/charset.rb
|
32
|
+
- lib/secret_sharing/point.rb
|
33
|
+
- lib/secret_sharing/polynomial.rb
|
34
|
+
- lib/secret_sharing/prime.rb
|
35
|
+
- lib/secret_sharing/share.rb
|
36
|
+
- lib/secret_sharing/version.rb
|
37
|
+
- secret_sharing.gemspec
|
38
|
+
- spec/charset_spec.rb
|
39
|
+
- spec/point_spec.rb
|
40
|
+
- spec/polynomial_spec.rb
|
41
|
+
- spec/prime_spec.rb
|
42
|
+
- spec/secret_sharing_spec.rb
|
43
|
+
- spec/share_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
homepage: https://github.com/duse-io/secret_sharing_ruby
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
metadata: {}
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 2.4.3
|
66
|
+
signing_key:
|
67
|
+
specification_version: 4
|
68
|
+
summary: Ruby implementation of sharmir's secret sharing
|
69
|
+
test_files:
|
70
|
+
- spec/charset_spec.rb
|
71
|
+
- spec/point_spec.rb
|
72
|
+
- spec/polynomial_spec.rb
|
73
|
+
- spec/prime_spec.rb
|
74
|
+
- spec/secret_sharing_spec.rb
|
75
|
+
- spec/share_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
has_rdoc:
|