sharing 0.1.0 → 0.3.0
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/.codecov.yml +6 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +12 -2
- data/Gemfile +3 -5
- data/Gemfile.lock +15 -6
- data/README.md +209 -13
- data/bin/console +1 -1
- data/codecov +0 -0
- data/lib/sharing/polynomial/shamir/v1.rb +64 -5
- data/lib/sharing/version.rb +1 -1
- data/sharing.gemspec +1 -1
- data/sig/secret_sharing.rbs +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 719563755ad21ee302ca5c4cdf7dc99d5392f03f5a42af56a38a9199a76e5d31
|
4
|
+
data.tar.gz: f58c948f6c1c26cc2cc0f7f6e0c318a2c46d2c219952757bf43d092328f5b6ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 678102cac63e5994565e6b7628e7ebd5865b696d996684a4ccfb1c073d8f028270989fc7f8771f0010df25529aaf97cb8265133b61e22b3188d11654c37ee851
|
7
|
+
data.tar.gz: a7903a1cdb18224fba5ceca2443c8856fca3368534c839bc5daf50a09dcbfdd8bb953c3d715534ec21d5f16b662d8f8d9e2a3162461b90a1763607c932447914
|
data/.codecov.yml
ADDED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
|
-
## [
|
1
|
+
## [0.3.0] - 2022-05-23
|
2
2
|
|
3
|
-
|
3
|
+
- Add division to Shamir's secret sharing implementation.
|
4
|
+
|
5
|
+
## [0.2.0] - 2022-03-25
|
6
|
+
|
7
|
+
- Add multiplication to Shamir's secret sharing implementation and overall improvements.
|
8
|
+
|
9
|
+
## [0.1.1] - 2022-03-25
|
10
|
+
|
11
|
+
- Fix threshold setting on Shamir's scheme v1
|
12
|
+
|
13
|
+
## [0.1.0] - 2022-03-25
|
4
14
|
|
5
15
|
- Initial release
|
data/Gemfile
CHANGED
@@ -4,13 +4,9 @@ ruby ">= 2.6.0"
|
|
4
4
|
|
5
5
|
source "https://rubygems.org"
|
6
6
|
|
7
|
-
# Specify your gem
|
7
|
+
# Specify your gem"s dependencies in sharing.gemspec
|
8
8
|
gemspec
|
9
9
|
|
10
|
-
gem "hensel_code", "~> 0.3.0"
|
11
|
-
|
12
|
-
gem "prime", "~> 0.1.2"
|
13
|
-
|
14
10
|
gem "rake", "~> 13.0"
|
15
11
|
|
16
12
|
gem "minitest", "~> 5.0"
|
@@ -24,3 +20,5 @@ gem "rubocop-rake", "~> 0.6"
|
|
24
20
|
gem "minitest-reporters", "~> 1.5"
|
25
21
|
|
26
22
|
gem "codecov", require: false, group: :test
|
23
|
+
|
24
|
+
gem "simplecov-console", "~>0.9", require: false
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
|
5
|
-
hensel_code (~> 0.3.
|
4
|
+
sharing (0.2.0)
|
5
|
+
hensel_code (~> 0.3.1)
|
6
6
|
prime (~> 0.1.2)
|
7
7
|
|
8
8
|
GEM
|
@@ -15,13 +15,16 @@ GEM
|
|
15
15
|
simplecov (>= 0.15, < 0.22)
|
16
16
|
docile (1.4.0)
|
17
17
|
forwardable (1.3.2)
|
18
|
-
hensel_code (0.3.
|
18
|
+
hensel_code (0.3.1)
|
19
|
+
openssl (~> 3.0.0)
|
20
|
+
prime (~> 0.1.2)
|
19
21
|
minitest (5.15.0)
|
20
22
|
minitest-reporters (1.5.0)
|
21
23
|
ansi
|
22
24
|
builder
|
23
25
|
minitest (>= 5.0)
|
24
26
|
ruby-progressbar
|
27
|
+
openssl (3.0.0)
|
25
28
|
parallel (1.21.0)
|
26
29
|
parser (3.1.1.0)
|
27
30
|
ast (~> 2.4.1)
|
@@ -52,25 +55,31 @@ GEM
|
|
52
55
|
docile (~> 1.1)
|
53
56
|
simplecov-html (~> 0.11)
|
54
57
|
simplecov_json_formatter (~> 0.1)
|
58
|
+
simplecov-console (0.9.1)
|
59
|
+
ansi
|
60
|
+
simplecov
|
61
|
+
terminal-table
|
55
62
|
simplecov-html (0.12.3)
|
56
63
|
simplecov_json_formatter (0.1.4)
|
57
64
|
singleton (0.1.1)
|
65
|
+
terminal-table (3.0.2)
|
66
|
+
unicode-display_width (>= 1.1.1, < 3)
|
58
67
|
unicode-display_width (2.1.0)
|
59
68
|
|
60
69
|
PLATFORMS
|
61
70
|
x86_64-darwin-19
|
71
|
+
x86_64-linux
|
62
72
|
|
63
73
|
DEPENDENCIES
|
64
74
|
codecov
|
65
|
-
hensel_code (~> 0.3.0)
|
66
75
|
minitest (~> 5.0)
|
67
76
|
minitest-reporters (~> 1.5)
|
68
|
-
prime (~> 0.1.2)
|
69
77
|
rake (~> 13.0)
|
70
78
|
rubocop (~> 1.21)
|
71
79
|
rubocop-minitest (~> 0.17.2)
|
72
80
|
rubocop-rake (~> 0.6)
|
73
|
-
|
81
|
+
sharing!
|
82
|
+
simplecov-console (~> 0.9)
|
74
83
|
|
75
84
|
RUBY VERSION
|
76
85
|
ruby 3.1.0p0
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# Sharing
|
2
2
|
|
3
|
-
|
3
|
+
 [](https://github.com/rubocop/rubocop)   
|
4
|
+
|
5
|
+
Sharing is a Ruby gem with implmementations of secret sharing schemes with homomorphic properties. Although secret sharing schemes and multiparty computation protocols are distinct notions, multiparty computation protocols are typically enabled by secret sharing schemes. In this setting, security comes from the use of multiple parties. If they collude, all security is lost, but satisfactory levels of security can be established by trusting a subset of them will not to collude. In many settings where corrupting security requires corrupting all the parties, and considering you are one of the computing parties, security is guaranteed if you are one of the parties.
|
6
|
+
|
7
|
+
Computing linear functions is trivial. Each non-linear operation however requires interaction between the parties/extra steps (for most secret sharing schemes).
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -27,6 +31,13 @@ Secret Sharing currently supports two schemes:
|
|
27
31
|
|
28
32
|
# Usage
|
29
33
|
|
34
|
+
In the examples below, there are two main levels of execution:
|
35
|
+
|
36
|
+
- Computations performed by the owner of the secrets (those are computations using instance methods)
|
37
|
+
- Computations performed over the secret shares (those are computations using class methods)
|
38
|
+
|
39
|
+
This distiction is important since we are showing everything at once here, for completeness and for clarity. However it is important to keep in mind that after the secret shares are generated, the computations over the shares are intended to be computed independetly by each participant (party), each one with their corresponding shares.
|
40
|
+
|
30
41
|
## Shamir's Secret Sharing V1
|
31
42
|
|
32
43
|
The Shamir's secret sharing v1 scheme is based on the work of Adi Shamir in [How to Share a Secret](https://web.mit.edu/6.857/OldStuff/Fall03/ref/Shamir-HowToShareASecret.pdf).
|
@@ -58,9 +69,9 @@ We reconstruct the secrets as follows:
|
|
58
69
|
|
59
70
|
```ruby
|
60
71
|
reconstructed_secret1 = sss.reconstruct_secret(shares1)
|
61
|
-
# =>
|
72
|
+
# => 22
|
62
73
|
reconstructed_secret2 = sss.reconstruct_secret(shares2)
|
63
|
-
# =>
|
74
|
+
# => 36
|
64
75
|
```
|
65
76
|
|
66
77
|
We can compute linear functions without requiring communication between the share holders:
|
@@ -80,18 +91,18 @@ and we can check that:
|
|
80
91
|
|
81
92
|
```ruby
|
82
93
|
sss.reconstruct_secret(shares1_add_shares2)
|
83
|
-
# =>
|
94
|
+
# => 58
|
84
95
|
sss.reconstruct_secret(shares2_sub_shares1)
|
85
|
-
# =>
|
96
|
+
# => 14
|
86
97
|
sss.reconstruct_secret(shares1_smul_scalar)
|
87
|
-
# =>
|
98
|
+
# => 44
|
88
99
|
sss.reconstruct_secret(shares1_sdiv_scalar)
|
89
|
-
# =>
|
100
|
+
# => 11
|
90
101
|
```
|
91
102
|
|
92
103
|
### Using Hensel Codes
|
93
104
|
|
94
|
-
The gem Secret Sharing takes advantage of the gem [Hensel
|
105
|
+
The gem Secret Sharing takes advantage of the gem [Hensel Code](https://github.com/davidwilliam/hensel_code) for homomorphically encoding rational numbers as integers in order to compute over the integers and yet obtain results over the rationals.
|
95
106
|
|
96
107
|
As most (if not all) of secret sharing schemes over finite fields `F_p` for `p > 2`, the secret inputs are naturally required to be positive integers in `F_p`. In this way, if we compute subtraction and we end up with a result that is negative, the reconstruction will fail (provided we don't have any econding in place). Same will occur if we compute a scalar division involving a scalar that is not a divisor of the corresponding secret. For addressing this and many other arithmetic problems, we can use Hensel codes to allow secret inputs to be positive and negative rational numbers.
|
97
108
|
|
@@ -143,13 +154,13 @@ We reconstruct the secrets:
|
|
143
154
|
|
144
155
|
```ruby
|
145
156
|
reconstruct_secret1_add_secret2 = sss.reconstruct_secret(shares1_add_shares2)
|
146
|
-
# => 3361138990
|
157
|
+
# => 3361138990
|
147
158
|
reconstruct_secret1_sub_secret2 = sss.reconstruct_secret(shares1_sub_shares2)
|
148
|
-
# => 2174854642
|
159
|
+
# => 2174854642
|
149
160
|
reconstruct_shares1_smul_scalar = sss.reconstruct_secret(shares1_smul_scalar)
|
150
|
-
# => 1383998411
|
161
|
+
# => 1383998411
|
151
162
|
reconstruct_shares1_sdiv_scalar = sss.reconstruct_secret(shares1_sdiv_scalar)
|
152
|
-
# => 3044796497
|
163
|
+
# => 3044796497
|
153
164
|
```
|
154
165
|
|
155
166
|
and we can check that:
|
@@ -165,6 +176,178 @@ HenselCode::TruncatedFinitePadicExpansion.new(sss.p, 1, reconstructed_shares1_sd
|
|
165
176
|
# => 2/15
|
166
177
|
```
|
167
178
|
|
179
|
+
### Multiplication
|
180
|
+
|
181
|
+
As we previously saw, linear functions are easy to compute with shares created by an instance of Shamir's secret sharing scheme. Non-linear functions need some strategy that require extra steps in other to successfuly achieve the desired results. We implement multiplication in the context of Shamir's secret sharing scheme following the approach discussed by Dan Bognadov in [Foundations and properties of Shamir's secret sharing scheme - Research Seminar in Cryptography](https://uuslepo.it.da.ut.ee/~peeter_l/teaching/seminar07k/bogdanov.pdf).
|
182
|
+
|
183
|
+
We define an instance of Shamir's secret sharing scheme with the following parameters:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
params = { lambda_: 16, total_shares: 6, threshold: 3 }
|
187
|
+
# => {:lambda_=>16, :total_shares=>6, :threshold=>3}
|
188
|
+
sss = Sharing::Polynomial::Shamir::V1.new params
|
189
|
+
# => #<Sharing::Polynomial::Shamir::V1:0x0000000105423640 @lambda_=16, @p=49367, @threshold=3, @total_shares=6>
|
190
|
+
```
|
191
|
+
|
192
|
+
As before, we define the secrets and create shares for them:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
secret1 = 13
|
196
|
+
secret2 = 28
|
197
|
+
shares1 = sss.create_shares(secret1)
|
198
|
+
# => [[1, 43064], [2, 20333], [3, 30554], [4, 24360], [5, 1751], [6, 12094]]
|
199
|
+
shares2 = sss.create_shares(secret2)
|
200
|
+
# => [[1, 7983], [2, 18517], [3, 31630], [4, 47322], [5, 16226], [6, 37076]]
|
201
|
+
```
|
202
|
+
|
203
|
+
We combine both shares on a single array in preparation for the multiplication steps:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
operands_shares = [shares1, shares2]
|
207
|
+
# => [[[1, 43064], [2, 20333], [3, 30554], [4, 24360], [5, 1751], [6, 12094]], [[1, 7983], [2, 18517], [3, 31630], [4, 47322], [5, 16226], [6, 37076]]]
|
208
|
+
```
|
209
|
+
|
210
|
+
Recall we are working with a t-out-of-n secret sharing scheme and this is actually required in this setting. We have a total of `n = 6` shares and threshold `t = 3`. In order to correctly recover the result of the multiplication over shares, we need to select any combination of `2 * t - 1` shares out of the total number of shares:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
selected_shares = Sharing::Polynomial::Shamir::V1.select_mul_shares(sss.total_shares, sss.threshold, operands_shares)
|
214
|
+
# => => [[[2, 20333], [1, 43064], [5, 1751], [3, 30554], [4, 24360]], [[2, 18517], [1, 7983], [5, 16226], [3, 31630], [4, 47322]]]
|
215
|
+
```
|
216
|
+
|
217
|
+
Now we have everything we need to compute multiplication over the secret shares, which we do in two rounds. First round:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
mul_round1 = Sharing::Polynomial::Shamir::V1.mul_first_round(selected_shares, sss.total_shares, sss.threshold, sss.lambda_, sss.p)
|
221
|
+
# => [[2, [[1, 25284], [2, 5881], [3, 2537], [4, 15252], [5, 44026], [6, 39492]]], [1, [[1, 36061], [2, 17299], [3, 32435], [4, 32102], [5, 16300], [6, 34396]]], [5, [[1, 30221], [2, 32724], [3, 33210], [4, 31679], [5, 28131], [6, 22566]]], [3, [[1, 46172], [2, 33017], [3, 8081], [4, 20731], [5, 21600], [6, 10688]]], [4, [[1, 12410], [2, 39133], [3, 5920], [4, 11505], [5, 6521], [6, 40335]]]]
|
222
|
+
```
|
223
|
+
|
224
|
+
Then we perform the second round:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
mul_round2 = Sharing::Polynomial::Shamir::V1.mul_second_round(mul_round1)
|
228
|
+
# => [[1, 150148], [2, 128054], [3, 82183], [4, 111269], [5, 116578], [6, 147477]]
|
229
|
+
```
|
230
|
+
|
231
|
+
Then we only need a number equal to the threshold to reconstruct the result of the multipliction over the shares:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
selected_multiplication_shares = mul_round2.sample(sss.threshold)
|
235
|
+
# => [[6, 147477], [2, 128054], [1, 150148]
|
236
|
+
sss.reconstruct_secret(selected_multiplication_shares)
|
237
|
+
# => 364
|
238
|
+
```
|
239
|
+
|
240
|
+
and we can check that
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
secret1 * secret2
|
244
|
+
# => 364
|
245
|
+
```
|
246
|
+
|
247
|
+
### t-out-of-n Secret Sharing
|
248
|
+
|
249
|
+
Now we defined a threshold value that is less than the total number of shares:
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
params = {total_shares: 5, threshold: 3, lambda_: 16}
|
253
|
+
# => {:total_shares=>5, :threshold=>3, :lambda_=>16}
|
254
|
+
sss = Sharing::Polynomial::Shamir::V1.new params
|
255
|
+
# => #<Sharing::Polynomial::Shamir::V1:0x000000010b046e90 @lambda_=16, @p=61343, @threshold=3, @total_shares=5>
|
256
|
+
secret = 25
|
257
|
+
# => 25
|
258
|
+
shares = sss.create_shares(secret)
|
259
|
+
# => [[1, 54707], [2, 50401], [3, 48450], [4, 48854], [5, 51613]]
|
260
|
+
selected_shares = shares.sample(3)
|
261
|
+
reconstructed_secret = sss.reconstruct_secret(selected_shares)
|
262
|
+
# => 25
|
263
|
+
```
|
264
|
+
|
265
|
+
Everything else works the sabe as before except the fact that only `3` shares are required to reconstruct the secret.
|
266
|
+
|
267
|
+
### Division
|
268
|
+
|
269
|
+
Here we simulate a division algorithm computed over the shares. Consider the following configuration:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
{:lambda_=>16, :total_shares=>6, :threshold=>3}
|
273
|
+
sss = Sharing::Polynomial::Shamir::V1.new(params)
|
274
|
+
```
|
275
|
+
|
276
|
+
and the rational numbers
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
rat1 = Rational(2, 3)
|
280
|
+
rat2 = Rational(-5, 7)
|
281
|
+
```
|
282
|
+
|
283
|
+
We compute their Hensel code so we define our secrets:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
secret1 = HenselCode::TFPE.new(sss.p, 1, rat1).hensel_code
|
287
|
+
# => 40896
|
288
|
+
secret2 = HenselCode::TFPE.new(sss.p, 1, rat2).hensel_code
|
289
|
+
# => 52579
|
290
|
+
```
|
291
|
+
|
292
|
+
We then comute the shares for each secret:
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
shares1 = sss.create_shares(secret1)
|
296
|
+
# => [[1, 22792], [2, 38518], [3, 26731], [4, 48774], [5, 43304], [6, 10321]]
|
297
|
+
shares2 = sss.create_shares(secret2)
|
298
|
+
# => [[1, 37982], [2, 294], [3, 858], [4, 39674], [5, 55399], [6, 48033]]
|
299
|
+
```
|
300
|
+
|
301
|
+
We select a subset of the shares of eacg secret based on the threshold:
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
selected_shares1 = shares1.sample(sss.threshold)
|
305
|
+
# => [[1, 22792], [5, 43304], [6, 10321]]
|
306
|
+
selected_shares2 = shares2.sample(sss.threshold)
|
307
|
+
# => [[6, 48033], [2, 294], [1, 37982]]
|
308
|
+
```
|
309
|
+
|
310
|
+
A party that is not one of the selected parties (a trusted party for instance) generates three random values that will later used:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
r1, r2, r3 = Sharing::Polynomial::Shamir::V1.generate_division_masking(sss.p)
|
314
|
+
=> [23078, 18925, 18812]
|
315
|
+
```
|
316
|
+
|
317
|
+
Each party multiply their shares of the first operand by `r1` and the shares of the second operand by `r2`. For convenience (given our simulation), this step is here done all at once as follows:
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
cs, ds = Sharing::Polynomial::Shamir::V1.compute_numerator_denominator(selected_shares1, selected_shares2, r1, r2, sss.p)
|
321
|
+
=> [[[1, 38894], [5, 30899], [6, 54512]], [[6, 43951], [2, 43080], [1, 53419]]]
|
322
|
+
```
|
323
|
+
|
324
|
+
`cs` denote the shares representing the numerator of the division and `ds` represent the shares of the denominator of the division, as in `c/d`.
|
325
|
+
|
326
|
+
Finally, in the reconstruction step, `c` and `d` are reconstructed and `r3` is used to invert the multiplication by `r1` and `r2` that was previously computed by the parties. With the correct values recovered, we compute the Hensel decoding and then we obtain the final result without revealing what the numerator and denominator were. For convenience, we execute these steps as follows:
|
327
|
+
|
328
|
+
```ruby
|
329
|
+
sss.reconstruct_division(cs, ds, r3)
|
330
|
+
# => (-14/15)
|
331
|
+
```
|
332
|
+
|
333
|
+
We can also use only a subset of the shares:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
selected_cs = cs.sample(sss.threshold)
|
337
|
+
=> [[5, 30899], [1, 38894], [6, 54512]]
|
338
|
+
selected_ds = ds.sample(sss.threshold)
|
339
|
+
# => [[2, 43080], [1, 53419], [6, 43951]]
|
340
|
+
sss.reconstruct_division(selected_cs, selected_ds, r3)
|
341
|
+
=> (-14/15)
|
342
|
+
```
|
343
|
+
|
344
|
+
And we can check that
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
rat1 / rat2
|
348
|
+
# => (-14/15)
|
349
|
+
```
|
350
|
+
|
168
351
|
## Asmuth-Bloom V2
|
169
352
|
|
170
353
|
The Asmuth-Bloom V2 was proposed by Ersoy et al. in in [Homomorphic extensions of CRT-based secret sharing](https://www.sciencedirect.com/science/article/pii/S0166218X20303012)). The reference is a CRT-based secret sharing scheme introduced by Asmuth-Bloom in [A modular approach to key safeguarding](https://ieeexplore.ieee.org/abstract/document/1056651).
|
@@ -227,6 +410,19 @@ crtss.reconstruct_secret(selected_shares1_add_shares2_add_shares1_mul_shares2)
|
|
227
410
|
|
228
411
|
and we can check that 5 + 8 = 13, 5 * 8 = 40, and 13 + 40 = 53.
|
229
412
|
|
413
|
+
## Author
|
414
|
+
|
415
|
+
David William Silva
|
416
|
+
|
417
|
+
## Contributors
|
418
|
+
|
419
|
+
David William Silva (Algemetric)
|
420
|
+
Marcio Junior (Algemetric)
|
421
|
+
|
422
|
+
## Acknowledgements
|
423
|
+
|
424
|
+
Luke Harmon (Algemetric) and Gaetan Delavignette (Algemetric) have been instrumental by providing/conducting mathematical analyses, tests, and overall recommendations for improving the gem.
|
425
|
+
|
230
426
|
## Development
|
231
427
|
|
232
428
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/console
CHANGED
data/codecov
ADDED
Binary file
|
@@ -28,15 +28,59 @@ module Sharing
|
|
28
28
|
shares.map { |s| [s[0], (s[1] * mod_inverse(scalar, prime)) % prime] }
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.mul_first_round(shares, total_shares, threshold, lambda_, prime)
|
32
|
+
shares1, shares2 = shares
|
33
|
+
xs = shares1.map(&:first)
|
34
|
+
shares1.zip(shares2).map.with_index do |s, i|
|
35
|
+
share = prepare_share_for_multiplication(i, xs, prime, s)
|
36
|
+
reshares = create_shares(share, total_shares, threshold, lambda_, prime)
|
37
|
+
encode_reshares(reshares, prime, s)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.encode_reshares(reshares, prime, s_pair)
|
42
|
+
reshares_encoded = reshares.map do |ss|
|
43
|
+
[ss[0], (ss[1].numerator * mod_inverse(ss[1].denominator, prime)) % prime]
|
44
|
+
end
|
45
|
+
[s_pair[0][0], reshares_encoded]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.prepare_share_for_multiplication(index, xs_, prime, s_pair)
|
49
|
+
beta = lagrange_basis_polynomial_inner_loop(index, xs_)
|
50
|
+
(s_pair[0][1] * s_pair[1][1] * beta) % prime
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.mul_second_round(mul_round1)
|
54
|
+
multiplication_shares = mul_round1.map(&:last).map { |m| m.map(&:last) }.transpose.map(&:sum)
|
55
|
+
multiplication_shares.map.with_index { |m, i| [i + 1, m] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.select_mul_shares(total_shares, threshold, shares)
|
59
|
+
indices = (0..total_shares - 1).to_a.sample((2 * threshold) - 1)
|
60
|
+
shares.map { |shares_| shares_.values_at(*indices) }
|
61
|
+
end
|
62
|
+
|
31
63
|
def self.generate_random_coefficients(total_shares, lambda_)
|
32
64
|
random_distinct_numbers("integer", total_shares - 1, lambda_ - 1)
|
33
65
|
end
|
34
66
|
|
35
|
-
def self.create_shares(secret, total_shares, lambda_, prime)
|
36
|
-
random_coefficients = generate_random_coefficients(
|
67
|
+
def self.create_shares(secret, total_shares, threshold, lambda_, prime)
|
68
|
+
random_coefficients = generate_random_coefficients(threshold, lambda_)
|
37
69
|
(1..total_shares).map.with_index { |x, i| [i + 1, f(x, secret, random_coefficients) % prime] }
|
38
70
|
end
|
39
71
|
|
72
|
+
def self.generate_division_masking(prime)
|
73
|
+
r1, r2 = random_distinct_numbers("integer", 2, prime.bit_length - 1)
|
74
|
+
r3 = (r2 * mod_inverse(r1, prime)) % prime
|
75
|
+
[r1, r2, r3]
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.compute_numerator_denominator(shares1, shares2, r1_, r2_, prime)
|
79
|
+
cs = shares1.map { |i, share| [i, (share * r1_) % prime] }
|
80
|
+
ds = shares2.map { |i, share| [i, (share * r2_) % prime] }
|
81
|
+
[cs, ds]
|
82
|
+
end
|
83
|
+
|
40
84
|
def initialize(params = {})
|
41
85
|
@lambda_ = params[:lambda_]
|
42
86
|
@total_shares = params[:total_shares]
|
@@ -44,16 +88,27 @@ module Sharing
|
|
44
88
|
generate_prime
|
45
89
|
end
|
46
90
|
|
91
|
+
def params
|
92
|
+
[lambda_, p, total_shares, threshold]
|
93
|
+
end
|
94
|
+
|
47
95
|
def create_shares(secret)
|
48
96
|
random_coefficients = generate_random_coefficients
|
49
|
-
(1..total_shares).map
|
97
|
+
(1..total_shares).map { |x| [x, f(x, secret, random_coefficients) % p] }
|
50
98
|
end
|
51
99
|
|
52
100
|
def reconstruct_secret(points)
|
53
101
|
xs = points.map(&:first)
|
54
102
|
ys = points.map(&:last)
|
55
103
|
l0s = lagrange_basis_polynomial(xs)
|
56
|
-
l0s.zip(ys).map { |l, y| l * y }.sum % p
|
104
|
+
reconstructed_secret = l0s.zip(ys).map { |l, y| l * y }.sum % p
|
105
|
+
encode_to_integer(reconstructed_secret)
|
106
|
+
end
|
107
|
+
|
108
|
+
def reconstruct_division(cs_, ds_, r3_)
|
109
|
+
c, d = [cs_, ds_].map { |shares| reconstruct_secret(shares) }
|
110
|
+
c_d_encoded = (c * mod_inverse(d, p) * r3_) % p
|
111
|
+
HenselCode::TruncatedFinitePadicExpansion.new(p, 1, c_d_encoded).to_r
|
57
112
|
end
|
58
113
|
|
59
114
|
private
|
@@ -63,7 +118,11 @@ module Sharing
|
|
63
118
|
end
|
64
119
|
|
65
120
|
def generate_random_coefficients
|
66
|
-
random_distinct_numbers("integer",
|
121
|
+
random_distinct_numbers("integer", threshold - 1, lambda_ - 1)
|
122
|
+
end
|
123
|
+
|
124
|
+
def encode_to_integer(reconstructed_secret)
|
125
|
+
(reconstructed_secret.numerator * mod_inverse(reconstructed_secret.denominator, p)) % p
|
67
126
|
end
|
68
127
|
end
|
69
128
|
end
|
data/lib/sharing/version.rb
CHANGED
data/sharing.gemspec
CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.require_paths = ["lib"]
|
31
31
|
|
32
32
|
# Uncomment to register a new dependency of your gem
|
33
|
-
spec.add_dependency "hensel_code", "~> 0.3.
|
33
|
+
spec.add_dependency "hensel_code", "~> 0.3.1"
|
34
34
|
spec.add_dependency "prime", "~> 0.1.2"
|
35
35
|
|
36
36
|
# For more information and examples about making a new gem, check out our
|
data/sig/secret_sharing.rbs
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sharing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David William Silva
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hensel_code
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.3.
|
19
|
+
version: 0.3.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.3.
|
26
|
+
version: 0.3.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: prime
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +45,7 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".codecov.yml"
|
48
49
|
- ".rubocop.yml"
|
49
50
|
- CHANGELOG.md
|
50
51
|
- Gemfile
|
@@ -54,6 +55,7 @@ files:
|
|
54
55
|
- Rakefile
|
55
56
|
- bin/console
|
56
57
|
- bin/setup
|
58
|
+
- codecov
|
57
59
|
- lib/sharing.rb
|
58
60
|
- lib/sharing/crt/asmuth-bloom/v2.rb
|
59
61
|
- lib/sharing/polynomial/shamir/v1.rb
|