fedimint_core/encoding/
threshold_crypto.rs

1use std::io::{Error, Read, Write};
2
3use threshold_crypto::group::Curve;
4use threshold_crypto::{G1Affine, G1Projective};
5
6use crate::encoding::{Decodable, DecodeError, Encodable};
7use crate::module::registry::ModuleDecoderRegistry;
8
9impl Encodable for threshold_crypto::PublicKeySet {
10    fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
11        let mut len = 0;
12        let num_coeff = self.coefficients().len() as u64;
13        len += num_coeff.consensus_encode(writer)?;
14        for coefficient in self.coefficients() {
15            len += coefficient
16                .to_affine()
17                .to_compressed()
18                .consensus_encode(writer)?;
19        }
20        Ok(len)
21    }
22}
23
24impl Decodable for threshold_crypto::PublicKeySet {
25    fn consensus_decode<R: Read>(
26        r: &mut R,
27        modules: &ModuleDecoderRegistry,
28    ) -> Result<Self, DecodeError> {
29        let num_coeff = u64::consensus_decode(r, modules)?;
30        (0..num_coeff)
31            .map(|_| {
32                let bytes: [u8; 48] = Decodable::consensus_decode(r, modules)?;
33                let point = G1Affine::from_compressed(&bytes);
34                if point.is_some().unwrap_u8() == 1 {
35                    let affine = point.unwrap();
36                    Ok(G1Projective::from(affine))
37                } else {
38                    Err(crate::encoding::DecodeError::from_str(
39                        "Error decoding public key",
40                    ))
41                }
42            })
43            .collect::<Result<Vec<_>, _>>()
44            .map(|coefficients| Self::from(threshold_crypto::poly::Commitment::from(coefficients)))
45    }
46}
47
48impl Encodable for threshold_crypto::PublicKey {
49    fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
50        self.to_bytes().consensus_encode(writer)
51    }
52}
53
54impl Decodable for threshold_crypto::PublicKey {
55    fn consensus_decode<R: Read>(
56        r: &mut R,
57        modules: &ModuleDecoderRegistry,
58    ) -> Result<Self, DecodeError> {
59        let bytes: [u8; 48] = Decodable::consensus_decode(r, modules)?;
60        Self::from_bytes(bytes).map_err(DecodeError::from_err)
61    }
62}
63
64impl Encodable for threshold_crypto::Ciphertext {
65    fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
66        self.to_bytes().consensus_encode(writer)
67    }
68}
69
70impl Decodable for threshold_crypto::Ciphertext {
71    fn consensus_decode<R: Read>(
72        reader: &mut R,
73        modules: &ModuleDecoderRegistry,
74    ) -> Result<Self, DecodeError> {
75        let ciphertext_bytes = Vec::<u8>::consensus_decode(reader, modules)?;
76        Self::from_bytes(&ciphertext_bytes).ok_or_else(|| {
77            DecodeError::from_str("Error decoding threshold_crypto::Ciphertext from bytes")
78        })
79    }
80}
81
82impl Encodable for threshold_crypto::DecryptionShare {
83    fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
84        self.to_bytes().consensus_encode(writer)
85    }
86}
87
88impl Decodable for threshold_crypto::DecryptionShare {
89    fn consensus_decode<R: Read>(
90        reader: &mut R,
91        modules: &ModuleDecoderRegistry,
92    ) -> Result<Self, DecodeError> {
93        let decryption_share_bytes = <[u8; 48]>::consensus_decode(reader, modules)?;
94        Self::from_bytes(&decryption_share_bytes).ok_or_else(|| {
95            DecodeError::from_str("Error decoding threshold_crypto::DecryptionShare from bytes")
96        })
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::super::tests::test_roundtrip;
103
104    #[test_log::test]
105    fn test_ciphertext() {
106        let sks = threshold_crypto::SecretKeySet::random(1, &mut rand::thread_rng());
107        let pks = sks.public_keys();
108        let pk = pks.public_key();
109
110        let message = b"Hello world!";
111        let ciphertext = pk.encrypt(message);
112        let decryption_share = sks.secret_key_share(0).decrypt_share(&ciphertext).unwrap();
113
114        test_roundtrip(&ciphertext);
115        test_roundtrip(&decryption_share);
116    }
117}