Skip to main content

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}