mpvss_rs/participant.rs
1// Copyright 2020-2021 MathxH Chen.
2//
3// Code is licensed under GPLv3.0 License.
4
5#![allow(non_snake_case)]
6
7use crate::dleq::DLEQ;
8use crate::mpvss::MPVSS;
9use crate::polynomial::Polynomial;
10use crate::sharebox::{DistributionSharesBox, ShareBox};
11use crate::util::Util;
12use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
13use num_integer::Integer;
14use num_primes::Generator;
15use num_traits::identities::{One, Zero};
16use sha2::{Digest, Sha256};
17use std::clone::Clone;
18use std::collections::BTreeMap;
19use std::option::Option;
20
21/// A participant represents one party in the secret sharing scheme. The participant can share a secret among a group of other participants and it is then called the "dealer".
22/// The receiving participants that receive a part of the secret can use it to reconstruct the secret Therefore the partticipants need to collaborate and exchange their parts.
23/// A participant represents as a Node in the Distributed Public NetWork
24#[derive(Debug, Clone, Default)]
25pub struct Participant {
26 mpvss: MPVSS,
27 pub privatekey: BigInt,
28 pub publickey: BigInt,
29}
30
31impl Participant {
32 /// Create A default participant
33 ///
34 /// ## Example
35 ///
36 /// ```rust
37 /// use mpvss_rs::Participant;
38 /// let mut dealer = Participant::new();
39 /// ```
40 pub fn new() -> Self {
41 Participant {
42 mpvss: MPVSS::new(),
43 privatekey: BigInt::zero(),
44 publickey: BigInt::zero(),
45 }
46 }
47 /// Initializes a new participant with the default MPVSS.
48 ///
49 /// ## Example
50 ///
51 /// ```rust
52 /// use mpvss_rs::Participant;
53 /// let mut dealer = Participant::new();
54 /// dealer.initialize();
55 /// ```
56 pub fn initialize(&mut self) {
57 self.privatekey = self.mpvss.generate_private_key();
58 self.publickey = self.mpvss.generate_public_key(&self.privatekey);
59 }
60
61 fn distribute(
62 &mut self,
63 secret: &BigInt,
64 publickeys: &[BigInt],
65 threshold: u32,
66 polynomial: &Polynomial,
67 w: &BigInt,
68 ) -> DistributionSharesBox {
69 assert!(threshold <= publickeys.len() as u32);
70 // Data the distribution shares box is going to be consisting of
71 let mut commitments: Vec<BigInt> = Vec::new();
72 let mut positions: BTreeMap<BigInt, i64> = BTreeMap::new();
73 let mut X: BTreeMap<BigInt, BigInt> = BTreeMap::new();
74 let mut shares: BTreeMap<BigInt, BigInt> = BTreeMap::new();
75 let mut challenge_hasher = Sha256::new();
76
77 // Temp variable
78 let mut sampling_points: BTreeMap<BigInt, BigInt> = BTreeMap::new();
79 let mut a: BTreeMap<BigInt, (BigInt, BigInt)> = BTreeMap::new();
80 let mut dleq_w: BTreeMap<BigInt, BigInt> = BTreeMap::new();
81 let mut position: i64 = 1;
82
83 // Calculate Ploynomial Coefficients Commitments C_j = g^(a_j) under group of prime q, and 0 <= j < threshold
84 for j in 0..threshold {
85 commitments.push(
86 self.mpvss.g.modpow(
87 &polynomial.coefficients[j as usize],
88 &self.mpvss.q,
89 ),
90 )
91 }
92
93 // Calculate Every Encrypted shares with every participant's public key generated from their own private key
94 // Y_i = (y_i)^p(i) X_i = g^p(i) = C_0^(i^0) * C_1^(i^1) * C_2^(i^2) * ... * C_j^(i^j) and 1 <= i <= n 0 <= j <= threshhold - 1
95 // n is participant current total number
96 // p(i) is secret share without encrypt on the ploynomial of the degree t - 1
97 // y_i is participant public key
98 // Y_i is encrypted secret share
99 for pubkey in publickeys {
100 positions.insert(pubkey.clone(), position);
101 // calc P(position) % (q - 1), from P(1) to P(n), actually is from share 1 to share n
102 let secret_share = polynomial.get_value(&BigInt::from(position))
103 % (&self.mpvss.q - BigInt::one());
104 sampling_points.insert(pubkey.clone(), secret_share.clone());
105
106 // Calc X_i
107 let mut x: BigInt = BigInt::one();
108 let mut exponent: BigInt = BigInt::one();
109 for j in 0..=threshold - 1 {
110 x = (x * commitments[j as usize]
111 .modpow(&exponent, &self.mpvss.q))
112 % &self.mpvss.q;
113 exponent = (exponent * BigInt::from(position))
114 % (&self.mpvss.q - BigInt::one());
115 }
116
117 X.insert(pubkey.clone(), x.clone());
118
119 // Calc Y_i
120 let encrypted_secret_share =
121 pubkey.modpow(&secret_share, &self.mpvss.q);
122 shares.insert(pubkey.clone(), encrypted_secret_share.clone());
123
124 // DLEQ(g1,h1,g2,h2) => DLEQ(g,X_i,y_i,Y_i) => DLEQ(g,commintment_with_secret_share,pubkey,enrypted_secret_share_from_pubkey)
125 // Prove That g^alpha = commintment_with_secret_share and pubkey^alpha = encrypted_secret_share_from_pubkey has same alpha value
126 let mut dleq = DLEQ::new();
127 dleq.init2(
128 self.mpvss.g.clone(),
129 x.clone(),
130 pubkey.clone(),
131 encrypted_secret_share.clone(),
132 self.mpvss.q.clone(),
133 secret_share.clone(),
134 w.clone(),
135 );
136
137 dleq_w.insert(pubkey.clone(), dleq.w.clone());
138 // Calc a_1i, a_2i
139 a.insert(pubkey.clone(), (dleq.get_a1(), dleq.get_a2()));
140
141 // Update challenge hash
142 // the challenge c for the protocol is computed as a cryptographic hash of X_i,Y_i,a_1i,a_2i, 1 <= i <= n
143 challenge_hasher
144 .update(x.to_biguint().unwrap().to_str_radix(10).as_bytes());
145 challenge_hasher.update(
146 encrypted_secret_share
147 .to_biguint()
148 .unwrap()
149 .to_str_radix(10)
150 .as_bytes(),
151 );
152 challenge_hasher.update(
153 dleq.get_a1()
154 .to_biguint()
155 .unwrap()
156 .to_str_radix(10)
157 .as_bytes(),
158 );
159 challenge_hasher.update(
160 dleq.get_a2()
161 .to_biguint()
162 .unwrap()
163 .to_str_radix(10)
164 .as_bytes(),
165 );
166 position += 1;
167 } // end for participant's publickeys
168
169 // the common challenge c
170 let challenge_hash = challenge_hasher.finalize();
171 let challenge_big_uint = BigUint::from_bytes_be(&challenge_hash[..])
172 .mod_floor(&(self.mpvss.q.to_biguint().unwrap() - BigUint::one()));
173
174 // Calc response r_i
175 let mut responses: BTreeMap<BigInt, BigInt> = BTreeMap::new();
176 for pubkey in publickeys {
177 // DLEQ(g1,h2,g2,h2) => DLEQ(g,X_i,y_i,Y_i) => DLEQ(g,commintment_with_secret_share,pubkey,encrypted_secret_share_from_pubkey)
178 let x_i = X.get(pubkey).unwrap();
179 let encrypted_secret_share = shares.get(pubkey).unwrap();
180 let secret_share = sampling_points.get(pubkey).unwrap();
181 let w = dleq_w.get(pubkey).unwrap();
182 let mut dleq = DLEQ::new();
183 dleq.init2(
184 self.mpvss.g.clone(),
185 x_i.clone(),
186 pubkey.clone(),
187 encrypted_secret_share.clone(),
188 self.mpvss.q.clone(),
189 secret_share.clone(),
190 w.clone(),
191 );
192 dleq.c = Some(challenge_big_uint.to_bigint().unwrap());
193 let response = dleq.get_r().unwrap();
194 responses.insert(pubkey.clone(), response);
195 } // end for pubkeys Calc r_i
196
197 // Calc U = secret xor SHA256(G^s) = secret xor SHA256(G^p(0)).
198 // [Section 4]
199 // σ ∈ Σ, where 2 ≤ |Σ| ≤ q.
200 // the general procedure is to let the dealer first run the distribution protocol for a random value s ∈ Zq, and then publish U = σ ⊕ H(G^s),
201 // where H is an appropriate cryptographic hash function. The reconstruction protocol will yield G^s, from which we obtain σ = U ⊕ H(G^s).
202 let shared_value = self.mpvss.G.modpow(
203 &polynomial.get_value(&BigInt::zero()).mod_floor(
204 &(self.mpvss.q.to_bigint().unwrap() - BigInt::one()),
205 ),
206 &self.mpvss.q,
207 );
208 let sha256_hash = sha2::Sha256::digest(
209 shared_value
210 .to_biguint()
211 .unwrap()
212 .to_str_radix(10)
213 .as_bytes(),
214 );
215 let hash_big_uint = BigUint::from_bytes_be(&sha256_hash[..])
216 .mod_floor(&self.mpvss.q.to_biguint().unwrap());
217 let U = secret.to_biguint().unwrap() ^ hash_big_uint;
218
219 // The proof consists of the common challenge c and the n responses r_i.
220 let mut shares_box = DistributionSharesBox::new();
221 shares_box.init(
222 &commitments,
223 positions,
224 shares,
225 publickeys,
226 &challenge_big_uint.to_bigint().unwrap(),
227 responses,
228 &U.to_bigint().unwrap(),
229 );
230 shares_box
231 }
232
233 /// Takes a secret as input and returns the distribution shares Box which is going to be submitted to all the participants the secret is going to be shared with.
234 /// Those participants are specified by their public keys. They use the distribution shares box to verify that the shares are correct (without learning anything about the shares that are not supposed to be decrypted by them)
235 /// and extract their encrypted shares. In fact, the distribution shares box can be published to everyone allowing even external parties to verify the integrity of the shares.
236 ///
237 /// - Parameters:
238 /// - secret: The value that is going to be shared among the other participants.
239 /// - publicKeys: Array of public keys of each participant the secret is to be shared with.
240 /// - threshold: The number of shares that is needed in order to reconstruct the secret. It must not be greater than the total number of participants.
241 /// - Requires: `threshold` <= number of participants
242 /// - Returns: The distribution shares Box that is published to everyone (especially but not only the participants) can check the shares' integrity. Furthermore the participants extract their shares from it.
243 ///
244 /// ## Example
245 ///
246 /// ```rust
247 /// use mpvss_rs::Participant;
248 /// use num_bigint::{BigUint, ToBigInt};
249 ///
250 /// let secret_message = String::from("Hello MPVSS Example.");
251 /// let secret = BigUint::from_bytes_be(&secret_message.as_bytes());
252 /// let mut dealer = Participant::new();
253 /// dealer.initialize();
254 /// let mut p1 = Participant::new();
255 /// let mut p2 = Participant::new();
256 /// let mut p3 = Participant::new();
257 /// p1.initialize();
258 /// p2.initialize();
259 /// p3.initialize();
260 ///
261 /// let distribute_shares_box = dealer.distribute_secret(
262 /// &secret.to_bigint().unwrap(),
263 /// &vec![
264 /// p1.publickey.clone(),
265 /// p2.publickey.clone(),
266 /// p3.publickey.clone(),
267 /// ],
268 /// 3,
269 /// );
270 /// ```
271 pub fn distribute_secret(
272 &mut self,
273 secret: &BigInt,
274 publickeys: &[BigInt],
275 threshold: u32,
276 ) -> DistributionSharesBox {
277 let mut polynomial = Polynomial::new();
278 polynomial
279 .init((threshold - 1) as i32, &self.mpvss.q.to_bigint().unwrap());
280
281 let mut rng = rand::thread_rng();
282 let w: BigUint =
283 rng.gen_biguint_below(&self.mpvss.q.to_biguint().unwrap());
284 self.distribute(
285 secret,
286 publickeys,
287 threshold,
288 &polynomial,
289 &w.to_bigint().unwrap(),
290 )
291 }
292
293 fn extract_share(
294 &self,
295 shares_box: &DistributionSharesBox,
296 private_key: &BigInt,
297 w: &BigInt,
298 ) -> Option<ShareBox> {
299 let public_key = self.mpvss.generate_public_key(private_key);
300 let encrypted_secret_share =
301 shares_box.shares.get(&public_key).unwrap();
302
303 // Decryption of the shares.
304 // Using its private key x_i, each participant finds the decrypted share S_i = G^p(i) from Y_i by computing S_i = Y_i^(1/x_i).
305 // Y_i is encrypted share: Y_i = y_i^p(i)
306 // find modular multiplicative inverses of private key
307 let privkey_inverse =
308 Util::mod_inverse(private_key, &(&self.mpvss.q - BigInt::one()))
309 .unwrap();
310 let decrypted_share =
311 encrypted_secret_share.modpow(&privkey_inverse, &self.mpvss.q);
312
313 // To this end it suffices to prove knowledge of an α such that y_i= G^α and Y_i= S_i^α, which is accomplished by the non-interactive version of the protocol DLEQ(G,y_i,S_i,Y_i).
314 // DLEQ(G,y_i,S_i,Y_i) => DLEQ(G, publickey, decrypted_share, encryted_share)
315 // All of this is to prove and tell participants that the decrypted share is must use your own public key encrypted,
316 // and only you can decrypt the share with your own private key and verify the share's proof
317 let mut dleq = DLEQ::new();
318 dleq.init2(
319 self.mpvss.G.clone(),
320 public_key.clone(),
321 decrypted_share.clone(),
322 encrypted_secret_share.clone(),
323 self.mpvss.q.clone(),
324 private_key.clone(),
325 w.clone(),
326 );
327
328 let mut challenge_hasher = Sha256::new();
329 challenge_hasher.update(
330 public_key.to_biguint().unwrap().to_str_radix(10).as_bytes(),
331 );
332 challenge_hasher.update(
333 encrypted_secret_share
334 .to_biguint()
335 .unwrap()
336 .to_str_radix(10)
337 .as_bytes(),
338 );
339 challenge_hasher.update(
340 dleq.get_a1()
341 .to_biguint()
342 .unwrap()
343 .to_str_radix(10)
344 .as_bytes(),
345 );
346 challenge_hasher.update(
347 dleq.get_a2()
348 .to_biguint()
349 .unwrap()
350 .to_str_radix(10)
351 .as_bytes(),
352 );
353
354 // the challenge c
355 let challenge_hash = challenge_hasher.finalize();
356 let challenge_big_uint = BigUint::from_bytes_be(&challenge_hash[..])
357 .mod_floor(&(self.mpvss.q.to_biguint().unwrap() - BigUint::one()));
358 dleq.c = Some(challenge_big_uint.to_bigint().unwrap());
359
360 let mut share_box = ShareBox::new();
361 share_box.init(
362 public_key,
363 decrypted_share,
364 challenge_big_uint.to_bigint().unwrap(),
365 dleq.get_r().unwrap(),
366 );
367 Some(share_box)
368 }
369
370 /// Extracts the share from a given distribution shares box that is addressed to the calling participant.
371 /// The extracted share is boxed with a proof which allows the other participants to verify the share's correctness.
372 ///
373 /// - Parameters:
374 /// - shares_box: The distribution shares box that consists the share to be extracted.
375 /// - private_key: The participant's private key used to decrypt the share.
376 /// - Returns: The share box that is to be submitted to all the other participants in order to reconstruct the secret.
377 /// It consists of the share itself and the proof that allows the receiving participant to verify its correctness.
378 /// Return `None` if the distribution shares box does not contain a share for the participant.
379 ///
380 /// ## Example
381 ///
382 /// ```rust
383 /// use mpvss_rs::Participant;
384 /// use num_bigint::{BigUint, ToBigInt};
385 ///
386 /// let secret_message = String::from("Hello MPVSS Example.");
387 /// let secret = BigUint::from_bytes_be(&secret_message.as_bytes());
388 /// let mut dealer = Participant::new();
389 /// dealer.initialize();
390 /// let mut p1 = Participant::new();
391 /// let mut p2 = Participant::new();
392 /// let mut p3 = Participant::new();
393 /// p1.initialize();
394 /// p2.initialize();
395 /// p3.initialize();
396 ///
397 /// let distribute_shares_box = dealer.distribute_secret(
398 /// &secret.to_bigint().unwrap(),
399 /// &vec![
400 /// p1.publickey.clone(),
401 /// p2.publickey.clone(),
402 /// p3.publickey.clone(),
403 /// ],
404 /// 3,
405 /// );
406 ///
407 /// let s1 = p1
408 /// .extract_secret_share(&distribute_shares_box, &p1.privatekey)
409 /// .unwrap();
410 /// let s2 = p2
411 /// .extract_secret_share(&distribute_shares_box, &p2.privatekey)
412 /// .unwrap();
413 /// let s3 = p3
414 /// .extract_secret_share(&distribute_shares_box, &p3.privatekey)
415 /// .unwrap();
416 /// ```
417 pub fn extract_secret_share(
418 &self,
419 shares_box: &DistributionSharesBox,
420 private_key: &BigInt,
421 ) -> Option<ShareBox> {
422 let w = Generator::new_uint(self.mpvss.length as usize)
423 .mod_floor(&self.mpvss.q.to_biguint().unwrap());
424 self.extract_share(shares_box, private_key, &w.to_bigint().unwrap())
425 }
426
427 /// Verifies that the shares the distribution shares box consists are consistent so that they can be used to reconstruct the secret later.
428 ///
429 /// - Parameter distribute_sharesbox: The distribution shares box whose consistency is to be verified.
430 /// - Returns: Returns `true` if the shares are correct and `false` otherwise.
431 ///
432 /// ## Example
433 ///
434 /// ```rust
435 /// use mpvss_rs::Participant;
436 /// use num_bigint::{BigUint, ToBigInt};
437 /// let secret_message = String::from("Hello MPVSS Example.");
438 /// let secret = BigUint::from_bytes_be(&secret_message.as_bytes());
439 /// let mut dealer = Participant::new();
440 /// dealer.initialize();
441 /// let mut p1 = Participant::new();
442 /// let mut p2 = Participant::new();
443 /// let mut p3 = Participant::new();
444 /// p1.initialize();
445 /// p2.initialize();
446 /// p3.initialize();
447 ///
448 /// let distribute_shares_box = dealer.distribute_secret(
449 /// &secret.to_bigint().unwrap(),
450 /// &vec![
451 /// p1.publickey.clone(),
452 /// p2.publickey.clone(),
453 /// p3.publickey.clone(),
454 /// ],
455 /// 3,
456 /// );
457 ///
458 /// assert_eq!(
459 /// p1.verify_distribution_shares(&distribute_shares_box),
460 /// true
461 /// );
462 ///
463 /// assert_eq!(
464 /// p2.verify_distribution_shares(&distribute_shares_box),
465 /// true
466 /// );
467 /// assert_eq!(
468 /// p3.verify_distribution_shares(&distribute_shares_box),
469 /// true
470 /// );
471 /// ```
472 pub fn verify_distribution_shares(
473 &self,
474 distribute_sharesbox: &DistributionSharesBox,
475 ) -> bool {
476 self.mpvss.verify_distribution_shares(distribute_sharesbox)
477 }
478
479 /// Verifies if the share in the distribution share box was decrypted correctly by the respective participant.
480 ///
481 /// - Parameters:
482 /// - shareBox: The share box containing the share to be verified.
483 /// - distributionShareBox: The distribution share box that contains the share.
484 /// - publicKey: The public key of the sender of the share bundle.
485 /// - Returns: Returns `true` if the share in the distribution share box matches the decryption of the encrypted share and `false` otherwise.
486 ///
487 /// ## Example
488 ///
489 /// ```rust
490 /// use mpvss_rs::Participant;
491 /// use num_bigint::{BigUint, ToBigInt};
492 ///
493 /// let secret_message = String::from("Hello MPVSS Example.");
494 /// let secret = BigUint::from_bytes_be(&secret_message.as_bytes());
495 /// let mut dealer = Participant::new();
496 /// dealer.initialize();
497 /// let mut p1 = Participant::new();
498 /// let mut p2 = Participant::new();
499 /// let mut p3 = Participant::new();
500 /// p1.initialize();
501 /// p2.initialize();
502 /// p3.initialize();
503 ///
504 /// let distribute_shares_box = dealer.distribute_secret(
505 /// &secret.to_bigint().unwrap(),
506 /// &vec![
507 /// p1.publickey.clone(),
508 /// p2.publickey.clone(),
509 /// p3.publickey.clone(),
510 /// ],
511 /// 3,
512 /// );
513 ///
514 /// let s1 = p1
515 /// .extract_secret_share(&distribute_shares_box, &p1.privatekey)
516 /// .unwrap();
517 /// let s2 = p2
518 /// .extract_secret_share(&distribute_shares_box, &p2.privatekey)
519 /// .unwrap();
520 /// let s3 = p3
521 /// .extract_secret_share(&distribute_shares_box, &p3.privatekey)
522 /// .unwrap();
523 ///
524 /// assert_eq!(
525 /// p1.verify_share(&s2, &distribute_shares_box, &p2.publickey),
526 /// true
527 /// );
528 ///
529 /// assert_eq!(
530 /// p2.verify_share(&s3, &distribute_shares_box, &p3.publickey),
531 /// true
532 /// );
533 ///
534 /// assert_eq!(
535 /// p3.verify_share(&s1, &distribute_shares_box, &s1.publickey),
536 /// true
537 /// );
538 /// ```
539 pub fn verify_share(
540 &self,
541 sharebox: &ShareBox,
542 distribution_sharebox: &DistributionSharesBox,
543 publickey: &BigInt,
544 ) -> bool {
545 self.mpvss
546 .verify_share(sharebox, distribution_sharebox, publickey)
547 }
548
549 /// Reconstruct secret from share boxs
550 ///
551 /// ## Example
552 ///
553 /// ```rust
554 /// use mpvss_rs::Participant;
555 /// use num_bigint::{BigUint, ToBigInt};
556 /// let secret_message = String::from("Hello MPVSS Example.");
557 /// let secret = BigUint::from_bytes_be(&secret_message.as_bytes());
558 /// let mut dealer = Participant::new();
559 /// dealer.initialize();
560 /// let mut p1 = Participant::new();
561 /// let mut p2 = Participant::new();
562 /// let mut p3 = Participant::new();
563 /// p1.initialize();
564 /// p2.initialize();
565 /// p3.initialize();
566 ///
567 /// let distribute_shares_box = dealer.distribute_secret(
568 /// &secret.to_bigint().unwrap(),
569 /// &vec![
570 /// p1.publickey.clone(),
571 /// p2.publickey.clone(),
572 /// p3.publickey.clone(),
573 /// ],
574 /// 3,
575 /// );
576 ///
577 /// assert_eq!(
578 /// p1.verify_distribution_shares(&distribute_shares_box),
579 /// true
580 /// );
581 ///
582 /// assert_eq!(
583 /// p2.verify_distribution_shares(&distribute_shares_box),
584 /// true
585 /// );
586 ///
587 /// assert_eq!(
588 /// p3.verify_distribution_shares(&distribute_shares_box),
589 /// true
590 /// );
591 ///
592 ///
593 /// let s1 = p1
594 /// .extract_secret_share(&distribute_shares_box, &p1.privatekey)
595 /// .unwrap();
596 ///
597 /// let s2 = p2
598 /// .extract_secret_share(&distribute_shares_box, &p2.privatekey)
599 /// .unwrap();
600 /// let s3 = p3
601 /// .extract_secret_share(&distribute_shares_box, &p3.privatekey)
602 /// .unwrap();
603 ///
604 /// assert_eq!(
605 /// p1.verify_share(&s2, &distribute_shares_box, &p2.publickey),
606 /// true
607 /// );
608 ///
609 /// assert_eq!(
610 /// p2.verify_share(&s3, &distribute_shares_box, &p3.publickey),
611 /// true
612 /// );
613 ///
614 /// assert_eq!(
615 /// p3.verify_share(&s1, &distribute_shares_box, &s1.publickey),
616 /// true
617 /// );
618 ///
619 /// let share_boxs = [s1, s2, s3];
620 /// let r1 = p1
621 /// .reconstruct(&share_boxs, &distribute_shares_box)
622 /// .unwrap();
623 /// let r2 = p2
624 /// .reconstruct(&share_boxs, &distribute_shares_box)
625 /// .unwrap();
626 /// let r3 = p3
627 /// .reconstruct(&share_boxs, &distribute_shares_box)
628 /// .unwrap();
629 ///
630 /// let r1_str =
631 /// String::from_utf8(r1.to_biguint().unwrap().to_bytes_be()).unwrap();
632 /// assert_eq!(secret_message.clone(), r1_str);
633 /// let r2_str =
634 /// String::from_utf8(r2.to_biguint().unwrap().to_bytes_be()).unwrap();
635 /// assert_eq!(secret_message.clone(), r2_str);
636 /// let r3_str =
637 /// String::from_utf8(r3.to_biguint().unwrap().to_bytes_be()).unwrap();
638 /// assert_eq!(secret_message.clone(), r3_str);
639 /// ```
640 pub fn reconstruct(
641 &self,
642 share_boxs: &[ShareBox],
643 distribute_share_box: &DistributionSharesBox,
644 ) -> Option<BigInt> {
645 self.mpvss.reconstruct(share_boxs, distribute_share_box)
646 }
647}
648
649#[cfg(test)]
650mod tests {
651
652 use super::BTreeMap;
653 use super::BigInt;
654 use super::MPVSS;
655 use super::Participant;
656 use super::Polynomial;
657 use super::{DistributionSharesBox, ShareBox};
658 use num_traits::{One, Zero};
659
660 struct Setup {
661 pub mpvss: MPVSS,
662 pub privatekey: BigInt,
663 pub secret: BigInt,
664 }
665
666 impl Setup {
667 fn new() -> Self {
668 let q = BigInt::from(179426549);
669 let g = BigInt::from(1301081);
670 let G = BigInt::from(15486487);
671
672 let length: i64 = 64_i64;
673 let mut mpvss = MPVSS::new();
674 mpvss.length = length as u32;
675 mpvss.g = g;
676 mpvss.G = G;
677 mpvss.q = q;
678
679 return Setup {
680 mpvss: mpvss,
681 privatekey: BigInt::from(105929),
682 secret: BigInt::from(1234567890),
683 };
684 }
685 }
686
687 // Use Fixed distribution shares box for tests
688 fn get_distribute_shares_box() -> DistributionSharesBox {
689 let setup = Setup::new();
690 let mut dealer = Participant::new();
691 dealer.mpvss = setup.mpvss.clone();
692 dealer.privatekey = setup.privatekey.clone();
693 dealer.publickey = setup.mpvss.generate_public_key(&setup.privatekey);
694
695 let mut polynomial = Polynomial::new();
696 polynomial.init_coefficients(&vec![
697 BigInt::from(164102006),
698 BigInt::from(43489589),
699 BigInt::from(98100795),
700 ]);
701 let threshold: i32 = 3;
702 // from participant 1 to 3
703 let privatekeys =
704 [BigInt::from(7901), BigInt::from(4801), BigInt::from(1453)];
705 let mut publickeys = vec![];
706 let w = BigInt::from(6345);
707
708 for key in privatekeys.iter() {
709 publickeys.push(setup.mpvss.generate_public_key(key));
710 }
711
712 return dealer.distribute(
713 &setup.secret,
714 &publickeys,
715 threshold as u32,
716 &polynomial,
717 &w,
718 );
719 }
720
721 // Use Fixed Share box for tests
722 fn get_share_box() -> ShareBox {
723 let distribution_shares_box = get_distribute_shares_box();
724 // Use Participant 1's private key
725 let private_key = BigInt::from(7901);
726 let w = BigInt::from(1337);
727 let mut participant = Participant::new();
728 let setup = Setup::new();
729 participant.mpvss = setup.mpvss.clone();
730 participant.privatekey = private_key.clone();
731 participant.publickey = setup.mpvss.generate_public_key(&private_key);
732
733 participant
734 .extract_share(&distribution_shares_box, &private_key, &w)
735 .unwrap()
736 }
737
738 #[test]
739 fn test_distribution() {
740 let distribution = get_distribute_shares_box();
741
742 let commitments = vec![
743 BigInt::from(92318234),
744 BigInt::from(76602245),
745 BigInt::from(63484157),
746 ];
747 let mut shares: BTreeMap<BigInt, BigInt> = BTreeMap::new();
748 shares
749 .insert(distribution.publickeys[0].clone(), BigInt::from(42478042));
750 shares
751 .insert(distribution.publickeys[1].clone(), BigInt::from(80117658));
752 shares
753 .insert(distribution.publickeys[2].clone(), BigInt::from(86941725));
754
755 let challenge = BigInt::from(41963410);
756 let mut responses: BTreeMap<BigInt, BigInt> = BTreeMap::new();
757 responses.insert(
758 distribution.publickeys[0].clone(),
759 BigInt::from(151565889),
760 );
761 responses.insert(
762 distribution.publickeys[1].clone(),
763 BigInt::from(146145105),
764 );
765 responses
766 .insert(distribution.publickeys[2].clone(), BigInt::from(71350321));
767
768 assert_eq!(distribution.publickeys[0], distribution.publickeys[0]);
769 assert_eq!(distribution.publickeys[1], distribution.publickeys[1]);
770 assert_eq!(distribution.publickeys[2], distribution.publickeys[2]);
771
772 assert_eq!(distribution.challenge, challenge);
773
774 for i in 0..=2 {
775 assert_eq!(distribution.commitments[i], commitments[i]);
776 assert_eq!(
777 distribution.shares[&distribution.publickeys[i]],
778 shares[&distribution.publickeys[i]]
779 );
780 assert_eq!(
781 distribution.responses[&distribution.publickeys[i]],
782 responses[&distribution.publickeys[i]]
783 );
784 }
785 }
786
787 #[test]
788 fn test_distribution_verify() {
789 let setup = Setup::new();
790 let distribution = get_distribute_shares_box();
791 assert_eq!(setup.mpvss.verify_distribution_shares(&distribution), true);
792 }
793
794 #[test]
795 fn test_extract_share() {
796 let share_box = get_share_box();
797 assert_eq!(share_box.share, BigInt::from(164021044));
798 assert_eq!(share_box.challenge, BigInt::from(134883166));
799 assert_eq!(share_box.response, BigInt::from(81801891));
800 }
801
802 #[test]
803 fn test_share_box_verify() {
804 // participant 1 private key
805 let private_key = BigInt::from(7901);
806 let distribution_shares_box = get_distribute_shares_box();
807 let share_box = get_share_box();
808
809 let setup = Setup::new();
810 assert_eq!(
811 setup.mpvss.verify_share(
812 &share_box,
813 &distribution_shares_box,
814 &setup.mpvss.generate_public_key(&private_key)
815 ),
816 true
817 );
818 }
819
820 #[test]
821 fn test_reconstruction_with_all_participants() {
822 let distribution_shares_box = get_distribute_shares_box();
823 let share_box1 = get_share_box();
824 let mut share_box2 = ShareBox::new();
825 share_box2.init(
826 BigInt::from(132222922),
827 BigInt::from(157312059),
828 BigInt::zero(),
829 BigInt::zero(),
830 );
831 let mut share_box3 = ShareBox::new();
832 share_box3.init(
833 BigInt::from(65136827),
834 BigInt::from(63399333),
835 BigInt::zero(),
836 BigInt::zero(),
837 );
838
839 let setup = Setup::new();
840 let share_boxs = [share_box1, share_box2, share_box3];
841 let reconstructed_secret = setup
842 .mpvss
843 .reconstruct(&share_boxs, &distribution_shares_box)
844 .unwrap();
845 assert_eq!(reconstructed_secret, setup.secret);
846 }
847
848 // (3,4) threshhold reconstruct, participant 3 is not available, 1,2,4 is available
849 #[test]
850 fn test_reconstruction_with_sub_group() {
851 let share_box1 = get_share_box();
852 let mut share_box2 = ShareBox::new();
853 share_box2.init(
854 BigInt::from(132222922),
855 BigInt::from(157312059),
856 BigInt::zero(),
857 BigInt::zero(),
858 );
859
860 let public_key4 = BigInt::from(42);
861 let mut share_box4 = ShareBox::new();
862 share_box4.init(
863 public_key4.clone(),
864 BigInt::from(59066181),
865 BigInt::zero(),
866 BigInt::zero(),
867 );
868
869 let mut positions = BTreeMap::new();
870 positions.insert(share_box1.clone().publickey, 1_i64);
871 positions.insert(share_box2.clone().publickey, 2_i64);
872 positions.insert(share_box4.clone().publickey, 4_i64);
873
874 let mut distribution_shares_box = DistributionSharesBox::new();
875 distribution_shares_box.init(
876 &vec![BigInt::zero(), BigInt::one(), BigInt::from(2)],
877 positions,
878 BTreeMap::new(),
879 &vec![],
880 &BigInt::zero(),
881 BTreeMap::new(),
882 &BigInt::from(1284073502),
883 );
884
885 let setup = Setup::new();
886 let share_boxs = [share_box1, share_box2, share_box4];
887 let reconstructed_secret = setup
888 .mpvss
889 .reconstruct(&share_boxs, &distribution_shares_box)
890 .unwrap();
891 assert_eq!(reconstructed_secret, setup.secret);
892 }
893}