bc_components/
public_keys.rs

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