bc_components/
public_keys.rs

1use anyhow::{ bail, Error, Result };
2use bc_ur::prelude::*;
3use crate::{
4    tags,
5    Digest,
6    EncapsulationPublicKey,
7    Encrypter,
8    Reference,
9    ReferenceProvider,
10    Signature,
11    SigningPublicKey,
12    Verifier,
13};
14
15/// A container for an entity's public cryptographic keys.
16///
17/// `PublicKeys` combines a verification key for checking digital signatures with an
18/// encapsulation key for encrypting messages, providing a complete public key
19/// package for secure communication with an entity.
20///
21/// This type is designed to be freely shared across networks and systems, allowing
22/// others to securely communicate with the key owner, who holds the corresponding
23/// `PrivateKeys` instance.
24///
25/// # Components
26///
27/// * `signing_public_key` - A public key used for verifying digital signatures.
28///   Can verify signatures created by the corresponding private key, which may be
29///   Schnorr, ECDSA, Ed25519, or SSH-based.
30///
31/// * `encapsulation_public_key` - A public key used for encrypting messages that
32///   can only be decrypted by the holder of the corresponding private key.
33///   Can be X25519 or ML-KEM based.
34///
35/// # Use Cases
36///
37/// * Verifying the authenticity of signed messages or content
38/// * Encrypting data for secure transmission to the key owner
39/// * Identity verification in distributed systems
40/// * Establishing secure communication channels
41///
42/// # Examples
43///
44/// ```
45/// use bc_components::{keypair, EncapsulationPublicKey};
46///
47/// // Generate a key pair
48/// let (private_keys, public_keys) = keypair();
49///
50/// // Get the encapsulation public key
51/// let enc_pub_key = public_keys.enapsulation_public_key();
52///
53/// // The public key can be used for key encapsulation
54/// // The resulting shared secret is only accessible to the 
55/// // holder of the corresponding private key
56/// ```
57#[derive(Clone, PartialEq, Eq, Debug, Hash)]
58pub struct PublicKeys {
59    signing_public_key: SigningPublicKey,
60    encapsulation_public_key: EncapsulationPublicKey,
61}
62
63impl PublicKeys {
64    /// Restores a `PublicKeys` from a `SigningPublicKey` and an `EncapsulationPublicKey`.
65    pub fn new(
66        signing_public_key: SigningPublicKey,
67        encapsulation_public_key: EncapsulationPublicKey
68    ) -> Self {
69        Self {
70            signing_public_key,
71            encapsulation_public_key,
72        }
73    }
74
75    /// Returns the `SigningPublicKey` of this `PublicKeys`.
76    pub fn signing_public_key(&self) -> &SigningPublicKey {
77        &self.signing_public_key
78    }
79
80    /// Returns the `EncapsulationPublicKey` of this `PublicKeys`.
81    pub fn enapsulation_public_key(&self) -> &EncapsulationPublicKey {
82        &self.encapsulation_public_key
83    }
84}
85
86/// A trait for types that can provide a complete set of public cryptographic keys.
87///
88/// Types implementing this trait can be used as a source of `PublicKeys`,
89/// which contain both verification and encryption public keys. This trait is
90/// particularly useful for key management systems, wallets, identity systems,
91/// or any component that needs to provide public keys for cryptographic operations.
92///
93/// # Examples
94///
95/// ```
96/// use bc_components::{PrivateKeyBase, PublicKeysProvider};
97///
98/// // Create a provider of public keys (in this case, a private key base
99/// // that can derive the corresponding public keys)
100/// let key_base = PrivateKeyBase::new();
101///
102/// // Get the public keys from the provider
103/// let public_keys = key_base.public_keys();
104/// 
105/// // These public keys can be shared with others for secure communication
106/// ```
107pub trait PublicKeysProvider {
108    /// Returns a complete set of public keys for cryptographic operations.
109    ///
110    /// The returned `PublicKeys` instance contains both verification and encryption
111    /// public keys that can be used by other parties to securely communicate with
112    /// the key owner.
113    ///
114    /// # Returns
115    ///
116    /// A `PublicKeys` instance containing the complete set of public keys.
117    fn public_keys(&self) -> PublicKeys;
118}
119
120impl PublicKeysProvider for PublicKeys {
121    fn public_keys(&self) -> PublicKeys {
122        self.clone()
123    }
124}
125
126impl ReferenceProvider for PublicKeys {
127    fn reference(&self) -> Reference {
128        Reference::from_digest(Digest::from_image(self.tagged_cbor().to_cbor_data()))
129    }
130}
131
132impl AsRef<PublicKeys> for PublicKeys {
133    fn as_ref(&self) -> &PublicKeys {
134        self
135    }
136}
137
138impl AsRef<SigningPublicKey> for PublicKeys {
139    fn as_ref(&self) -> &SigningPublicKey {
140        &self.signing_public_key
141    }
142}
143
144impl AsRef<EncapsulationPublicKey> for PublicKeys {
145    fn as_ref(&self) -> &EncapsulationPublicKey {
146        &self.encapsulation_public_key
147    }
148}
149
150impl CBORTagged for PublicKeys {
151    fn cbor_tags() -> Vec<Tag> {
152        tags_for_values(&[tags::TAG_PUBLIC_KEYS])
153    }
154}
155
156impl From<PublicKeys> for CBOR {
157    fn from(value: PublicKeys) -> Self {
158        value.tagged_cbor()
159    }
160}
161
162impl CBORTaggedEncodable for PublicKeys {
163    fn untagged_cbor(&self) -> CBOR {
164        let signing_key_cbor: CBOR = self.signing_public_key.clone().into();
165        let encapsulation_key_cbor: CBOR = self.encapsulation_public_key.clone().into();
166        vec![signing_key_cbor, encapsulation_key_cbor].into()
167    }
168}
169
170impl TryFrom<CBOR> for PublicKeys {
171    type Error = Error;
172
173    fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
174        Self::from_tagged_cbor(cbor)
175    }
176}
177
178impl CBORTaggedDecodable for PublicKeys {
179    fn from_untagged_cbor(untagged_cbor: CBOR) -> Result<Self> {
180        match untagged_cbor.as_case() {
181            CBORCase::Array(elements) => {
182                if elements.len() != 2 {
183                    bail!("PublicKeys must have two elements");
184                }
185
186                let signing_public_key = SigningPublicKey::try_from(elements[0].clone())?;
187                let encapsulation_public_key = EncapsulationPublicKey::try_from(
188                    elements[1].clone()
189                )?;
190                Ok(Self::new(signing_public_key, encapsulation_public_key))
191            }
192            _ => bail!("PublicKeys must be an array"),
193        }
194    }
195}
196
197impl Verifier for PublicKeys {
198    fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
199        self.signing_public_key.verify(signature, message)
200    }
201}
202
203impl Encrypter for PublicKeys {
204    fn encapsulation_public_key(&self) -> EncapsulationPublicKey {
205        self.encapsulation_public_key.clone()
206    }
207}
208
209impl std::fmt::Display for PublicKeys {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        write!(f, "PublicKeys({})", self.reference().ref_hex_short())
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use bc_ur::{ UREncodable, URDecodable };
218    use hex_literal::hex;
219    use dcbor::prelude::*;
220
221    use crate::{ PrivateKeyBase, PublicKeys, PublicKeysProvider, ReferenceProvider };
222
223    const SEED: [u8; 16] = hex!("59f2293a5bce7d4de59e71b4207ac5d2");
224
225    #[test]
226    fn test_private_key_base() {
227        crate::register_tags();
228        let private_key_base = PrivateKeyBase::from_data(SEED);
229        let public_keys = private_key_base.public_keys();
230
231        let cbor = CBOR::from(public_keys.clone());
232
233        let public_keys_2 = PublicKeys::try_from(cbor.clone()).unwrap();
234        assert_eq!(public_keys, public_keys_2);
235
236        let cbor_2 = CBOR::from(public_keys_2);
237        assert_eq!(cbor, cbor_2);
238
239        let ur = public_keys.ur_string();
240        assert_eq!(
241            ur,
242            "ur:crypto-pubkeys/lftanshfhdcxzcgtcpytvsgafsondpjkbkoxaopsnniycawpnbnlwsgtregdfhgynyjksrgafmcstansgrhdcxlnfnwfzstovlrdfeuoghvwwyuesbcltsmetbgeurpfoyswfrzojlwdenjzckvadnrndtgsya"
243        );
244        assert_eq!(PublicKeys::from_ur_string(&ur).unwrap(), public_keys);
245
246        assert_eq!(format!("{}", public_keys), "PublicKeys(c9ede672)");
247        assert_eq!(format!("{}", public_keys.reference()), "Reference(c9ede672)");
248    }
249}