ntc-rcrypto 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/README.md +33 -5
- data/lib/main.rb +87 -28
- data/lib/rcrypto/sss.rb +161 -73
- data/lib/rcrypto/version.rb +1 -1
- metadata +2 -5
- data/Gemfile.lock +0 -21
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d418af6ae2b5279365489c245007dec3863765e7268bab4481074926a0dc5e3f
|
4
|
+
data.tar.gz: c32826acf84e80db1a30611c4196dac565116588ec257da008ee5658501ed6d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e4ec45b5a06df1eb2eef30e5f151a6474a26ac35248cee058c15f2dfd501d7690509c783dc4c6ef369ff66de47f49f2ecac607699e0ca9b97f6bd254c93db39
|
7
|
+
data.tar.gz: 89688e0525dc327f04e2f1006c058f469ccf313c2e94bf1c21065beb90f7b1b2ad49b71fe3b9d37777ca4e0ce4254b5ed9e387d07528115b60271bb20c376c61
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -21,6 +21,34 @@ gem install ntc-rcrypto
|
|
21
21
|
|
22
22
|
## 1. An implementation of Shamir's Secret Sharing Algorithm 256-bits in Ruby
|
23
23
|
### Usage
|
24
|
+
|
25
|
+
**Use encode/decode Base64Url**
|
26
|
+
```ruby
|
27
|
+
require 'rcrypto'
|
28
|
+
|
29
|
+
sss = Rcrypto::SSS.new
|
30
|
+
|
31
|
+
s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
32
|
+
puts s
|
33
|
+
puts s.length
|
34
|
+
# creates a set of shares
|
35
|
+
arr = sss.create(3, 6, s, true)
|
36
|
+
# puts arr
|
37
|
+
|
38
|
+
# combines shares into secret
|
39
|
+
s1 = sss.combine(arr[0...3], true)
|
40
|
+
puts s1
|
41
|
+
puts s1.length
|
42
|
+
|
43
|
+
s2 = sss.combine(arr[3...6], true)
|
44
|
+
puts s2
|
45
|
+
puts s2.length
|
46
|
+
|
47
|
+
s3 = sss.combine(arr[1...5], true)
|
48
|
+
puts s3
|
49
|
+
puts s3.length
|
50
|
+
```
|
51
|
+
|
24
52
|
**Use encode/decode Hex**
|
25
53
|
```ruby
|
26
54
|
require 'rcrypto'
|
@@ -31,22 +59,22 @@ s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
31
59
|
puts s
|
32
60
|
puts s.length
|
33
61
|
# creates a set of shares
|
34
|
-
arr = sss.create(3, 6, s)
|
62
|
+
arr = sss.create(3, 6, s, false)
|
35
63
|
# puts arr
|
36
64
|
|
37
65
|
# combines shares into secret
|
38
|
-
s1 = sss.combine(arr[0...3])
|
66
|
+
s1 = sss.combine(arr[0...3], false)
|
39
67
|
puts s1
|
40
68
|
puts s1.length
|
41
69
|
|
42
|
-
s2 = sss.combine(arr[3...6])
|
70
|
+
s2 = sss.combine(arr[3...6], false)
|
43
71
|
puts s2
|
44
72
|
puts s2.length
|
45
73
|
|
46
|
-
s3 = sss.combine(arr[1...5])
|
74
|
+
s3 = sss.combine(arr[1...5], false)
|
47
75
|
puts s3
|
48
76
|
puts s3.length
|
49
77
|
```
|
50
78
|
|
51
79
|
## License
|
52
|
-
This code is under the [Apache
|
80
|
+
This code is under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0).
|
data/lib/main.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# Run Terminal: /bin/bash -c "env RBENV_VERSION=2.7.0 ~/.rbenv/libexec/rbenv exec bundle exec ruby ./lib/main.rb"
|
2
|
+
|
1
3
|
require 'rcrypto'
|
2
4
|
|
3
5
|
sss = Rcrypto::SSS.new
|
@@ -18,11 +20,15 @@ sss = Rcrypto::SSS.new
|
|
18
20
|
# number = 67356225285819719212258382314594931188352598651646313425411610888829358649431
|
19
21
|
# puts number
|
20
22
|
# b64data = sss.to_base64(number)
|
21
|
-
# puts b64data.length
|
22
|
-
# puts b64data
|
23
|
+
# puts b64data.length
|
24
|
+
# puts b64data
|
25
|
+
# # 88
|
26
|
+
# # OTRlYTQ1YzMyYzI5MDllNTQwNzBhZDNmMmNlMjg2Zjk4YjU2ZWY1YzcyOGY1NmQ3ZDNhMDljNWJiNTU5MzA1Nw==
|
27
|
+
# # 44
|
28
|
+
# # lOpFwywpCeVAcK0_LOKG-YtW71xyj1bX06CcW7VZMFc=
|
23
29
|
# hexdata = sss.to_hex(number)
|
24
|
-
# puts hexdata.length
|
25
|
-
# puts hexdata
|
30
|
+
# puts hexdata.length # 64
|
31
|
+
# puts hexdata # 94ea45c32c2909e54070ad3f2ce286f98b56ef5c728f56d7d3a09c5bb5593057
|
26
32
|
# numb64decode = sss.from_base64(b64data)
|
27
33
|
# puts numb64decode
|
28
34
|
# numhexdecode = sss.from_hex(hexdata)
|
@@ -39,27 +45,27 @@ sss = Rcrypto::SSS.new
|
|
39
45
|
# puts rs
|
40
46
|
# puts rs.length # 109
|
41
47
|
|
42
|
-
# Test1
|
43
|
-
s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
44
|
-
puts s
|
45
|
-
puts s.length
|
46
|
-
# creates a set of shares
|
47
|
-
arr = sss.create(3, 6, s)
|
48
|
-
# puts "================== arr"
|
49
|
-
# puts arr
|
50
|
-
# puts "=================="
|
51
|
-
# combines shares into secret
|
52
|
-
s1 = sss.combine(arr[0...3])
|
53
|
-
puts s1
|
54
|
-
puts s1.length
|
55
|
-
|
56
|
-
s2 = sss.combine(arr[3...6])
|
57
|
-
puts s2
|
58
|
-
puts s2.length
|
59
|
-
|
60
|
-
s3 = sss.combine(arr[1...5])
|
61
|
-
puts s3
|
62
|
-
puts s3.length
|
48
|
+
# # Test1
|
49
|
+
# s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
50
|
+
# puts s
|
51
|
+
# puts s.length
|
52
|
+
# # creates a set of shares
|
53
|
+
# arr = sss.create(3, 6, s, false)
|
54
|
+
# # puts "================== arr"
|
55
|
+
# # puts arr
|
56
|
+
# # puts "=================="
|
57
|
+
# # combines shares into secret
|
58
|
+
# s1 = sss.combine(arr[0...3], false)
|
59
|
+
# puts s1
|
60
|
+
# puts s1.length
|
61
|
+
#
|
62
|
+
# s2 = sss.combine(arr[3...6], false)
|
63
|
+
# puts s2
|
64
|
+
# puts s2.length
|
65
|
+
#
|
66
|
+
# s3 = sss.combine(arr[1...5], false)
|
67
|
+
# puts s3
|
68
|
+
# puts s3.length
|
63
69
|
|
64
70
|
|
65
71
|
# # Test2
|
@@ -79,14 +85,67 @@ puts s3.length
|
|
79
85
|
# # puts arr
|
80
86
|
# # puts "=================="
|
81
87
|
# # combines shares into secret
|
82
|
-
# s1 = sss.combine(arr[0...3])
|
88
|
+
# s1 = sss.combine(arr[0...3], false)
|
89
|
+
# puts s1
|
90
|
+
# puts s1.length
|
91
|
+
#
|
92
|
+
# s2 = sss.combine(arr[3...6], false)
|
93
|
+
# puts s2
|
94
|
+
# puts s2.length
|
95
|
+
#
|
96
|
+
# s3 = sss.combine(arr[1...5], false)
|
97
|
+
# puts s3
|
98
|
+
# puts s3.length
|
99
|
+
|
100
|
+
|
101
|
+
# # Test3
|
102
|
+
# s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
103
|
+
# puts s
|
104
|
+
# puts s.length
|
105
|
+
# # creates a set of shares
|
106
|
+
# arr = sss.create(3, 6, s, true)
|
107
|
+
# # puts "================== arr"
|
108
|
+
# # puts arr
|
109
|
+
# # puts "=================="
|
110
|
+
# # combines shares into secret
|
111
|
+
# s1 = sss.combine(arr[0...3], true)
|
112
|
+
# puts s1
|
113
|
+
# puts s1.length
|
114
|
+
#
|
115
|
+
# s2 = sss.combine(arr[3...6], true)
|
116
|
+
# puts s2
|
117
|
+
# puts s2.length
|
118
|
+
#
|
119
|
+
# s3 = sss.combine(arr[1...5], true)
|
120
|
+
# puts s3
|
121
|
+
# puts s3.length
|
122
|
+
|
123
|
+
|
124
|
+
# # Test4
|
125
|
+
# s = "nghiatcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
126
|
+
# puts s
|
127
|
+
# puts s.length
|
128
|
+
# # creates a set of shares
|
129
|
+
# arr = [
|
130
|
+
# "3yHo_uVUBRJJ8AiBL-3SS2OAFoe8A0lYF9PVsylFpfU=hFNCvpl0Vo9pESdgVuQs88bna5lMFgfVsixJEjT38EU=rnqFtyOaWu6ROU7LqegKRBG3hnr75Uwa3xTLRTD_Ahs=HeD7Nh0314-9m6YAaAiLKv5QiPToYd_PpSOveTPf-08=VLnVwLvMoEy19oHz7F1RuQjexvNdBB9Z_0VBFpz3-tw=FVJFrnO0LyhswtULPNUQr3j-rwPVrruAp-SrU-JDQcU=6dUlv2kHgZNYlV0ZiVhtQ_E-Vdt5Qu_74_ur8hLkTaM=oOyKYNhTd98bif9cEOVxPQCJjOh7haA63COMtGVLGDA=",
|
131
|
+
# "coKbKOpKsucIF0hLgL6r2dOJpQ52TXnqU4Y4Znc26aU=Byrn3KrQn8Rq8-F49THePjAxy1fkixnjf7H-Q82tlNY=C-17nZaq6PPDfHCDPIpmVa928rUYAXxkhop-1dhyEqg=kn_fIXrpRCh1WluMW2EQddz9Vlj7m4SlUWnSAupD6yQ=yrT7uX2bF0AEdOUFQx1sd-SAYBj4vY0wLQaXkilp9LQ=65RU1AOhohmmN5dmKChFipsCdCraLIu1I0tlfUCdtdQ=_oHtNTo71hjx5RO_BaDJq2hiZTvpQjN6-O4n6zf8F_M=bd5XjTzbwgZIoXDCeqX_lGbCAIW1kepA-j6xRChI5Co=",
|
132
|
+
# "O7As77L_0wcYIjvuL-Uod9WNAWWsB1W3iFjSVPDfgDE=bfOMBFU6n6dcMTmD7Vp67xwyUMQDLMVv3dkJfU0-GAE=N7rOnWAcjXG_SA0UZyfTi4Rv17ja5_8otHG4nbnYsUE=xhfjU2E_Zc3ldk5S5vUS3nUbHcWP_8Co0ROXF_542T8=3_XtNGxPNC_ZPRydvGdeGomiHRU1alWEFbfYPE4TFPg=hUA48-h2u6gJs4g5wDmvQzbTXQlAagBG3VjBQYGgjDI=AZHs5DhgW27YC5Tw0bW4wkbwpq7l13JNyEpR6m6PM0s=ZLA7GzYugrD-ii2h0f9kx0F8dS0TJQEJgcM1sg4KxHQ=",
|
133
|
+
# "1qi-z1_JzZq1pPaQlajigXK7ZLD49o9uEbAG0i2JPRE=F_-WklezDbbn5TwLzwgTH7y4CrdtgzHkRnoT7yGvlOc=L2ydfKaeEZAdO99MEW5z2_G73Cw17GKSjrFBrtlv91w=AVDKhDGyMJjcslpMKP796I6gMAs7Y3B5Oqqo0abpTSo=Jk2aKW6g1Ol88MXn2mZcRE7o_mjlK4L4rm7Mn-1xW4Y=PTxmdcCnxcI30aqkf1vmC96CmGovnH2G_RvtRaudmoE=vlw4fz5CHvoUteCz1KiQ4VvS_AmZqJUbMC1qIh4TTbU=uNF3vO6B7Q9nA29FFoDg5XnryRJAWPf0Fyn5-qNgorg=",
|
134
|
+
# "BvCmwKngaukEhX9PbO_mbs-kVXJZasFnCTbG1BU4uy8=D5R_MinicWA4MSUYlurfxKeMqHjXcsnB8fe6eGlWl2Q=4EqtWUErsPDEupb-lyrFBcrsDVmutZao3u7NMM0j-eE=atF3vl9wmfzGWsPtaYgmMA3K6VbEctYO0PvxLYEqhPs=yWvAcAYRiz7N08AxR7gS6FUkw5K9Fufb0TUvv6sn0Go=QnYDo7XCF0A_q4zdKLgrzSuwGxdACySdy_YyvbQXKFU=zoJeB5fBh-_JZXZh_e9_lI0VYZfj2sSmn0QU5rbDzjw=RJW7Ip7iy2E5bzLFmA0MRluWRBI_unyVeCIrxSFgnr0=",
|
135
|
+
# "H7L3h0FeMRJhlOjb4P7ujl8TU62V6BR-3hmrgeZSsqY=YIgcyaTE2i9cjWGy2KYwXG-Bihe5tVqwTDvfpGG0bjc=HaQPRVj61WadfsKTNQ_nz8Ysmuw8kbTTdtTUq4pr8ow=mral1sUzGfHO7wqBG5OjpieS8OQVcfWUGMefSmoePwM=hTgwBQUnnz5NpUjq-f5ZmFLeraoWqAUXu3FvpN2InoY=_O78YvsYo8BdIVwlixp889NAACSo1fnHjXwZ06X8LIQ=D_gDXhWQ4efiIxJPn-80PiCE1qRt89bh_IK0ZOZt9Ew=tYgTQLKfnvNrlq8fMyPnKWJ165zEuvu3lOpWnw8_Qiw="
|
136
|
+
# ]
|
137
|
+
# # puts "================== arr"
|
138
|
+
# # puts arr
|
139
|
+
# # puts "=================="
|
140
|
+
# # combines shares into secret
|
141
|
+
# s1 = sss.combine(arr[0...3], true)
|
83
142
|
# puts s1
|
84
143
|
# puts s1.length
|
85
144
|
#
|
86
|
-
# s2 = sss.combine(arr[3...6])
|
145
|
+
# s2 = sss.combine(arr[3...6], true)
|
87
146
|
# puts s2
|
88
147
|
# puts s2.length
|
89
148
|
#
|
90
|
-
# s3 = sss.combine(arr[1...5])
|
149
|
+
# s3 = sss.combine(arr[1...5], true)
|
91
150
|
# puts s3
|
92
151
|
# puts s3.length
|
data/lib/rcrypto/sss.rb
CHANGED
@@ -48,6 +48,32 @@ module Rcrypto
|
|
48
48
|
s.split.pack('H*')
|
49
49
|
end
|
50
50
|
|
51
|
+
# Return Uint8Array binary representation of hex string.
|
52
|
+
def hex_to_u8b(hex)
|
53
|
+
u8 = []
|
54
|
+
hex = '0' + hex if hex.length.odd?
|
55
|
+
len = hex.length / 2
|
56
|
+
i = 0
|
57
|
+
j = 0
|
58
|
+
while i < len
|
59
|
+
u8.append((hex[j...j + 2]).to_i(16))
|
60
|
+
j += 2
|
61
|
+
i += 1
|
62
|
+
end
|
63
|
+
# uint8_t
|
64
|
+
u8b = u8.pack('C*')
|
65
|
+
u8b
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return hex string representation of Uint8Array binary.
|
69
|
+
def u8b_to_hex(u8b)
|
70
|
+
u8 = u8b.unpack('C*')
|
71
|
+
hex = u8.map do |v|
|
72
|
+
v.to_s(16).rjust(2, '0')
|
73
|
+
end.join
|
74
|
+
hex
|
75
|
+
end
|
76
|
+
|
51
77
|
# Returns the Int number base10 in base64 representation; note: this is
|
52
78
|
# not a string representation; the base64 output is exactly 256 bits long.
|
53
79
|
def to_base64(number)
|
@@ -58,7 +84,8 @@ module Rcrypto
|
|
58
84
|
hexdata = '0' + hexdata
|
59
85
|
i += 1
|
60
86
|
end
|
61
|
-
|
87
|
+
u8b = hex_to_u8b(hexdata)
|
88
|
+
b64data = Base64.urlsafe_encode64(u8b)
|
62
89
|
b64data
|
63
90
|
end
|
64
91
|
|
@@ -66,7 +93,8 @@ module Rcrypto
|
|
66
93
|
# not coming from a string representation; the base64 input is exactly 256
|
67
94
|
# bits long, and the output is an arbitrary size base 10 integer.
|
68
95
|
def from_base64(number)
|
69
|
-
|
96
|
+
u8b = Base64.urlsafe_decode64(number)
|
97
|
+
hexdata = u8b_to_hex(u8b)
|
70
98
|
rs = hexdata.to_i(16)
|
71
99
|
rs
|
72
100
|
end
|
@@ -147,7 +175,7 @@ module Rcrypto
|
|
147
175
|
# Converts an array of Ints to the original byte array, removing any
|
148
176
|
# least significant nulls.
|
149
177
|
def merge_int_to_string(secrets)
|
150
|
-
hex_data =
|
178
|
+
hex_data = ''
|
151
179
|
for s in secrets
|
152
180
|
tmp = to_hex(s)
|
153
181
|
hex_data += tmp
|
@@ -159,17 +187,129 @@ module Rcrypto
|
|
159
187
|
# in_numbers(numbers, value) returns boolean whether or not value is in array
|
160
188
|
def in_numbers(numbers, value)
|
161
189
|
for n in numbers
|
162
|
-
if n == value
|
163
|
-
|
190
|
+
return true if n == value
|
191
|
+
end
|
192
|
+
false
|
193
|
+
end
|
194
|
+
|
195
|
+
# Takes a string array of shares encoded in Base64Url created via Shamir's
|
196
|
+
# Algorithm; each string must be of equal length of a multiple of 88 characters
|
197
|
+
# as a single 88 character share is a pair of 256-bit numbers (x, y).
|
198
|
+
def decode_share_base64(shares)
|
199
|
+
# Recreate the original object of x, y points, based upon number of shares
|
200
|
+
# and size of each share (number of parts in the secret).
|
201
|
+
secrets = []
|
202
|
+
|
203
|
+
# For each share...
|
204
|
+
for i in 0...shares.length
|
205
|
+
# ensure that it is valid.
|
206
|
+
unless is_valid_share_base64(shares[i])
|
207
|
+
raise Exception('one of the shares is invalid')
|
164
208
|
end
|
209
|
+
|
210
|
+
# find the number of parts it represents.
|
211
|
+
share = shares[i]
|
212
|
+
count = share.length / 88
|
213
|
+
arrsh = []
|
214
|
+
# and for each part, find the x,y pair...
|
215
|
+
for j in 0...count
|
216
|
+
cshare = share[j * 88...(j + 1) * 88]
|
217
|
+
arrxy = []
|
218
|
+
# decoding from Base64.
|
219
|
+
x = from_base64(cshare[0...44])
|
220
|
+
y = from_base64(cshare[44...88])
|
221
|
+
arrxy.push(x)
|
222
|
+
arrxy.push(y)
|
223
|
+
arrsh.push(arrxy)
|
224
|
+
end
|
225
|
+
secrets.push(arrsh)
|
226
|
+
end
|
227
|
+
secrets
|
228
|
+
end
|
229
|
+
|
230
|
+
# Takes in a given string to check if it is a valid secret
|
231
|
+
#
|
232
|
+
# Requirements:
|
233
|
+
# Length multiple of 88
|
234
|
+
# Can decode each 44 character block as Bas64Url
|
235
|
+
#
|
236
|
+
# Returns only success/failure (bool)
|
237
|
+
def is_valid_share_base64(candidate)
|
238
|
+
return false if candidate.length == 0 || candidate.length % 88 != 0
|
239
|
+
|
240
|
+
count = candidate.length / 44
|
241
|
+
j = 0
|
242
|
+
while j < count
|
243
|
+
part = candidate[j * 44...(j + 1) * 44]
|
244
|
+
decode = from_base64(part)
|
245
|
+
return false if decode <= 0 || decode >= @@prime
|
246
|
+
|
247
|
+
j += 1
|
165
248
|
end
|
166
|
-
|
249
|
+
true
|
250
|
+
end
|
251
|
+
|
252
|
+
# Takes a string array of shares encoded in Hex created via Shamir's
|
253
|
+
# Algorithm; each string must be of equal length of a multiple of 128 characters
|
254
|
+
# as a single 128 character share is a pair of 256-bit numbers (x, y).
|
255
|
+
def decode_share_hex(shares)
|
256
|
+
# Recreate the original object of x, y points, based upon number of shares
|
257
|
+
# and size of each share (number of parts in the secret).
|
258
|
+
secrets = []
|
259
|
+
|
260
|
+
# For each share...
|
261
|
+
for i in 0...shares.length
|
262
|
+
# ensure that it is valid.
|
263
|
+
unless is_valid_share_hex(shares[i])
|
264
|
+
raise Exception('one of the shares is invalid')
|
265
|
+
end
|
266
|
+
|
267
|
+
# find the number of parts it represents.
|
268
|
+
share = shares[i]
|
269
|
+
count = share.length / 128
|
270
|
+
arrsh = []
|
271
|
+
# and for each part, find the x,y pair...
|
272
|
+
for j in 0...count
|
273
|
+
cshare = share[j * 128...(j + 1) * 128]
|
274
|
+
arrxy = []
|
275
|
+
# decoding from Hex.
|
276
|
+
x = from_hex(cshare[0...64])
|
277
|
+
y = from_hex(cshare[64...128])
|
278
|
+
arrxy.push(x)
|
279
|
+
arrxy.push(y)
|
280
|
+
arrsh.push(arrxy)
|
281
|
+
end
|
282
|
+
secrets.push(arrsh)
|
283
|
+
end
|
284
|
+
secrets
|
285
|
+
end
|
286
|
+
|
287
|
+
# Takes in a given string to check if it is a valid secret
|
288
|
+
#
|
289
|
+
# Requirements:
|
290
|
+
# Length multiple of 128
|
291
|
+
# Can decode each 64 character block as Hex
|
292
|
+
#
|
293
|
+
# Returns only success/failure (bool)
|
294
|
+
def is_valid_share_hex(candidate)
|
295
|
+
return false if candidate.length == 0 || candidate.length % 128 != 0
|
296
|
+
|
297
|
+
count = candidate.length / 64
|
298
|
+
j = 0
|
299
|
+
while j < count
|
300
|
+
part = candidate[j * 64...(j + 1) * 64]
|
301
|
+
decode = from_hex(part)
|
302
|
+
return false if decode <= 0 || decode >= @@prime
|
303
|
+
|
304
|
+
j += 1
|
305
|
+
end
|
306
|
+
return true
|
167
307
|
end
|
168
308
|
|
169
309
|
# Returns a new array of secret shares (encoding x,y pairs as Base64 or Hex strings)
|
170
310
|
# created by Shamir's Secret Sharing Algorithm requiring a minimum number of
|
171
311
|
# share to recreate, of length shares, from the input secret raw as a string.
|
172
|
-
def create(minimum, shares, secret)
|
312
|
+
def create(minimum, shares, secret, is_base64 = false)
|
173
313
|
result = []
|
174
314
|
|
175
315
|
# Verify minimum isn't greater than shares; there is no way to recreate
|
@@ -236,8 +376,13 @@ module Rcrypto
|
|
236
376
|
y = evaluate_polynomial(polynomial, j, number)
|
237
377
|
arrxy.push(x)
|
238
378
|
arrxy.push(y)
|
239
|
-
|
240
|
-
|
379
|
+
if is_base64
|
380
|
+
s += to_base64(x)
|
381
|
+
s += to_base64(y)
|
382
|
+
else
|
383
|
+
s += to_hex(x)
|
384
|
+
s += to_hex(y)
|
385
|
+
end
|
241
386
|
arrsh.push(arrxy)
|
242
387
|
end
|
243
388
|
points.push(arrsh)
|
@@ -246,79 +391,22 @@ module Rcrypto
|
|
246
391
|
result
|
247
392
|
end
|
248
393
|
|
249
|
-
# akes a string array of shares encoded in Hex created via Shamir's
|
250
|
-
# Algorithm; each string must be of equal length of a multiple of 128 characters
|
251
|
-
# as a single 128 character share is a pair of 256-bit numbers (x, y).
|
252
|
-
def decode_share_hex(shares)
|
253
|
-
# Recreate the original object of x, y points, based upon number of shares
|
254
|
-
# and size of each share (number of parts in the secret).
|
255
|
-
secrets = []
|
256
|
-
|
257
|
-
# For each share...
|
258
|
-
for i in 0...shares.length
|
259
|
-
# ensure that it is valid.
|
260
|
-
unless is_valid_share_hex(shares[i])
|
261
|
-
raise Exception('one of the shares is invalid')
|
262
|
-
end
|
263
|
-
|
264
|
-
# find the number of parts it represents.
|
265
|
-
share = shares[i]
|
266
|
-
count = share.length / 128
|
267
|
-
arrsh = []
|
268
|
-
# and for each part, find the x,y pair...
|
269
|
-
for j in 0...count
|
270
|
-
cshare = share[j * 128...(j + 1) * 128]
|
271
|
-
arrxy = []
|
272
|
-
# decoding from Base64.
|
273
|
-
x = from_hex(cshare[0...64])
|
274
|
-
y = from_hex(cshare[64...128])
|
275
|
-
arrxy.push(x)
|
276
|
-
arrxy.push(y)
|
277
|
-
arrsh.push(arrxy)
|
278
|
-
end
|
279
|
-
secrets.push(arrsh)
|
280
|
-
end
|
281
|
-
secrets
|
282
|
-
end
|
283
|
-
|
284
|
-
# Takes in a given string to check if it is a valid secret
|
285
|
-
#
|
286
|
-
# Requirements:
|
287
|
-
# Length multiple of 128
|
288
|
-
# Can decode each 64 character block as Hex
|
289
|
-
#
|
290
|
-
# Returns only success/failure (bool)
|
291
|
-
def is_valid_share_hex(candidate)
|
292
|
-
if candidate.length == 0 || candidate.length % 128 != 0
|
293
|
-
return false
|
294
|
-
end
|
295
|
-
count = candidate.length / 64
|
296
|
-
j = 0
|
297
|
-
while j < count
|
298
|
-
part = candidate[j * 64...(j + 1) * 64]
|
299
|
-
decode = from_hex(part)
|
300
|
-
if decode <= 0 || decode >= @@prime
|
301
|
-
return false
|
302
|
-
end
|
303
|
-
j += 1
|
304
|
-
end
|
305
|
-
return true
|
306
|
-
end
|
307
|
-
|
308
394
|
# Takes a string array of shares encoded in Base64 or Hex created via Shamir's Algorithm
|
309
395
|
# Note: the polynomial will converge if the specified minimum number of shares
|
310
396
|
# or more are passed to this function. Passing thus does not affect it
|
311
397
|
# Passing fewer however, simply means that the returned secret is wrong.
|
312
|
-
def combine(shares)
|
313
|
-
if shares.empty?
|
314
|
-
raise Exception('shares is NULL or empty')
|
315
|
-
end
|
398
|
+
def combine(shares, is_base64 = false)
|
399
|
+
raise Exception('shares is NULL or empty') if shares.empty?
|
316
400
|
|
317
401
|
# Recreate the original object of x, y points, based upon number of shares
|
318
402
|
# and size of each share (number of parts in the secret).
|
319
403
|
#
|
320
404
|
# points[shares][parts][2]
|
321
|
-
points =
|
405
|
+
points = if is_base64
|
406
|
+
decode_share_base64(shares)
|
407
|
+
else
|
408
|
+
decode_share_hex(shares)
|
409
|
+
end
|
322
410
|
# puts points
|
323
411
|
|
324
412
|
# Use Lagrange Polynomial Interpolation (LPI) to reconstruct the secrets.
|
data/lib/rcrypto/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ntc-rcrypto
|
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
|
- nghiatc
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: ntc-rcrypto is module ruby cryptography.
|
14
14
|
email:
|
@@ -21,12 +21,9 @@ files:
|
|
21
21
|
- ".travis.yml"
|
22
22
|
- CODE_OF_CONDUCT.md
|
23
23
|
- Gemfile
|
24
|
-
- Gemfile.lock
|
25
24
|
- LICENSE
|
26
25
|
- README.md
|
27
26
|
- Rakefile
|
28
|
-
- bin/console
|
29
|
-
- bin/setup
|
30
27
|
- lib/main.rb
|
31
28
|
- lib/rcrypto.rb
|
32
29
|
- lib/rcrypto/base_error.rb
|
data/Gemfile.lock
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
ntc-rcrypto (0.0.3)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
minitest (5.13.0)
|
10
|
-
rake (12.3.3)
|
11
|
-
|
12
|
-
PLATFORMS
|
13
|
-
ruby
|
14
|
-
|
15
|
-
DEPENDENCIES
|
16
|
-
minitest (~> 5.10)
|
17
|
-
ntc-rcrypto!
|
18
|
-
rake (~> 12.1)
|
19
|
-
|
20
|
-
BUNDLED WITH
|
21
|
-
2.1.4
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "rcrypto"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|