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