race_api/
random.rs

1//! # Random handling
2//!
3//! We use Mental Poker randomization between transactors.
4
5use std::{collections::HashMap, iter::repeat};
6
7use borsh::{BorshDeserialize, BorshSerialize};
8use thiserror::Error;
9
10use crate::types::{Ciphertext, RandomId, SecretDigest, SecretIdent, SecretKey};
11
12#[derive(Error, Debug, PartialEq, Eq)]
13pub enum Error {
14    #[error("invalid random status: {0:?}")]
15    InvalidRandomStatus(RandomStatus),
16
17    #[error("invalid operator, expected: {0}, actual: {1}")]
18    InvalidOperator(String, String),
19
20    #[error("duplicated mask")]
21    DuplicatedMask,
22
23    #[error("duplicated lock")]
24    DuplicatedLock,
25
26    #[error("can't mask")]
27    CantMask,
28
29    #[error("invalid ciphertexts")]
30    InvalidCiphertexts,
31
32    #[error("update expired")]
33    UpdateExpired,
34
35    #[error("invalid index")]
36    InvalidIndex,
37
38    #[error("ciphertext already assigned")]
39    CiphertextAlreadyAssigned,
40
41    #[error("invalid mask provider")]
42    InvalidMaskProvider,
43
44    #[error("invalid lock provider")]
45    InvalidLockProvider,
46
47    #[error("duplicated secret")]
48    DuplicatedSecret,
49
50    #[error("invalid secret")]
51    InvalidSecret,
52
53    #[error("randomness is not ready")]
54    RandomnessNotReady,
55
56    #[error("secrets are not ready")]
57    SecretsNotReady,
58
59    #[error("No enough servers")]
60    NoEnoughServer,
61
62    #[error("Invalid reveal operation")]
63    InvalidRevealOperation,
64
65    #[error("Unreachable: {0}")]
66    Unreachable(String),
67}
68
69impl From<Error> for crate::error::Error {
70    fn from(e: Error) -> Self {
71        Self::RandomizationError(e.to_string())
72    }
73}
74
75pub type Result<T> = std::result::Result<T, Error>;
76
77#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
78pub enum RandomMode {
79    Shuffler,
80    Drawer,
81}
82
83#[derive(Debug, BorshDeserialize, BorshSerialize, PartialEq, Eq)]
84pub enum RandomSpec {
85    ShuffledList {
86        options: Vec<String>,
87    },
88    Lottery {
89        options_and_weights: HashMap<String, u16>,
90    },
91}
92
93impl RandomSpec {
94    pub fn as_options(self) -> Vec<String> {
95        match self {
96            RandomSpec::ShuffledList { options } => options,
97            RandomSpec::Lottery {
98                options_and_weights,
99            } => options_and_weights
100                .into_iter()
101                .flat_map(|(o, w)| repeat(o).take(w as _))
102                .collect(),
103        }
104    }
105
106    /// Create a deck of cards.
107    /// Use A, 2-9, T, J, Q, K for kinds.
108    /// Use S(spade), D(diamond), C(club), H(heart) for suits.
109    pub fn deck_of_cards() -> Self {
110        RandomSpec::ShuffledList {
111            options: vec![
112                "ha".into(),
113                "h2".into(),
114                "h3".into(),
115                "h4".into(),
116                "h5".into(),
117                "h6".into(),
118                "h7".into(),
119                "h8".into(),
120                "h9".into(),
121                "ht".into(),
122                "hj".into(),
123                "hq".into(),
124                "hk".into(),
125                "sa".into(),
126                "s2".into(),
127                "s3".into(),
128                "s4".into(),
129                "s5".into(),
130                "s6".into(),
131                "s7".into(),
132                "s8".into(),
133                "s9".into(),
134                "st".into(),
135                "sj".into(),
136                "sq".into(),
137                "sk".into(),
138                "da".into(),
139                "d2".into(),
140                "d3".into(),
141                "d4".into(),
142                "d5".into(),
143                "d6".into(),
144                "d7".into(),
145                "d8".into(),
146                "d9".into(),
147                "dt".into(),
148                "dj".into(),
149                "dq".into(),
150                "dk".into(),
151                "ca".into(),
152                "c2".into(),
153                "c3".into(),
154                "c4".into(),
155                "c5".into(),
156                "c6".into(),
157                "c7".into(),
158                "c8".into(),
159                "c9".into(),
160                "ct".into(),
161                "cj".into(),
162                "cq".into(),
163                "ck".into(),
164            ],
165        }
166    }
167
168    pub fn shuffled_list(options: Vec<String>) -> Self {
169        RandomSpec::ShuffledList { options }
170    }
171
172    pub fn lottery(options_and_weights: HashMap<String, u16>) -> Self {
173        RandomSpec::Lottery {
174            options_and_weights,
175        }
176    }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
180pub enum MaskStatus {
181    Required,
182    Applied,
183    Removed,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
187pub struct Mask {
188    pub status: MaskStatus,
189    pub owner: String,
190}
191
192impl Mask {
193    pub fn new<S: Into<String>>(owner: S) -> Self {
194        Self {
195            status: MaskStatus::Required,
196            owner: owner.into(),
197        }
198    }
199
200    pub fn is_required(&self) -> bool {
201        self.status == MaskStatus::Required
202    }
203
204    pub fn is_applied(&self) -> bool {
205        self.status == MaskStatus::Applied
206    }
207
208    pub fn is_removed(&self) -> bool {
209        self.status == MaskStatus::Removed
210    }
211
212    pub fn belongs_to<S: AsRef<str>>(&self, addr: S) -> bool {
213        self.owner.eq(addr.as_ref())
214    }
215}
216
217#[derive(Clone, Default, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
218pub struct Lock {
219    pub digest: SecretDigest,
220    pub owner: String,
221}
222
223impl Lock {
224    pub fn new<S: Into<String>>(owner: S, digest: SecretDigest) -> Self {
225        Self {
226            digest,
227            owner: owner.into(),
228        }
229    }
230}
231
232#[derive(Debug, Default, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone)]
233pub enum CipherOwner {
234    #[default]
235    Unclaimed,
236    // Visible to the assigned player only
237    Assigned(String),
238    // Assigned to multiple players
239    MultiAssigned(Vec<String>),
240    Revealed,
241}
242
243/// The representation of a ciphertext with locks applied.
244/// If all the required locks are applied, then it's ready.
245#[derive(Debug, Default, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone)]
246pub struct LockedCiphertext {
247    pub locks: Vec<Lock>,
248    pub owner: CipherOwner,
249    pub ciphertext: Ciphertext,
250}
251
252impl LockedCiphertext {
253    pub fn new(text: Ciphertext) -> Self {
254        Self {
255            locks: vec![],
256            owner: CipherOwner::Unclaimed,
257            ciphertext: text,
258        }
259    }
260
261    pub fn ciphertext(&self) -> &Ciphertext {
262        &self.ciphertext
263    }
264}
265
266#[derive(Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone)]
267pub struct Share {
268    from_addr: String,
269    // None means public revealed
270    to_addr: Option<String>,
271    index: usize,
272    // None means missing
273    secret: Option<SecretKey>,
274}
275
276#[derive(Default, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone)]
277pub enum RandomStatus {
278    #[default]
279    Ready,
280    Locking(String), // The address to mask the ciphertexts
281    Masking(String), // The address to lock the ciphertexts
282    WaitingSecrets,  // Waiting for the secrets to be shared
283    Shared,          // All secrets are shared, waiting to be notified to the system
284}
285
286/// RandomState represents the public information for a single randomness.
287#[derive(Default, Debug, PartialEq, Eq, BorshDeserialize, BorshSerialize, Clone)]
288pub struct RandomState {
289    pub id: RandomId,
290    pub size: usize,
291    pub owners: Vec<String>,
292    pub options: Vec<String>,
293    pub status: RandomStatus,
294    pub masks: Vec<Mask>,
295    pub ciphertexts: Vec<LockedCiphertext>,
296    pub secret_shares: Vec<Share>,
297    pub revealed: HashMap<usize, String>,
298}
299
300impl RandomState {
301    pub fn is_fully_masked(&self) -> bool {
302        self.masks.iter().all(|m| !m.is_required())
303    }
304
305    pub fn is_fully_locked(&self) -> bool {
306        self.masks.iter().all(|m| m.is_removed())
307    }
308
309    pub fn is_shared(&self) -> bool {
310        self.status == RandomStatus::Shared
311    }
312
313    pub fn is_ready(&self) -> bool {
314        self.status == RandomStatus::Ready
315    }
316
317    pub fn get_ciphertext(&self, index: usize) -> Option<&LockedCiphertext> {
318        self.ciphertexts.get(index)
319    }
320
321    pub fn get_ciphertext_unchecked(&self, index: usize) -> &LockedCiphertext {
322        &self.ciphertexts[index]
323    }
324
325    fn get_ciphertext_mut(&mut self, index: usize) -> Option<&mut LockedCiphertext> {
326        self.ciphertexts.get_mut(index)
327    }
328
329    pub fn try_new(id: RandomId, spec: RandomSpec, owners: &[String]) -> Result<Self> {
330        let options = spec.as_options();
331        let size = options.len();
332
333        let ciphertexts = options
334            .iter()
335            .map(|o| {
336                let ciphertext = o.as_bytes().to_owned();
337                LockedCiphertext::new(ciphertext)
338            })
339            .collect();
340
341        let masks = owners.iter().map(Mask::new).collect();
342
343        let status = if let Some(owner) = owners.first() {
344            RandomStatus::Masking(owner.clone())
345        } else {
346            return Err(Error::NoEnoughServer);
347        };
348
349        Ok(Self {
350            id,
351            size,
352            masks,
353            owners: owners.to_owned(),
354            options: options.clone(),
355            status,
356            ciphertexts,
357            revealed: HashMap::new(),
358            secret_shares: Vec::new(),
359        })
360    }
361
362    pub fn mask<S: AsRef<str>>(&mut self, addr: S, mut ciphertexts: Vec<Ciphertext>) -> Result<()> {
363        match self.status {
364            RandomStatus::Masking(ref a) => {
365                let addr = addr.as_ref();
366                if a.ne(addr) {
367                    return Err(Error::InvalidOperator(a.into(), addr.into()));
368                }
369                if let Some(mask) = self.masks.iter_mut().find(|m| m.owner.eq(addr)) {
370                    if !mask.is_required() {
371                        return Err(Error::DuplicatedMask);
372                    } else {
373                        if ciphertexts.len() != self.ciphertexts.len() {
374                            return Err(Error::InvalidCiphertexts);
375                        }
376                        for c in self.ciphertexts.iter_mut() {
377                            c.ciphertext = ciphertexts.remove(0);
378                        }
379                        mask.status = MaskStatus::Applied;
380                        self.update_status();
381                    }
382                } else {
383                    // unreachable
384                    return Err(Error::Unreachable("Mask is None, this is an internal error".into()));
385                }
386                Ok(())
387            }
388            _ => Err(Error::InvalidRandomStatus(self.status.clone())),
389        }
390    }
391
392    pub fn lock<S>(
393        &mut self,
394        addr: S,
395        mut ciphertexts_and_digests: Vec<(Ciphertext, SecretDigest)>,
396    ) -> Result<()>
397    where
398        S: Into<String> + AsRef<str> + Clone,
399    {
400        match self.status {
401            RandomStatus::Locking(ref a) => {
402                let addr = addr.as_ref();
403                if a.ne(addr) {
404                    return Err(Error::InvalidOperator(a.into(), addr.into()));
405                }
406                if let Some(mask) = self.masks.iter_mut().find(|m| m.owner.eq(addr)) {
407                    if mask.status.eq(&MaskStatus::Removed) {
408                        return Err(Error::DuplicatedLock);
409                    }
410                    if ciphertexts_and_digests.len() != self.ciphertexts.len() {
411                        return Err(Error::InvalidCiphertexts);
412                    }
413                    mask.status = MaskStatus::Removed;
414                    for c in self.ciphertexts.iter_mut() {
415                        let (new_text, digest) = ciphertexts_and_digests.remove(0);
416                        c.ciphertext = new_text;
417                        c.locks.push(Lock::new(addr.to_owned(), digest));
418                    }
419                    self.update_status();
420                } else {
421                    return Err(Error::Unreachable("Mask is None, this is an internal error".into()));
422                }
423                Ok(())
424            }
425            _ => Err(Error::InvalidRandomStatus(self.status.clone())),
426        }
427    }
428
429    pub fn assign<S>(&mut self, addr: S, indexes: Vec<usize>) -> Result<()>
430    where
431        S: ToOwned<Owned = String>,
432    {
433        if !matches!(
434            self.status,
435            RandomStatus::Shared | RandomStatus::Ready | RandomStatus::WaitingSecrets
436        ) {
437            return Err(Error::InvalidRandomStatus(self.status.clone()));
438        }
439
440        if indexes
441            .iter()
442            .filter_map(|i| self.get_ciphertext(*i))
443            .any(|c| matches!(c.owner, CipherOwner::Assigned(_) | CipherOwner::Revealed))
444        {
445            return Err(Error::CiphertextAlreadyAssigned);
446        }
447
448        for i in indexes.into_iter() {
449            if let Some(c) = self.get_ciphertext_mut(i) {
450                c.owner = CipherOwner::Assigned(addr.to_owned());
451            }
452            let secrets = &mut self.secret_shares;
453            for o in self.owners.iter() {
454                secrets.push(Share {
455                    from_addr: o.to_owned(),
456                    to_addr: Some(addr.to_owned()),
457                    index: i,
458                    secret: None,
459                });
460            }
461        }
462
463        self.status = RandomStatus::WaitingSecrets;
464
465        Ok(())
466    }
467
468    fn add_secret_share(&mut self, share: Share) {
469        if self
470            .secret_shares
471            .iter()
472            .find(|ss| {
473                ss.from_addr.eq(&share.from_addr)
474                    && ss.to_addr.eq(&share.to_addr)
475                    && ss.index == share.index
476            })
477            .is_none()
478        {
479            self.secret_shares.push(share);
480        }
481    }
482    pub fn reveal(&mut self, indexes: Vec<usize>) -> Result<()> {
483        if !matches!(
484            self.status,
485            RandomStatus::Shared | RandomStatus::Ready | RandomStatus::WaitingSecrets
486        ) {
487            return Err(Error::InvalidRandomStatus(self.status.clone()));
488        }
489
490        for i in indexes.into_iter() {
491            if let Some(c) = self.get_ciphertext_mut(i) {
492                if c.owner != CipherOwner::Revealed {
493                    c.owner = CipherOwner::Revealed;
494                    let owners: Vec<String> = self.owners.iter().map(|o| o.to_owned()).collect();
495                    for o in owners.into_iter() {
496                        self.add_secret_share(Share {
497                            from_addr: o,
498                            to_addr: None,
499                            index: i,
500                            secret: None,
501                        })
502                    }
503                }
504            }
505        }
506
507        self.status = RandomStatus::WaitingSecrets;
508        Ok(())
509    }
510
511    pub fn list_required_secrets_by_from_addr(&self, from_addr: &str) -> Vec<SecretIdent> {
512        self.secret_shares
513            .iter()
514            .filter(|ss| ss.secret.is_none() && ss.from_addr.eq(from_addr))
515            .map(|ss| SecretIdent {
516                from_addr: ss.from_addr.clone(),
517                to_addr: ss.to_addr.clone(),
518                random_id: self.id,
519                index: ss.index as usize,
520            })
521            .collect()
522    }
523
524    pub fn list_revealed_secrets(&self) -> Result<HashMap<usize, Vec<Ciphertext>>> {
525        if self.status != RandomStatus::Ready {
526            return Err(Error::SecretsNotReady);
527        }
528        let ret = self
529            .secret_shares
530            .iter()
531            .filter(|ss| ss.to_addr.is_none())
532            .fold(HashMap::new(), |mut acc, ss| {
533                acc.entry(ss.index as usize)
534                    .and_modify(|v: &mut Vec<SecretKey>| {
535                        v.push(ss.secret.as_ref().unwrap().clone())
536                    })
537                    .or_insert_with(|| vec![ss.secret.as_ref().unwrap().clone()]);
538                acc
539            });
540        Ok(ret)
541    }
542
543    /// List all ciphertexts assigned to a specific address.
544    /// Return a mapping from item index to ciphertext.
545    pub fn list_assigned_ciphertexts(&self, addr: &str) -> HashMap<usize, Ciphertext> {
546        self.ciphertexts
547            .iter()
548            .enumerate()
549            .filter_map(|(i, c)| {
550                if matches!(&c.owner, CipherOwner::Assigned(a) if a.eq(addr)) {
551                    Some((i as usize, c.ciphertext.clone()))
552                } else {
553                    None
554                }
555            })
556            .collect()
557    }
558
559    pub fn list_revealed_ciphertexts(&self) -> HashMap<usize, Ciphertext> {
560        self.ciphertexts
561            .iter()
562            .enumerate()
563            .filter_map(|(i, c)| {
564                if c.owner == CipherOwner::Revealed {
565                    Some((i as usize, c.ciphertext.clone()))
566                } else {
567                    None
568                }
569            })
570            .collect()
571    }
572
573    /// List shared secrets by receiver address.
574    /// Return a mapping from item index to list of secrets(each is in HEX format).
575    /// Return [[Error::SecretsNotReady]] in case of any missing secret.
576    pub fn list_shared_secrets(&self, to_addr: &str) -> Result<HashMap<usize, Vec<SecretKey>>> {
577        if self.status.ne(&RandomStatus::Ready) {
578            return Err(Error::SecretsNotReady);
579        }
580
581        Ok(self
582            .secret_shares
583            .iter()
584            .filter(|ss| ss.to_addr.is_some() && ss.to_addr.as_ref().unwrap().eq(to_addr))
585            .fold(HashMap::new(), |mut acc, ss| {
586                acc.entry(ss.index)
587                    .and_modify(|v: &mut Vec<SecretKey>| {
588                        v.push(ss.secret.as_ref().unwrap().clone())
589                    })
590                    .or_insert_with(|| vec![ss.secret.as_ref().unwrap().clone()]);
591                acc
592            }))
593    }
594
595    pub fn add_revealed(&mut self, revealed: HashMap<usize, String>) -> Result<()> {
596        for (index, value) in revealed.into_iter() {
597            if index >= self.size {
598                return Err(Error::InvalidIndex);
599            }
600            self.revealed.entry(index).or_insert(value);
601        }
602        Ok(())
603    }
604
605    pub fn get_revealed(&self) -> &HashMap<usize, String> {
606        &self.revealed
607    }
608
609    pub fn add_secret(
610        &mut self,
611        from_addr: String,
612        to_addr: Option<String>,
613        index: usize,
614        secret: SecretKey,
615    ) -> Result<()> {
616        if let Some(secret_share) = self
617            .secret_shares
618            .iter_mut()
619            .find(|ss| ss.from_addr.eq(&from_addr) && ss.to_addr.eq(&to_addr) && ss.index == index)
620        {
621            match secret_share.secret {
622                None => {
623                    if let Some(_ciphertext) = self.ciphertexts.get(secret_share.index) {
624                        // TODO, check digest
625                        // if let Some(lock) = ciphertext.locks.iter().find(|l| l.owner.eq(&from_addr)) {
626
627                        // } else {
628                        //     return Err(Error::InvalidSecret);
629                        // }
630                        secret_share.secret = Some(secret);
631                    } else {
632                        return Err(Error::InvalidSecret);
633                    }
634                }
635                Some(_) => return Err(Error::DuplicatedSecret),
636            }
637        }
638        self.update_status();
639        Ok(())
640    }
641
642    /// Return addresses those haven't submitted operation
643    pub fn list_operating_addrs(&self) -> Vec<String> {
644        match &self.status {
645            RandomStatus::Shared => Vec::new(),
646            RandomStatus::Ready => Vec::new(),
647            RandomStatus::Locking(addr) => vec![addr.clone()],
648            RandomStatus::Masking(addr) => vec![addr.clone()],
649            RandomStatus::WaitingSecrets => self
650                .secret_shares
651                .iter()
652                .filter(|s| s.secret.is_none())
653                .map(|s| s.from_addr.to_owned())
654                .collect(),
655        }
656    }
657
658    /// Update randomness status
659    pub fn update_status(&mut self) {
660        if matches!(self.status, RandomStatus::Locking(_))
661            && self.masks.iter().all(|m| m.is_removed())
662        {
663            // This is for Locking -> Ready
664            self.status = RandomStatus::Ready;
665        } else if let Some(mask) = self.masks.iter().find(|m| m.is_required()) {
666            self.status = RandomStatus::Masking(mask.owner.clone());
667        } else if let Some(mask) = self.masks.iter().find(|m| m.is_applied()) {
668            self.status = RandomStatus::Locking(mask.owner.clone());
669        } else if self.secret_shares.iter().any(|s| s.secret.is_none()) {
670            self.status = RandomStatus::WaitingSecrets;
671        } else {
672            self.status = RandomStatus::Shared;
673        }
674    }
675}
676
677#[cfg(test)]
678mod tests {
679
680    use super::*;
681
682    #[test]
683    fn test_list_required_secrets() -> Result<()> {
684        let random = RandomSpec::shuffled_list(vec!["a".into(), "b".into(), "c".into()]);
685        let mut state = RandomState::try_new(0, random, &["alice".into(), "bob".into()])?;
686        state.mask("alice", vec![vec![1], vec![2], vec![3]])?;
687        state.mask("bob", vec![vec![1], vec![2], vec![3]])?;
688        state.lock(
689            "alice",
690            vec![(vec![1], vec![1]), (vec![2], vec![2]), (vec![3], vec![3])],
691        )?;
692        state.lock(
693            "bob",
694            vec![(vec![1], vec![1]), (vec![2], vec![2]), (vec![3], vec![3])],
695        )?;
696        state.reveal(vec![0])?;
697        assert_eq!(1, state.list_required_secrets_by_from_addr("alice").len());
698        assert_eq!(1, state.list_required_secrets_by_from_addr("bob").len());
699        state.add_secret("alice".into(), None, 0, vec![1, 2, 3])?;
700        // duplicated reveal
701        state.reveal(vec![0])?;
702        assert_eq!(0, state.list_required_secrets_by_from_addr("alice").len());
703        assert_eq!(1, state.list_required_secrets_by_from_addr("bob").len());
704        state.add_secret("bob".into(), None, 0, vec![1, 2, 3])?;
705        assert_eq!(0, state.list_required_secrets_by_from_addr("alice").len());
706        assert_eq!(0, state.list_required_secrets_by_from_addr("bob").len());
707        assert_eq!(RandomStatus::Shared, state.status);
708        Ok(())
709    }
710
711    #[test]
712    fn test_new_random_spec() -> Result<()> {
713        let random = RandomSpec::shuffled_list(vec!["a".into(), "b".into(), "c".into()]);
714        let state =
715            RandomState::try_new(0, random, &["alice".into(), "bob".into(), "charlie".into()])?;
716        assert_eq!(3, state.masks.len());
717        Ok(())
718    }
719
720    #[test]
721    fn test_mask_serialize() {
722        let mask = Mask::new("hello");
723        let encoded = mask.try_to_vec().unwrap();
724        let decoded = Mask::try_from_slice(&encoded).unwrap();
725        assert_eq!(mask, decoded);
726    }
727
728    #[test]
729    fn test_mask() -> Result<()> {
730        let random = RandomSpec::shuffled_list(vec!["a".into(), "b".into(), "c".into()]);
731        let mut state = RandomState::try_new(0, random, &["alice".into(), "bob".into()])?;
732        assert_eq!(RandomStatus::Masking("alice".into()), state.status);
733        state
734            .mask("alice", vec![vec![1], vec![2], vec![3]])
735            .expect("failed to mask");
736
737        assert_eq!(RandomStatus::Masking("bob".into()), state.status);
738        assert_eq!(false, state.is_fully_masked());
739        state
740            .mask("bob", vec![vec![1], vec![2], vec![3]])
741            .expect("failed to mask");
742        assert_eq!(RandomStatus::Locking("alice".into()), state.status);
743        assert_eq!(true, state.is_fully_masked());
744        Ok(())
745    }
746
747    #[test]
748    fn test_add_secret_share() -> Result<()> {
749        let random = RandomSpec::shuffled_list(vec!["a".into(), "b".into(), "c".into()]);
750        let mut state = RandomState::try_new(0, random, &["alice".into(), "bob".into()])?;
751        let share1 = Share {
752            from_addr: "alice".into(),
753            to_addr: None,
754            index: 0,
755            secret: None,
756        };
757        let share2 = Share {
758            from_addr: "alice".into(),
759            to_addr: None,
760            index: 0,
761            secret: Some(vec![1]),
762        };
763        state.add_secret_share(share1);
764        state.add_secret_share(share2);
765        assert_eq!(state.secret_shares.len(), 1);
766        Ok(())
767    }
768
769    #[test]
770    fn test_lock() -> Result<()> {
771        let random = RandomSpec::shuffled_list(vec!["a".into(), "b".into(), "c".into()]);
772        let mut state = RandomState::try_new(0, random, &["alice".into(), "bob".into()])?;
773        state
774            .mask("alice", vec![vec![1], vec![2], vec![3]])
775            .expect("failed to mask");
776        state
777            .lock(
778                "alice",
779                vec![(vec![1], vec![1]), (vec![2], vec![2]), (vec![3], vec![3])],
780            )
781            .expect_err("should failed to lock");
782        state
783            .mask("bob", vec![vec![1], vec![2], vec![3]])
784            .expect("failed to mask");
785        assert_eq!(RandomStatus::Locking("alice".into()), state.status);
786        state
787            .lock(
788                "alice",
789                vec![(vec![1], vec![1]), (vec![2], vec![2]), (vec![3], vec![3])],
790            )
791            .expect("failed to lock");
792        assert_eq!(RandomStatus::Locking("bob".into()), state.status);
793        assert_eq!(false, state.is_fully_locked());
794        state
795            .lock(
796                "bob",
797                vec![(vec![1], vec![1]), (vec![2], vec![2]), (vec![3], vec![3])],
798            )
799            .expect("failed to lock");
800        assert_eq!(RandomStatus::Ready, state.status);
801        assert_eq!(true, state.is_fully_locked());
802        Ok(())
803    }
804}