shamir-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.
@@ -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: []