shamir-secret-sharing 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d07e642746c89a96dde0b5f5d66fa254b4cfe3d3
4
+ data.tar.gz: 613b4c2987524ee3fd2ee1a927dc49eb0ba98867
5
+ SHA512:
6
+ metadata.gz: b12215854edfb42ed511d29f5e58548faef927cf785a5328690161de11ea948ee82d1232eb19831eead3e6ccb073b1e9fa1788de810c6e7677238efcf6fabc98
7
+ data.tar.gz: db8dae71854f87544628d1d78f4e76601c873e304c3398d84a889867dbb5c45ffae1fe1b1311e8dd877bddd7d3765d6fc962a6758875883d55c5e307d81119e2
@@ -0,0 +1,75 @@
1
+ = shamir-secret-sharing
2
+
3
+ This is a ruby library for Shamir's Secret Sharing. ( http://en.wikipedia.org/wiki/Shamir's_Secret_Sharing )
4
+
5
+ == Compatible with...
6
+
7
+ * ruby 1.9.3
8
+ * ruby 2.0.0
9
+
10
+
11
+ == Installation
12
+
13
+ We assume you already have a ruby 1.9 or 2.0 compatible interpreter and rubygems environment.
14
+
15
+ git clone https://github.com/lian/shamir-secret-sharing.git; cd shamir-secret-sharing
16
+ irb -Ilib -rshamir-secret-sharing
17
+
18
+ If you want to have it available system-wide, just build the gem and install it:
19
+
20
+ gem build shamir-secret-sharing.gemspec && gem install shamir-secret-sharing-*.gem
21
+
22
+ == Tests
23
+
24
+ The tests can be run with
25
+
26
+ rake
27
+
28
+ If you make changes to the code or add functionality, please also add tests.
29
+
30
+ = Example
31
+
32
+ == Split and Combine
33
+
34
+ # split a secret into 4 shares. 3 of them are needed to combine the secret again.
35
+ shares = ShamirSecretSharing::Base58.split(secret="hello", available=4, needed=3)
36
+ shares #=> ["FPGPdS98vRUCy9", "VmTjT28nES7Pck", "k9eRjVVpWP7uzj", "zXqDJNRpPttPjR"]
37
+
38
+ # combine the secret again using at least 3 shares
39
+ ShamirSecretSharing::Base58.combine( ["VmTjT28nES7Pck", "zXqDJNRpPttPjR", "k9eRjVVpWP7uzj"] )
40
+ #=> "hello"
41
+
42
+ # not enough shares
43
+ ShamirSecretSharing::Base58.combine( ["VmTjT28nES7Pck", "zXqDJNRpPttPjR"] )
44
+ #=> false
45
+
46
+ # wrong shares
47
+ ShamirSecretSharing::Base58.combine( ["VmTjT28nES7Pck", "zXqDJNRpPttPjR", "some-wrong-share"] )
48
+ #=> false
49
+
50
+ == Encypt and Decrypt
51
+
52
+ Split and combine only work with a secret length below 512 bytes and the resulting share lengths are equivalent to the secret length. That means a 128 byte secret has a very long (128 byte) share length.
53
+ Encrypt and decrypt are used to encrypt a large piece of data while keeping the share lengths to a fixed and reasonable size. It does that by AES-256-CBC encrypting the data with a random key and only then splitting that fixed size key into shares.
54
+
55
+ # encrypt the data and create 4 shares. Later 3 shares and the encrypted data are needed to decrypt it again. This example uses a 96 bit random key for encryption.
56
+ shares, encrypted = ShamirSecretSharing::Base58.encrypt(data="Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 4, 3, 96)
57
+ shares #=> ["3QZNRFYZHKUpnv96cE6eVwPP", "5p611mjtxXBgPDx1m2SRwCKr", "8DcdGMD9i3kWGrYEVGtQLSWA", "Ad9NLPDVSnHfbqVhnmNn8YK4"]
58
+ encrypted #=> "4PHcPwzzk48EjmusQz27t3X1rS7hAi9kwKgZJ7UMDR99rJgi19aHM8e7syh6uVrJ6HbcbgRmEUcR7hmkDvrYaJXH"
59
+
60
+ # combine the shares and decrypt the encrypted data
61
+ ShamirSecretSharing::Base58.decrypt(["3QZNRFYZHKUpnv96cE6eVwPP", "8DcdGMD9i3kWGrYEVGtQLSWA", "Ad9NLPDVSnHfbqVhnmNn8YK4"], "4PHcPwzzk48EjmusQz27t3X1rS7hAi9kwKgZJ7UMDR99rJgi19aHM8e7syh6uVrJ6HbcbgRmEUcR7hmkDvrYaJXH")
62
+ #=> "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
63
+
64
+ # not enough shares
65
+ ShamirSecretSharing::Base58.decrypt(["3QZNRFYZHKUpnv96cE6eVwPP", "8DcdGMD9i3kWGrYEVGtQLSWA"], "4PHcPwzzk48EjmusQz27t3X1rS7hAi9kwKgZJ7UMDR99rJgi19aHM8e7syh6uVrJ6HbcbgRmEUcR7hmkDvrYaJXH")
66
+ #=> false
67
+
68
+ # wrong shares
69
+ ShamirSecretSharing::Base58.decrypt(["3QZNRFYZHKUpnv96cE6eVwPP", "8DcdGMD9i3kWGrYEVGtQLSWA", "some-wrong-share"], "4PHcPwzzk48EjmusQz27t3X1rS7hAi9kwKgZJ7UMDR99rJgi19aHM8e7syh6uVrJ6HbcbgRmEUcR7hmkDvrYaJXH")
70
+ #=> false
71
+
72
+ # wrong encrypted data
73
+ ShamirSecretSharing::Base58.decrypt(["3QZNRFYZHKUpnv96cE6eVwPP", "8DcdGMD9i3kWGrYEVGtQLSWA", "Ad9NLPDVSnHfbqVhnmNn8YK4"], "wrong-encrypted-data")
74
+ #=> false
75
+
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'bundler/gem_tasks'
3
+ rescue LoadError
4
+ end
5
+
6
+ RUBY = 'ruby' unless defined?(RUBY)
7
+
8
+ task :default => :tests
9
+
10
+ # test runner [0/61]
11
+ desc 'Run all bacon specs with pretty output'
12
+ task :tests do
13
+ sh RUBY, 'lib/shamir-secret-sharing.rb'
14
+ end
@@ -0,0 +1,380 @@
1
+ require 'openssl'
2
+ require 'digest/sha1'
3
+
4
+ class ShamirSecretSharing
5
+ VERSION = '0.0.1'
6
+
7
+ def self.pack(shares); shares; end
8
+ def self.unpack(shares); shares; end
9
+ def self.encode(string); string; end
10
+ def self.decode(string); string; end
11
+
12
+ def self.smallest_prime_of_bytelength(bytelength)
13
+ n = OpenSSL::BN.new((2**(bytelength*8)+1).to_s)
14
+ loop{ break if n.prime_fasttest?(20); n += 2 }
15
+ n
16
+ end
17
+
18
+ def self.split(secret, available, needed, do_data_checksum=true)
19
+ raise ArgumentError, "needed must be <= available" unless needed <= available
20
+ raise ArgumentError, "needed must be >= 2" unless needed >= 2
21
+ raise ArgumentError, "available must be <= 250" unless available <= 250
22
+
23
+ if do_data_checksum
24
+ checksum = Digest::SHA512.digest(secret)[0...2]
25
+ num_bytes = secret.bytesize+2
26
+ secret = OpenSSL::BN.new((checksum + secret).unpack("H*")[0], 16) rescue OpenSSL::BN.new("0")
27
+ #num_bytes = secret.to_s(0).unpack("N")[0]
28
+ raise ArgumentError, "bytelength of secret must be >= 1" if num_bytes < 3
29
+ raise ArgumentError, "bytelength of secret must be <= 512" if num_bytes > 513
30
+ else
31
+ num_bytes = secret.bytesize
32
+ secret = OpenSSL::BN.new(secret.unpack("H*")[0], 16) rescue OpenSSL::BN.new("0") # without checksum
33
+ raise ArgumentError, "bytelength of secret must be >= 1" if num_bytes < 1
34
+ raise ArgumentError, "bytelength of secret must be <= 512" if num_bytes > 512
35
+ end
36
+
37
+ prime = smallest_prime_of_bytelength(num_bytes)
38
+ coef = [ secret ] + Array.new(needed-1){ OpenSSL::BN.rand(num_bytes * 8) }
39
+
40
+ shares = (1..available).map{|x|
41
+ x = OpenSSL::BN.new(x.to_s)
42
+ y = coef.each_with_index.inject(OpenSSL::BN.new("0")){|acc, (c, idx)|
43
+ acc + c * x.mod_exp(idx, prime)
44
+ } % prime
45
+ [x, num_bytes, y]
46
+ }
47
+ pack(shares)
48
+ end
49
+
50
+ def self.combine(shares, do_raise=false, do_data_checksum=true)
51
+ return false if shares.size < 2
52
+ shares = unpack(shares)
53
+ num_bytes = shares[0][1]
54
+ prime = smallest_prime_of_bytelength(num_bytes)
55
+
56
+ secret = shares.inject(OpenSSL::BN.new("0")){|secret,(x,num_bytes,y)|
57
+ l_x = l(x, shares, prime)
58
+ summand = OpenSSL::BN.new(y.to_s).mod_mul(l_x, prime)
59
+ secret = (secret + summand) % prime
60
+ }
61
+ if do_data_checksum
62
+ checksum, secret = [ secret.to_s(16).rjust(num_bytes*2, '0') ].pack("H*").unpack("a2a*")
63
+ checksum == Digest::SHA512.digest(secret)[0...2] ? secret : false
64
+ else
65
+ secret = [ secret.to_s(16).rjust(num_bytes*2, '0') ].pack("H*")
66
+ end
67
+ rescue ShareChecksumError, ShareDecodeError => ex
68
+ raise if do_raise
69
+ false
70
+ end
71
+
72
+ # Part of the Lagrange interpolation.
73
+ # This is l_j(0), i.e. # \prod_{x_j \neq x_i} \frac{-x_i}{x_j - x_i}
74
+ # for more information compare Wikipedia: # http://en.wikipedia.org/wiki/Lagrange_form
75
+ def self.l(current_x, shares, prime)
76
+ shares.select{|x,num_bytes,y| x != current_x }.map{|x,num_bytes,y|
77
+ minus_xi = OpenSSL::BN.new((-x).to_s)
78
+ one_over_xj_minus_xi = OpenSSL::BN.new((current_x - x).to_s).mod_inverse(prime)
79
+ minus_xi.mod_mul(one_over_xj_minus_xi, prime)
80
+ }.inject{|p,f| p.mod_mul(f, prime) }
81
+ end
82
+
83
+ def self.encrypt(data, available, needed, key_bit_length=128)
84
+ key = key_bit_length.is_a?(String) ? key_bit_length : [ OpenSSL::BN.rand(key_bit_length).to_s(16) ].pack("H*")
85
+ c = OpenSSL::Cipher.new('aes-256-cbc').encrypt
86
+ c.key, c.iv = Digest::SHA512.digest(key).unpack("a32a16")
87
+ encrypted = c.update(data) << c.final
88
+ [ split(key, available, needed), encode(encrypted) ]
89
+ end
90
+
91
+ def self.decrypt(shares, encrypted, do_raise=false)
92
+ key = combine(shares, do_raise)
93
+ return false unless key
94
+
95
+ encrypted_decoded = decode(encrypted) rescue nil
96
+ raise ShareDecodeError, "encrypted_data: #{encrypted}" unless encrypted_decoded
97
+
98
+ return false unless encrypted and key
99
+ c = OpenSSL::Cipher.new('aes-256-cbc').decrypt
100
+ c.key, c.iv = Digest::SHA512.digest(key).unpack("a32a16")
101
+ data = c.update(encrypted_decoded) << c.final
102
+ data
103
+ rescue OpenSSL::Cipher::CipherError, ShareDecodeError
104
+ raise if do_raise
105
+ false
106
+ end
107
+
108
+ def self.split_with_sanity_check(secret, available, needed, do_data_checksum=true)
109
+ shares = split(secret, available, needed, do_data_checksum)
110
+ success = true
111
+ needed.upto(available).each{|n| shares.permutation(n).each{|shares| success = false if combine(shares) != secret } }
112
+ (needed-1).downto(2).each{|n| shares.permutation(n).each{|shares| success = false if combine(shares) != false } }
113
+ raise ShareSanityCheckError if success != true
114
+ shares
115
+ rescue ShareSanityCheckError
116
+ retry
117
+ end
118
+
119
+ def self.encrypt_with_sanity_check(data, available, needed, key_bit_length=128)
120
+ shares, encrypted = encrypt(data, available, needed, key_bit_length)
121
+ success = true
122
+ needed.upto(available).each{|n| shares.permutation(n).each{|shares| success = false if decrypt(shares, encrypted) != data } }
123
+ (needed-1).downto(2).each{|n| shares.permutation(n).each{|shares| success = false if decrypt(shares, encrypted) != false } }
124
+ raise ShareSanityCheckError if success != true
125
+ [shares, encrypted]
126
+ rescue ShareSanityCheckError
127
+ retry
128
+ end
129
+
130
+
131
+ class Number < ShamirSecretSharing
132
+ def self.split(secret, available, needed)
133
+ num = OpenSSL::BN.new(secret.to_s)
134
+ raise ArgumentError, "available must be <= 9" unless available <= 9
135
+ raise ArgumentError, "num too large. bytelength must be <= 9" unless num.num_bytes <= 9
136
+ shares = ShamirSecretSharing.split([num.to_s(16)].pack("H*"), available, needed, do_data_checksum=nil)
137
+ shares.map{|i| i.join.to_i }
138
+ end
139
+
140
+ def self.combine(shares)
141
+ shares = shares.map{|i| i.to_s.match(/(\d)(\d)(\d+)/); [$1.to_i, $2.to_i, $3.to_i] }
142
+ ShamirSecretSharing.combine(shares, do_raise=false, do_data_checksum=nil).unpack("H*")[0].to_i(16)
143
+ end
144
+ end
145
+
146
+ class ShareChecksumError < ::StandardError; end
147
+ class ShareDecodeError < ::StandardError; end
148
+ class ShareSanityCheckError < ::StandardError; end
149
+
150
+ class Packed < ShamirSecretSharing # packing format and checkum
151
+ def self.pack(shares)
152
+ shares.map{|x,num_bytes,y|
153
+ buf = [ x, num_bytes, y.to_s(16) ].pack("CnH*")
154
+ checksum = Digest::SHA512.digest(buf)[0...2]
155
+ encode(checksum << buf)
156
+ }
157
+ end
158
+ def self.unpack(shares)
159
+ shares.map{|i|
160
+ buf = decode(i) rescue nil
161
+ raise ShareDecodeError, "share: #{i}" unless buf
162
+ checksum, buf = buf.unpack("a2a*")
163
+ raise ShareChecksumError, "share: #{i}" unless checksum == Digest::SHA512.digest(buf)[0...2]
164
+ i = buf.unpack("CnH*"); [ i[0], i[1], i[2].to_i(16) ]
165
+ }
166
+ end
167
+ end
168
+
169
+ class Base58 < Packed
170
+ def self.encode(string)
171
+ string = string.unpack("H*")[0]
172
+ leading_zero_bytes = (string.match(/^([0]+)/) ? $1 : '').size / 2
173
+ ("1"*leading_zero_bytes) + int_to_base58( string.to_i(16) )
174
+ end
175
+ def self.decode(string)
176
+ leading_zero_bytes = (string.match(/^([1]+)/) ? $1 : '').size
177
+ buf = base58_to_int(string).to_s(16); buf = (buf.bytesize.odd? ? '0'+buf : buf)
178
+ [ ("00"*leading_zero_bytes) + buf ].pack("H*")
179
+ end
180
+ def self.int_to_base58(int_val, leading_zero_bytes=0)
181
+ alpha, base58_val, base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", "", 58
182
+ while int_val > 0
183
+ int_val, remainder = int_val.divmod(base)
184
+ base58_val = alpha[remainder] + base58_val
185
+ end; base58_val
186
+ end
187
+
188
+ def self.base58_to_int(base58_val)
189
+ alpha, base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", 58
190
+ base58_val.reverse.each_char.with_index.inject(0) do |int_val, (char,index)|
191
+ raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
192
+ int_val + char_index*(base**index)
193
+ end
194
+ end
195
+ end
196
+
197
+ class Base64 < Packed
198
+ def self.encode(string); [string].pack("m0"); end
199
+ def self.decode(string); string.unpack("m0")[0]; end
200
+ end
201
+
202
+ class Hex < Packed
203
+ def self.encode(string); string.unpack("H*")[0]; end
204
+ def self.decode(string); [string].pack("H*"); end
205
+ end
206
+ end
207
+
208
+
209
+
210
+
211
+ if $0 == __FILE__
212
+ require "minitest/autorun"
213
+
214
+ class MiniTest::Unit::TestCase
215
+ def assert_raises_and_message(klass, msg, &blk)
216
+ err = assert_raises(klass, &blk); assert_equal msg, err.message
217
+ end
218
+ end
219
+
220
+
221
+ class TestShamirSecretSharing < MiniTest::Unit::TestCase
222
+
223
+ def helper(&b)
224
+ [ [6,3], [10, 2], [3,2], [100, 30] ].each{|available,needed| b.call(available, needed) }
225
+ end
226
+
227
+
228
+ def test_shamir_base58
229
+ secret = "hello"
230
+ helper{|available,needed|
231
+ shares = ShamirSecretSharing::Base58.split(secret, available, needed)
232
+ assert_equal secret, ShamirSecretSharing::Base58.combine(shares.shuffle[0...needed])
233
+ }
234
+
235
+ shares = ShamirSecretSharing::Base58.split_with_sanity_check(secret, available=3, needed=2)
236
+ assert_equal secret, ShamirSecretSharing::Base58.combine(shares.shuffle[0...needed])
237
+ end
238
+
239
+ def test_shamir_base64
240
+ secret = "hello"
241
+ helper{|available,needed|
242
+ shares = ShamirSecretSharing::Base64.split(secret, available, needed)
243
+ assert_equal secret, ShamirSecretSharing::Base64.combine(shares.shuffle[0...needed])
244
+ }
245
+ end
246
+
247
+ def test_shamir_hex
248
+ secret = "hello"
249
+ helper{|available,needed|
250
+ shares = ShamirSecretSharing::Hex.split(secret, available, needed)
251
+ assert_equal secret, ShamirSecretSharing::Hex.combine(shares.shuffle[0...needed])
252
+ }
253
+ end
254
+
255
+ def test_shamir_number
256
+ secret = 123
257
+ shares = ShamirSecretSharing::Number.split(secret, 6, 3)
258
+ assert_equal secret, ShamirSecretSharing::Number.combine(shares.shuffle[0...3])
259
+ end
260
+
261
+ def test_shamir_base58_encrypt
262
+ text = "A"*32
263
+ helper{|available,needed|
264
+ shares, encrypted = ShamirSecretSharing::Base58.encrypt(text, available, needed, 96)
265
+ assert_equal text, ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...needed], encrypted)
266
+ }
267
+
268
+ shares, encrypted = ShamirSecretSharing::Base58.encrypt_with_sanity_check(text, available=3, needed=2)
269
+ assert_equal text, ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...needed], encrypted)
270
+ end
271
+
272
+ def test_shamir_base58_encrypt_sanity_checks
273
+ klass = ShamirSecretSharing::Base58
274
+ checks, success = 5, true
275
+ [
276
+ [2,3], [2,4], [3,5]
277
+ ].each{|needed,available|
278
+ checks.times{
279
+ data = "A"*32
280
+ shares, encrypted = klass.encrypt(data, available, needed, 96)
281
+ needed.upto(available).each{|n|
282
+ shares.permutation(n).each{|shares| success = false if klass.decrypt(shares, encrypted, true) != data }
283
+ }
284
+ (needed-1).downto(2).each{|n|
285
+ shares.permutation(n).each{|shares| success = false if klass.decrypt(shares, encrypted, true) != false }
286
+ }
287
+ break unless success
288
+ }
289
+ }
290
+ assert_equal true, success
291
+ end
292
+
293
+ def test_shamir_base64_encrypt
294
+ text = "A"*32
295
+ helper{|available,needed|
296
+ shares, encrypted = ShamirSecretSharing::Base64.encrypt(text, available, needed, 96)
297
+ assert_equal text, ShamirSecretSharing::Base64.decrypt(shares.shuffle[0...needed], encrypted)
298
+ }
299
+ end
300
+
301
+ def test_shamir_hex_encrypt
302
+ text = "A"*32
303
+ helper{|available,needed|
304
+ shares, encrypted = ShamirSecretSharing::Hex.encrypt(text, available, needed, 96)
305
+ assert_equal text, ShamirSecretSharing::Hex.decrypt(shares.shuffle[0...needed], encrypted)
306
+ }
307
+ end
308
+
309
+ def test_shamir_with_broken_share_checksum
310
+ secret = "hello"
311
+ share_with_broken_checksum = ShamirSecretSharing::Base58.encode("foobar")
312
+ share_with_broken_encoding = "1Il"
313
+ shares = ShamirSecretSharing::Base58.split(secret, 3, 2)
314
+ assert_equal false, ShamirSecretSharing::Base58.combine( [shares.shuffle.first, share_with_broken_checksum])
315
+ assert_equal false, ShamirSecretSharing::Base58.combine( [shares.shuffle.first, share_with_broken_encoding])
316
+
317
+ do_raise = true
318
+ err = assert_raises(ShamirSecretSharing::ShareChecksumError){ ShamirSecretSharing::Base58.combine( [shares.shuffle.first, share_with_broken_checksum], do_raise) }
319
+ assert_match /share: /, err.message
320
+ assert_raises(ShamirSecretSharing::ShareDecodeError){ ShamirSecretSharing::Base58.combine( [shares.shuffle.first, share_with_broken_encoding], do_raise) }
321
+ assert_match /share: /, err.message
322
+ end
323
+
324
+ def test_shamir_encrypt_with_broken_encypted_data
325
+ text = "A"*32
326
+ broken_encrypted_data = ShamirSecretSharing::Base58.encode("foobar")
327
+ broken_encrypted_data_encoding = "1Il"
328
+ share_with_broken_encoding = "1Il"
329
+ shares, encrypted = ShamirSecretSharing::Base58.encrypt(text, 3, 2, 96)
330
+ assert_equal false, ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...2], broken_encrypted_data)
331
+ assert_equal false, ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...2], broken_encrypted_data_encoding)
332
+
333
+ do_raise = true
334
+ assert_raises(OpenSSL::Cipher::CipherError) { ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...2], broken_encrypted_data, do_raise) }
335
+ err = assert_raises(ShamirSecretSharing::ShareDecodeError){ ShamirSecretSharing::Base58.decrypt( [shares.shuffle.first, share_with_broken_encoding], encrypted, do_raise) }
336
+ assert_match /share: /, err.message
337
+ err = assert_raises(ShamirSecretSharing::ShareDecodeError){ ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...2], broken_encrypted_data_encoding, do_raise) }
338
+ assert_match /encrypted_data: /, err.message
339
+ end
340
+
341
+ def test_shamir_split_argument_errors
342
+ assert_raises_and_message(ArgumentError, "needed must be <= available") { ShamirSecretSharing::Base58.split("foobar", 2, 3) }
343
+ assert_raises_and_message(ArgumentError, "needed must be >= 2") { ShamirSecretSharing::Base58.split("foobar", 3, 1) }
344
+ assert_raises_and_message(ArgumentError, "available must be <= 250") { ShamirSecretSharing::Base58.split("foobar", 251, 2) }
345
+ assert_raises_and_message(ArgumentError, "bytelength of secret must be >= 1") { ShamirSecretSharing::Base58.split("", 3, 2) }
346
+ assert_raises_and_message(ArgumentError, "bytelength of secret must be <= 512") { ShamirSecretSharing::Base58.split("A"*513, 3, 2) }
347
+ end
348
+
349
+ end
350
+
351
+ =begin
352
+ require 'pp'
353
+
354
+ pp shares = ShamirSecretSharing::Base58.split("hello", 6, 3)
355
+ pp ShamirSecretSharing::Base58.combine(shares[0...3])
356
+
357
+ pp shares = ShamirSecretSharing::Base64.split("hello", 6, 3)
358
+ pp ShamirSecretSharing::Base64.combine(shares[0...3])
359
+
360
+ pp shares = ShamirSecretSharing::Hex.split("hello", 6, 3)
361
+ pp ShamirSecretSharing::Hex.combine(shares[0...3])
362
+
363
+ pp shares = ShamirSecretSharing::Number.split(123, 6, 3)
364
+ pp ShamirSecretSharing::Number.combine(shares[0...3])
365
+
366
+
367
+ shares, encrypted = ShamirSecretSharing::Base58.encrypt("A"*32, 6, 3, 96)
368
+ pp [shares, encrypted]
369
+ p ShamirSecretSharing::Base58.decrypt(shares.shuffle[0...3], encrypted)
370
+
371
+ shares, encrypted = ShamirSecretSharing::Base64.encrypt("A"*32, 6, 3, 96)
372
+ pp [shares, encrypted]
373
+ p ShamirSecretSharing::Base64.decrypt(shares.shuffle[0...3], encrypted)
374
+
375
+ shares, encrypted = ShamirSecretSharing::Hex.encrypt("A"*32, 6, 3, 96)
376
+ pp [shares, encrypted]
377
+ p ShamirSecretSharing::Hex.decrypt(shares.shuffle[0...3], encrypted)
378
+ =end
379
+
380
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "shamir-secret-sharing"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "shamir-secret-sharing"
7
+ s.version = ShamirSecretSharing::VERSION
8
+ s.authors = ["lian"]
9
+ s.email = ["meta.rb@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Gem for Shamir's Secret Sharing}
12
+ s.description = %q{Gem for Shamir's Secret Sharing}
13
+
14
+ s.rubyforge_project = "shamir-secret-sharing"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.required_rubygems_version = ">= 1.3.6"
22
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shamir-secret-sharing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - lian
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Gem for Shamir's Secret Sharing
14
+ email:
15
+ - meta.rb@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.rdoc
21
+ - Rakefile
22
+ - lib/shamir-secret-sharing.rb
23
+ - shamir-secret-sharing.gemspec
24
+ homepage: ''
25
+ licenses: []
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.6
41
+ requirements: []
42
+ rubyforge_project: shamir-secret-sharing
43
+ rubygems_version: 2.2.0
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Gem for Shamir's Secret Sharing
47
+ test_files: []