bc_components/
public_keys.rs1use bc_ur::prelude::*;
2
3use crate::{
4 Digest, EncapsulationPublicKey, Encrypter, Reference, ReferenceProvider,
5 Signature, SigningPublicKey, Verifier, tags,
6};
7
8#[derive(Clone, PartialEq, Eq, Debug, Hash)]
51pub struct PublicKeys {
52 signing_public_key: SigningPublicKey,
53 encapsulation_public_key: EncapsulationPublicKey,
54}
55
56impl PublicKeys {
57 pub fn new(
60 signing_public_key: SigningPublicKey,
61 encapsulation_public_key: EncapsulationPublicKey,
62 ) -> Self {
63 Self { signing_public_key, encapsulation_public_key }
64 }
65
66 pub fn signing_public_key(&self) -> &SigningPublicKey {
68 &self.signing_public_key
69 }
70
71 pub fn enapsulation_public_key(&self) -> &EncapsulationPublicKey {
73 &self.encapsulation_public_key
74 }
75}
76
77pub trait PublicKeysProvider {
102 fn public_keys(&self) -> PublicKeys;
112}
113
114impl PublicKeysProvider for PublicKeys {
115 fn public_keys(&self) -> PublicKeys { self.clone() }
116}
117
118impl ReferenceProvider for PublicKeys {
119 fn reference(&self) -> Reference {
120 Reference::from_digest(Digest::from_image(
121 self.tagged_cbor().to_cbor_data(),
122 ))
123 }
124}
125
126impl AsRef<PublicKeys> for PublicKeys {
127 fn as_ref(&self) -> &PublicKeys { self }
128}
129
130impl AsRef<SigningPublicKey> for PublicKeys {
131 fn as_ref(&self) -> &SigningPublicKey { &self.signing_public_key }
132}
133
134impl AsRef<EncapsulationPublicKey> for PublicKeys {
135 fn as_ref(&self) -> &EncapsulationPublicKey {
136 &self.encapsulation_public_key
137 }
138}
139
140impl CBORTagged for PublicKeys {
141 fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_PUBLIC_KEYS]) }
142}
143
144impl From<PublicKeys> for CBOR {
145 fn from(value: PublicKeys) -> Self { value.tagged_cbor() }
146}
147
148impl CBORTaggedEncodable for PublicKeys {
149 fn untagged_cbor(&self) -> CBOR {
150 #[cfg(any(
151 feature = "secp256k1",
152 feature = "ed25519",
153 feature = "ssh",
154 feature = "pqcrypto"
155 ))]
156 {
157 let _signing_key_cbor: CBOR =
158 self.signing_public_key.clone().into();
159 let _encapsulation_key_cbor: CBOR =
160 self.encapsulation_public_key.clone().into();
161 vec![_signing_key_cbor, _encapsulation_key_cbor].into()
162 }
163 #[cfg(not(any(
164 feature = "secp256k1",
165 feature = "ed25519",
166 feature = "ssh",
167 feature = "pqcrypto"
168 )))]
169 {
170 match self.signing_public_key {}
171 }
172 }
173}
174
175impl TryFrom<CBOR> for PublicKeys {
176 type Error = dcbor::Error;
177
178 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
179 Self::from_tagged_cbor(cbor)
180 }
181}
182
183impl CBORTaggedDecodable for PublicKeys {
184 fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
185 match untagged_cbor.as_case() {
186 CBORCase::Array(elements) => {
187 if elements.len() != 2 {
188 return Err("PublicKeys must have two elements".into());
189 }
190
191 let signing_public_key =
192 SigningPublicKey::try_from(elements[0].clone())?;
193 let encapsulation_public_key =
194 EncapsulationPublicKey::try_from(elements[1].clone())?;
195 Ok(Self::new(signing_public_key, encapsulation_public_key))
196 }
197 _ => Err("PublicKeys must be an array".into()),
198 }
199 }
200}
201
202impl Verifier for PublicKeys {
203 fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
204 self.signing_public_key.verify(signature, message)
205 }
206}
207
208impl Encrypter for PublicKeys {
209 fn encapsulation_public_key(&self) -> EncapsulationPublicKey {
210 self.encapsulation_public_key.clone()
211 }
212}
213
214impl std::fmt::Display for PublicKeys {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 write!(
217 f,
218 "PublicKeys({}, {}, {})",
219 self.reference().ref_hex_short(),
220 self.signing_public_key,
221 self.encapsulation_public_key
222 )
223 }
224}
225
226#[cfg(test)]
227#[cfg(feature = "secp256k1")]
228mod tests {
229 use bc_ur::{URDecodable, UREncodable};
230 use dcbor::prelude::*;
231 use hex_literal::hex;
232
233 use crate::{
234 PrivateKeyBase, PublicKeys, PublicKeysProvider, ReferenceProvider,
235 };
236
237 const SEED: [u8; 16] = hex!("59f2293a5bce7d4de59e71b4207ac5d2");
238
239 #[test]
240 #[cfg(feature = "secp256k1")]
241 fn test_private_key_base() {
242 crate::register_tags();
243 let private_key_base = PrivateKeyBase::from_data(SEED);
244 let public_keys = private_key_base.public_keys();
245
246 let cbor = CBOR::from(public_keys.clone());
247
248 let public_keys_2 = PublicKeys::try_from(cbor.clone()).unwrap();
249 assert_eq!(public_keys, public_keys_2);
250
251 let cbor_2 = CBOR::from(public_keys_2);
252 assert_eq!(cbor, cbor_2);
253
254 let ur = public_keys.ur_string();
255 assert_eq!(
256 ur,
257 "ur:crypto-pubkeys/lftanshfhdcxzcgtcpytvsgafsondpjkbkoxaopsnniycawpnbnlwsgtregdfhgynyjksrgafmcstansgrhdcxlnfnwfzstovlrdfeuoghvwwyuesbcltsmetbgeurpfoyswfrzojlwdenjzckvadnrndtgsya"
258 );
259 assert_eq!(PublicKeys::from_ur_string(&ur).unwrap(), public_keys);
260
261 assert_eq!(
262 format!("{}", public_keys),
263 "PublicKeys(c9ede672, SigningPublicKey(7efa2ea1, SchnorrPublicKey(b4df96ce)), EncapsulationPublicKey(bacae62f, X25519PublicKey(bacae62f)))"
264 );
265 assert_eq!(
266 format!("{}", public_keys.reference()),
267 "Reference(c9ede672)"
268 );
269 }
270}