Skip to content

Commit 58621d7

Browse files
authored
Add reconstruct_parallelized API for improve reconstruct performance (#2)
* Use rayon to improve reconstruct performance * Add reconstruct_parallelized API for improve perf
1 parent 87132be commit 58621d7

File tree

6 files changed

+309
-48
lines changed

6 files changed

+309
-48
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ num-integer = "0.1.44"
1717
num-primes = "0.1.2"
1818
num-traits = "0.2.14"
1919
rand = "0.5.6"
20+
rayon = "1.5.0"
2021
sha2 = "0.9.2"

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,32 @@ let r3_str = String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
140140
assert_eq!(secret_message.clone(), r3_str);
141141
```
142142

143+
Reconstruction using multi-threads.
144+
145+
```rust
146+
let share_boxs = [s1, s2, s3];
147+
let r1 = p1
148+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
149+
.unwrap();
150+
let r2 = p2
151+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
152+
.unwrap();
153+
let r3 = p3
154+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
155+
.unwrap();
156+
157+
let r1_str = String::from_utf8(r1.to_biguint().unwrap().to_bytes_be()).unwrap();
158+
assert_eq!(secret_message.clone(), r1_str);
159+
let r2_str = String::from_utf8(r2.to_biguint().unwrap().to_bytes_be()).unwrap();
160+
assert_eq!(secret_message.clone(), r2_str);
161+
let r3_str = String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
162+
assert_eq!(secret_message.clone(), r3_str);
163+
```
164+
165+
## In the futures
166+
167+
Add more Elliptic Curves groups.
168+
143169
## Related References:
144170

145171
- Berry Schoenmakers. [A Simple Publicly Verifiable Secret Sharing Scheme and its Application to Electronic Voting](https://www.win.tue.nl/~berry/papers/crypto99.pdf)

examples/mpvss_all.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,34 @@ fn main() {
7979
String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
8080
assert_eq!(secret_message.clone(), r3_str);
8181

82-
println!("secret message: {}", secret_message);
83-
println!("r1 str: {}", r1_str);
84-
println!("r2 str: {}", r2_str);
85-
println!("r3 str: {}", r3_str);
82+
println!("secret message with single thread: {}", secret_message);
83+
println!("r1 str with single thread: {}", r1_str);
84+
println!("r2 str with single thread: {}", r2_str);
85+
println!("r3 str with single thread: {}", r3_str);
86+
87+
// Improve reconstruct performance
88+
let r1 = p1
89+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
90+
.unwrap();
91+
let r2 = p2
92+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
93+
.unwrap();
94+
let r3 = p3
95+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
96+
.unwrap();
97+
98+
let r1_str =
99+
String::from_utf8(r1.to_biguint().unwrap().to_bytes_be()).unwrap();
100+
assert_eq!(secret_message.clone(), r1_str);
101+
let r2_str =
102+
String::from_utf8(r2.to_biguint().unwrap().to_bytes_be()).unwrap();
103+
assert_eq!(secret_message.clone(), r2_str);
104+
let r3_str =
105+
String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
106+
assert_eq!(secret_message.clone(), r3_str);
107+
108+
println!("secret message with parallelized: {}", secret_message);
109+
println!("r1 str with parallelized: {}", r1_str);
110+
println!("r2 str with parallelized: {}", r2_str);
111+
println!("r3 str with parallelized: {}", r3_str);
86112
}

examples/mpvss_sub.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,37 @@ fn main() {
102102
println!("r2 str: {}", r2_str);
103103
println!("r3 str: {}", r3_str);
104104
println!("r3 str: {}", r4_str);
105+
106+
// Improve reconstruct performance
107+
let r1 = p1
108+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
109+
.unwrap();
110+
let r2 = p2
111+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
112+
.unwrap();
113+
let r3 = p3
114+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
115+
.unwrap();
116+
let r4 = p4
117+
.reconstruct_parallelized(&share_boxs, &distribute_shares_box)
118+
.unwrap();
119+
120+
let r1_str =
121+
String::from_utf8(r1.to_biguint().unwrap().to_bytes_be()).unwrap();
122+
assert_eq!(secret_message.clone(), r1_str);
123+
let r2_str =
124+
String::from_utf8(r2.to_biguint().unwrap().to_bytes_be()).unwrap();
125+
assert_eq!(secret_message.clone(), r2_str);
126+
let r3_str =
127+
String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
128+
assert_eq!(secret_message.clone(), r3_str);
129+
let r4_str =
130+
String::from_utf8(r4.to_biguint().unwrap().to_bytes_be()).unwrap();
131+
assert_eq!(secret_message.clone(), r4_str);
132+
133+
println!("secret message with parallelized: {}", secret_message);
134+
println!("r1 str with parallelized: {}", r1_str);
135+
println!("r2 str with parallelized: {}", r2_str);
136+
println!("r3 str with parallelized: {}", r3_str);
137+
println!("r3 str with parallelized: {}", r4_str);
105138
}

src/mpvss.rs

Lines changed: 107 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
1212
use num_integer::Integer;
1313
use num_primes::Generator;
1414
use num_traits::identities::{One, Zero};
15+
use rayon::prelude::*;
1516
use sha2::{Digest, Sha256};
1617
use std::clone::Clone;
1718
use std::collections::BTreeMap;
@@ -189,6 +190,61 @@ impl MPVSS {
189190
dleq.check(&challenge_hasher)
190191
}
191192

193+
fn compute_factor(
194+
&self,
195+
position: i64,
196+
share: &BigInt,
197+
values: &[i64],
198+
) -> BigInt {
199+
let mut exponent = BigInt::one();
200+
let lagrangeCoefficient = Util::lagrange_coefficient(&position, values);
201+
if lagrangeCoefficient.0.clone() % lagrangeCoefficient.1.clone()
202+
== BigInt::zero()
203+
{
204+
// Lagrange coefficient is an integer
205+
exponent = lagrangeCoefficient.0.clone()
206+
/ Util::abs(&lagrangeCoefficient.1);
207+
} else {
208+
// Lagrange coefficient is a proper fraction
209+
// Cancel fraction if possible
210+
let mut numerator = lagrangeCoefficient.0.to_biguint().unwrap();
211+
let mut denominator =
212+
Util::abs(&lagrangeCoefficient.1).to_biguint().unwrap();
213+
let gcd = numerator.gcd(&denominator);
214+
numerator = numerator / gcd.clone();
215+
denominator = denominator / gcd.clone();
216+
217+
let q1 = self.q.clone() - BigInt::one();
218+
let inverseDenominator = Util::mod_inverse(
219+
&denominator.to_bigint().unwrap(),
220+
&q1.to_bigint().unwrap(),
221+
);
222+
if inverseDenominator.is_some() {
223+
exponent = (numerator.to_bigint().unwrap()
224+
* inverseDenominator.unwrap())
225+
% q1.clone().to_bigint().unwrap();
226+
} else {
227+
eprintln!("ERROR: Denominator of Lagrange coefficient fraction does not have an inverse. Share cannot be processed.");
228+
}
229+
}
230+
let mut factor = share
231+
.to_bigint()
232+
.unwrap()
233+
.modpow(&exponent, &self.q.to_bigint().unwrap());
234+
if lagrangeCoefficient.0 * lagrangeCoefficient.1 < BigInt::zero() {
235+
// Lagrange coefficient was negative. S^(-lambda) = 1/(S^lambda)
236+
let inverseFactor =
237+
Util::mod_inverse(&factor, &self.q.to_bigint().unwrap());
238+
if inverseFactor.is_some() {
239+
factor = inverseFactor.unwrap();
240+
} else {
241+
eprintln!("ERROR: Lagrange coefficient was negative and does not have an inverse. Share cannot be processed.")
242+
}
243+
}
244+
245+
factor
246+
}
247+
192248
/// Reconstruct secret from share boxs
193249
pub fn reconstruct(
194250
&self,
@@ -214,52 +270,59 @@ impl MPVSS {
214270
let mut secret: BigInt = BigInt::one();
215271
let values: Vec<i64> = shares.keys().map(|key| *key).collect();
216272
for (position, share) in shares {
217-
let mut exponent = BigInt::one();
218-
let lagrangeCoefficient =
219-
Util::lagrange_coefficient(&position, values.as_slice());
220-
if lagrangeCoefficient.0.clone() % lagrangeCoefficient.1.clone()
221-
== BigInt::zero()
222-
{
223-
// Lagrange coefficient is an integer
224-
exponent = lagrangeCoefficient.0.clone()
225-
/ Util::abs(&lagrangeCoefficient.1);
226-
} else {
227-
// Lagrange coefficient is a proper fraction
228-
// Cancel fraction if possible
229-
let mut numerator = lagrangeCoefficient.0.to_biguint().unwrap();
230-
let mut denominator =
231-
Util::abs(&lagrangeCoefficient.1).to_biguint().unwrap();
232-
let gcd = numerator.gcd(&denominator);
233-
numerator = numerator / gcd.clone();
234-
denominator = denominator / gcd.clone();
273+
let factor =
274+
self.compute_factor(position, &share, values.as_slice());
275+
secret = (secret * factor) % self.q.clone();
276+
}
235277

236-
let q1 = self.q.clone() - BigInt::one();
237-
let inverseDenominator = Util::mod_inverse(
238-
&denominator.to_bigint().unwrap(),
239-
&q1.to_bigint().unwrap(),
240-
);
241-
if inverseDenominator.is_some() {
242-
exponent = (numerator.to_bigint().unwrap()
243-
* inverseDenominator.unwrap())
244-
% q1.clone().to_bigint().unwrap();
245-
} else {
246-
println!("ERROR: Denominator of Lagrange coefficient fraction does not have an inverse. Share cannot be processed.");
247-
}
248-
}
249-
let mut factor = share
250-
.to_bigint()
251-
.unwrap()
252-
.modpow(&exponent, &self.q.to_bigint().unwrap());
253-
if lagrangeCoefficient.0 * lagrangeCoefficient.1 < BigInt::zero() {
254-
// Lagrange coefficient was negative. S^(-lambda) = 1/(S^lambda)
255-
let inverseFactor =
256-
Util::mod_inverse(&factor, &self.q.to_bigint().unwrap());
257-
if inverseFactor.is_some() {
258-
factor = inverseFactor.unwrap();
259-
} else {
260-
println!("ERROR: Lagrange coefficient was negative and does not have an inverse. Share cannot be processed.")
261-
}
278+
// Reconstruct the secret = H(G^s) xor U
279+
let secret_hash = sha2::Sha256::digest(
280+
&secret.to_biguint().unwrap().to_str_radix(10).as_bytes(),
281+
);
282+
let hash_big_uint = BigUint::from_bytes_be(&secret_hash[..])
283+
.mod_floor(&self.q.to_biguint().unwrap());
284+
let decrypted_secret = hash_big_uint
285+
^ distribute_share_box.U.clone().to_biguint().unwrap();
286+
Some(decrypted_secret.to_bigint().unwrap())
287+
}
288+
289+
/// Reconstruct secret from share boxs using multi threaded
290+
pub fn reconstruct_parallelized(
291+
&self,
292+
share_boxs: &[ShareBox],
293+
distribute_share_box: &DistributionSharesBox,
294+
) -> Option<BigInt> {
295+
if share_boxs.len() < distribute_share_box.commitments.len() {
296+
return None;
297+
}
298+
let mut shares: BTreeMap<i64, BigInt> = BTreeMap::new();
299+
for share_box in share_boxs.iter() {
300+
let position =
301+
distribute_share_box.positions.get(&share_box.publickey);
302+
if position.is_none() {
303+
return None;
262304
}
305+
shares.insert(*position.unwrap(), share_box.share.clone());
306+
}
307+
// Pooling the shares. Suppose
308+
// w.l.o.g. that participantsPiproduce correctvalues for S_i, for i= 1,...,t.
309+
// The secret G^s is obtained by Lagrange interpolation:
310+
// ∏(i=1->t)(S^λ_i) = ∏(i=1->t)(G^p(i))^λ_i = G^(∑(i=1->t)p(i)*λ_i = G^p(0) = G^s,
311+
let mut secret: BigInt = BigInt::one();
312+
let values: Vec<i64> = shares.keys().map(|key| *key).collect();
313+
let shares_vec: Vec<(i64, BigInt)> = shares
314+
.into_iter()
315+
.map(|(postion, share)| (postion, share))
316+
.collect();
317+
let shares_slice = shares_vec.as_slice();
318+
let factors: Vec<BigInt> = shares_slice
319+
.par_iter()
320+
.map(|(position, share)| {
321+
self.compute_factor(*position, share, values.as_slice())
322+
})
323+
.collect();
324+
325+
for factor in factors {
263326
secret = (secret * factor) % self.q.clone();
264327
}
265328

0 commit comments

Comments
 (0)