1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use commit::Commit;
use errors::*;

use crypto_mac::generic_array::GenericArray;
use crypto_mac::Mac;

use bincode;

use rand::{CryptoRng, Rng};

use serde::Serialize;

use typenum::Unsigned;

/// An individual participant's contribution to a randomly generated number.
#[derive(Debug)]
pub struct Secret<T, M>
where
    M: Mac,
{
    value: T,
    key: GenericArray<u8, M::KeySize>,
}

impl<T, M> Secret<T, M>
where
    M: Mac,
{
    /// Returns a new secret with the given `value` and a randomly generated
    /// salt.
    pub fn new<R>(rng: &mut R, value: T) -> Self
    where
        R: Rng + CryptoRng,
    {
        let mut key = vec![0; M::KeySize::to_usize()];

        rng.fill_bytes(&mut key);

        Self {
            value,
            key: GenericArray::from_exact_iter(key).unwrap(),
        }
    }
}

impl<T, M> Secret<T, M>
where
    M: Mac,
    T: Serialize,
{
    /// Create a new `Commit` that can be used to validate a Secret during the
    /// reveal phase.
    pub fn commit(&self) -> Result<Commit<T, M>> {
        let bytes = bincode::serialize(&self.value)
            .map_err(|e| Error::with_chain(e, ErrorKind::Serialize))?;

        Ok(Commit::new(&self.key, &bytes))
    }

    pub(crate) fn validate(self, commit: Commit<T, M>) -> Result<T> {
        let mine = self.commit()?.into_mac();
        let other = commit.into_mac();

        if mine == other {
            Ok(self.value)
        } else {
            bail!("validation failed");
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate hmac;
    extern crate sha2;

    use self::hmac::Hmac;
    use self::sha2::Sha512;

    use super::*;

    use rand::thread_rng;

    #[test]
    fn new() {
        let mut rng = thread_rng();

        let s: Secret<u32, Hmac<Sha512>> = Secret::new(&mut rng, 4);

        assert_eq!(s.value, 4);
        assert_eq!(s.key.len(), 128);
    }
}