1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Traits defining credential books. These are used in the deserialization path to provide
16 //! the credentials to try for either advertisement version.
17 //! See [`CredentialBookBuilder`] for batteries-included implementations.
18 
19 use crate::credential::{
20     source::{CredentialSource, SliceCredentialSource},
21     v0::{V0DiscoveryCryptoMaterial, V0},
22     v1::{
23         MicExtendedSaltSectionIdentityResolutionMaterial,
24         MicExtendedSaltSectionVerificationMaterial, MicShortSaltSectionIdentityResolutionMaterial,
25         MicShortSaltSectionVerificationMaterial, SignedSectionIdentityResolutionMaterial,
26         SignedSectionVerificationMaterial, V1DiscoveryCryptoMaterial, V1,
27     },
28     DiscoveryMetadataCryptoMaterial, MatchableCredential, MatchedCredential, ProtocolVersion,
29 };
30 use core::{borrow::Borrow, marker::PhantomData};
31 use crypto_provider::CryptoProvider;
32 
33 #[cfg(any(feature = "alloc", test))]
34 extern crate alloc;
35 #[cfg(any(feature = "alloc", test))]
36 use crate::credential::ReferencedMatchedCredential;
37 #[cfg(any(feature = "alloc", test))]
38 use alloc::vec::Vec;
39 
40 /// A collection of credentials to try when attempting to deserialize
41 /// advertisements of either advertisement version which is
42 /// valid for the given lifetime.
43 pub trait CredentialBook<'a>
44 where
45     Self: 'a,
46 {
47     /// The type of the matched credentials for the credentials
48     /// held within this credential-book. May lend from the credential-book.
49     type Matched: MatchedCredential;
50 
51     /// The type of V0 crypto-materials yielded by this credential-book.
52     type V0Crypto: V0DiscoveryCryptoMaterial;
53 
54     /// The type of V1 crypto-materials yielded by this credential-book.
55     type V1Crypto: V1DiscoveryCryptoMaterial;
56 
57     /// The iterator type returned from [`CredentialBook#v0_iter()`],
58     /// which yields `(crypto-material, match_data)` pairs.
59     /// This is a lending iterator which may borrow things from `self`.
60     type V0Iterator: Iterator<Item = (Self::V0Crypto, Self::Matched)>;
61 
62     /// The iterator type returned from [`CredentialBook#v1_iter()`],
63     /// which yields `(crypto-material, match_data)` pairs.
64     /// This is a lending iterator which may borrow things from `self`.
65     type V1Iterator: Iterator<Item = (Self::V1Crypto, Self::Matched)>;
66 
67     /// Returns an iterator over V0 credentials in this credential book.
v0_iter(&'a self) -> Self::V0Iterator68     fn v0_iter(&'a self) -> Self::V0Iterator;
69 
70     /// Returns an iterator over V1 credentials in this credential book.
v1_iter(&'a self) -> Self::V1Iterator71     fn v1_iter(&'a self) -> Self::V1Iterator;
72 }
73 
74 /// Convenient marker struct for building credential-books with
75 /// some given match-data type.
76 pub struct CredentialBookBuilder<M: MatchedCredential> {
77     _marker: PhantomData<M>,
78 }
79 
80 impl<M: MatchedCredential> CredentialBookBuilder<M> {
81     /// Constructs a [`CachedSliceCredentialBook`] from the given slices of discovery credentials,
82     /// populating its internal buffers of cached credential crypto-materials for up to the
83     /// given number of credentials in each version (up to `N0` credentials cached in V0,
84     /// and up to `N1` credentials cached in `V1`.)
build_cached_slice_book<'a, const N0: usize, const N1: usize, P: CryptoProvider>( v0_creds: &'a [MatchableCredential<V0, M>], v1_creds: &'a [MatchableCredential<V1, M>], ) -> CachedSliceCredentialBook<'a, M, N0, N1>85     pub fn build_cached_slice_book<'a, const N0: usize, const N1: usize, P: CryptoProvider>(
86         v0_creds: &'a [MatchableCredential<V0, M>],
87         v1_creds: &'a [MatchableCredential<V1, M>],
88     ) -> CachedSliceCredentialBook<'a, M, N0, N1> {
89         let v0_source = SliceCredentialSource::new(v0_creds);
90         let v0_cache = init_cache_from_source::<V0, _, N0, P>(&v0_source);
91         let v0_source = CachedCredentialSource::<_, _, N0>::new(v0_source, v0_cache);
92 
93         let v1_source = SliceCredentialSource::new(v1_creds);
94         let v1_cache = init_cache_from_source::<V1, _, N1, P>(&v1_source);
95         let v1_source = CachedCredentialSource::<_, _, N1>::new(v1_source, v1_cache);
96 
97         CredentialBookFromSources::new(v0_source, v1_source)
98     }
99 
100     #[cfg(feature = "alloc")]
101     /// Constructs a new credential-book which owns all of the given credentials,
102     /// and maintains pre-calculated cryptographic information about them
103     /// for speedy advertisement deserialization.
build_precalculated_owned_book<P: CryptoProvider>( v0_iter: impl IntoIterator<Item = MatchableCredential<V0, M>>, v1_iter: impl IntoIterator<Item = MatchableCredential<V1, M>>, ) -> PrecalculatedOwnedCredentialBook<M>104     pub fn build_precalculated_owned_book<P: CryptoProvider>(
105         v0_iter: impl IntoIterator<Item = MatchableCredential<V0, M>>,
106         v1_iter: impl IntoIterator<Item = MatchableCredential<V1, M>>,
107     ) -> PrecalculatedOwnedCredentialBook<M> {
108         let v0_source = PrecalculatedOwnedCredentialSource::<V0, M>::new::<P>(v0_iter);
109         let v1_source = PrecalculatedOwnedCredentialSource::<V1, M>::new::<P>(v1_iter);
110         CredentialBookFromSources::new(v0_source, v1_source)
111     }
112 }
113 
114 // Now, for the implementation details. External implementors still need
115 // to be able to reference these types (since the returned types from
116 // [`CredentialBookBuilder`]'s convenience methods are just type-aliases),
117 // and if they want, they can use them as building-blocks to construct
118 // their own [`CredentialBook`]s, but they're largely just scaffolding.
119 
120 /// A structure bundling both V0 and V1 credential-sources to define
121 /// a credential-book which owns both of these independent sources.
122 pub struct CredentialBookFromSources<S0, S1> {
123     /// The source for V0 credentials.
124     v0_source: S0,
125     /// The source for V1 credentials.
126     v1_source: S1,
127 }
128 
129 impl<'a, S0, S1> CredentialBookFromSources<S0, S1>
130 where
131     Self: 'a,
132     S0: CredentialSource<'a, V0>,
133     S1: CredentialSource<'a, V1, Matched = <S0 as CredentialSource<'a, V0>>::Matched>,
134     <S0 as CredentialSource<'a, V0>>::Crypto: V0DiscoveryCryptoMaterial,
135     <S1 as CredentialSource<'a, V1>>::Crypto: V1DiscoveryCryptoMaterial,
136 {
137     /// Constructs a new [`CredentialBook`] out of the two given
138     /// credential-sources, one for v0 and one for v1. The match-data
139     /// of both credential sources must be the same.
new(v0_source: S0, v1_source: S1) -> Self140     pub fn new(v0_source: S0, v1_source: S1) -> Self {
141         Self { v0_source, v1_source }
142     }
143 }
144 
145 impl<'a, S0, S1> CredentialBook<'a> for CredentialBookFromSources<S0, S1>
146 where
147     Self: 'a,
148     S0: CredentialSource<'a, V0>,
149     S1: CredentialSource<'a, V1, Matched = <S0 as CredentialSource<'a, V0>>::Matched>,
150     <S0 as CredentialSource<'a, V0>>::Crypto: V0DiscoveryCryptoMaterial,
151     <S1 as CredentialSource<'a, V1>>::Crypto: V1DiscoveryCryptoMaterial,
152 {
153     type Matched = <S0 as CredentialSource<'a, V0>>::Matched;
154     type V0Crypto = <S0 as CredentialSource<'a, V0>>::Crypto;
155     type V1Crypto = <S1 as CredentialSource<'a, V1>>::Crypto;
156     type V0Iterator = <S0 as CredentialSource<'a, V0>>::Iterator;
157     type V1Iterator = <S1 as CredentialSource<'a, V1>>::Iterator;
158 
v0_iter(&'a self) -> Self::V0Iterator159     fn v0_iter(&'a self) -> Self::V0Iterator {
160         self.v0_source.iter()
161     }
v1_iter(&'a self) -> Self::V1Iterator162     fn v1_iter(&'a self) -> Self::V1Iterator {
163         self.v1_source.iter()
164     }
165 }
166 
167 /// Type-level function used internally
168 /// by [`CachedCredentialSource`] in order to uniformly
169 /// refer to the "precalculated" crypto-material variants
170 /// for each protocol version.
171 pub(crate) mod precalculated_for_version {
172     use crate::credential::{
173         v0::{PrecalculatedV0DiscoveryCryptoMaterial, V0DiscoveryCredential, V0},
174         v1::{PrecalculatedV1DiscoveryCryptoMaterial, V1DiscoveryCredential, V1},
175         DiscoveryMetadataCryptoMaterial, ProtocolVersion,
176     };
177     use crypto_provider::CryptoProvider;
178 
179     pub trait MappingTrait<V: ProtocolVersion> {
180         type Output: DiscoveryMetadataCryptoMaterial<V>;
181         /// Provides pre-calculated crypto-material for the given
182         /// discovery credential.
precalculate<C: CryptoProvider>( discovery_credential: &V::DiscoveryCredential, ) -> Self::Output183         fn precalculate<C: CryptoProvider>(
184             discovery_credential: &V::DiscoveryCredential,
185         ) -> Self::Output;
186     }
187     pub enum Marker {}
188     impl MappingTrait<V0> for Marker {
189         type Output = PrecalculatedV0DiscoveryCryptoMaterial;
precalculate<C: CryptoProvider>( discovery_credential: &V0DiscoveryCredential, ) -> PrecalculatedV0DiscoveryCryptoMaterial190         fn precalculate<C: CryptoProvider>(
191             discovery_credential: &V0DiscoveryCredential,
192         ) -> PrecalculatedV0DiscoveryCryptoMaterial {
193             PrecalculatedV0DiscoveryCryptoMaterial::new::<C>(discovery_credential)
194         }
195     }
196     impl MappingTrait<V1> for Marker {
197         type Output = PrecalculatedV1DiscoveryCryptoMaterial;
precalculate<C: CryptoProvider>( discovery_credential: &V1DiscoveryCredential, ) -> PrecalculatedV1DiscoveryCryptoMaterial198         fn precalculate<C: CryptoProvider>(
199             discovery_credential: &V1DiscoveryCredential,
200         ) -> PrecalculatedV1DiscoveryCryptoMaterial {
201             discovery_credential.to_precalculated::<C>()
202         }
203     }
204 }
205 
206 type PrecalculatedCryptoForProtocolVersion<V> =
207     <precalculated_for_version::Marker as precalculated_for_version::MappingTrait<V>>::Output;
208 
precalculate_crypto_material<V: ProtocolVersion, C: CryptoProvider>( discovery_credential: &V::DiscoveryCredential, ) -> PrecalculatedCryptoForProtocolVersion<V> where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,209 fn precalculate_crypto_material<V: ProtocolVersion, C: CryptoProvider>(
210     discovery_credential: &V::DiscoveryCredential,
211 ) -> PrecalculatedCryptoForProtocolVersion<V>
212 where
213     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
214 {
215     <precalculated_for_version::Marker as precalculated_for_version::MappingTrait<V>>::precalculate::<
216         C,
217     >(discovery_credential)
218 }
219 
220 /// Iterator type for [`CachedCredentialSource`].
221 pub struct CachedCredentialSourceIterator<'a, V, S, const N: usize>
222 where
223     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
224     V: ProtocolVersion + 'a,
225     S: CredentialSource<'a, V> + 'a,
226     S::Crypto: Borrow<V::DiscoveryCredential>,
227 {
228     /// The current index of the (enumerated) elements that we're iterating over.
229     /// Always counts up at every iteration, and may lie outside of the range
230     /// of the `cache` slice for uncached elements.
231     current_index: usize,
232     /// The cache of pre-calculated crypto-materials from the original source.
233     ///
234     /// The [`self.source_iterator`]'s (up-to) first `N` elements
235     /// must match (up-to) the first `N` elements in the cache,
236     /// and they must both appear in the same order.
237     cache: &'a [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
238     /// The iterator over the credentials in the original source
239     source_iterator: S::Iterator,
240 }
241 
242 impl<'a, V, S, const N: usize> Iterator for CachedCredentialSourceIterator<'a, V, S, N>
243 where
244     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
245     V: ProtocolVersion + 'a,
246     S: CredentialSource<'a, V> + 'a,
247     S::Crypto: Borrow<V::DiscoveryCredential>,
248 {
249     type Item = (PossiblyCachedDiscoveryCryptoMaterial<'a, V>, S::Matched);
next(&mut self) -> Option<Self::Item>250     fn next(&mut self) -> Option<Self::Item> {
251         // Regardless of what we're going to do with the crypto-materials, we still need
252         // to advance the underlying iterator, and bail if it runs out.
253         let (discovery_credential, match_data) = self.source_iterator.next()?;
254         // Check whether/not we have cached crypto-material for the current index
255         let crypto = match self.cache.get(self.current_index) {
256             Some(precalculated_crypto_entry) => {
257                 let precalculated_crypto = precalculated_crypto_entry
258                     .as_ref()
259                     .expect("iterator still going, but cache is not full?");
260                 PossiblyCachedDiscoveryCryptoMaterial::from_precalculated(precalculated_crypto)
261             }
262             None => PossiblyCachedDiscoveryCryptoMaterial::from_discovery_credential(
263                 discovery_credential.borrow().clone(),
264             ),
265         };
266         // Advance the index forward to point to the next item in the cache.
267         self.current_index += 1;
268         Some((crypto, match_data))
269     }
270 }
271 
272 /// A [`CredentialSource`] which augments the externally-provided [`CredentialSource`] with
273 /// a cache containing up to the specified number of pre-calculated credentials.
274 pub struct CachedCredentialSource<V: ProtocolVersion, S, const N: usize>
275 where
276     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
277 {
278     wrapped: S,
279     cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
280 }
281 
282 /// Helper function to construct a cache for a [`CachedCredentialSource`] from
283 /// a reference to some source of discovery-credentials.
284 ///
285 /// This function needs to be kept separate from [`CachedCredentialSource#new`]
286 /// to get around otherwise-tricky lifetime issues around ephemerally-borrowing
287 /// from a moved object within the body of a function.
init_cache_from_source<'a, V: ProtocolVersion, S, const N: usize, P: CryptoProvider>( original: &'a S, ) -> [Option<PrecalculatedCryptoForProtocolVersion<V>>; N] where S: CredentialSource<'a, V> + 'a, S::Crypto: Borrow<V::DiscoveryCredential>, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,288 pub(crate) fn init_cache_from_source<'a, V: ProtocolVersion, S, const N: usize, P: CryptoProvider>(
289     original: &'a S,
290 ) -> [Option<PrecalculatedCryptoForProtocolVersion<V>>; N]
291 where
292     S: CredentialSource<'a, V> + 'a,
293     S::Crypto: Borrow<V::DiscoveryCredential>,
294     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
295 {
296     let mut cache = [0u8; N].map(|_| None);
297     for (cache_entry, source_credential) in cache.iter_mut().zip(original.iter()) {
298         let (discovery_credential, _) = source_credential;
299         let precalculated_crypto_material =
300             precalculate_crypto_material::<V, P>(discovery_credential.borrow());
301         let _ = cache_entry.insert(precalculated_crypto_material);
302     }
303     cache
304 }
305 
306 impl<'a, V: ProtocolVersion, S, const N: usize> CachedCredentialSource<V, S, N>
307 where
308     S: CredentialSource<'a, V> + 'a,
309     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
310 {
311     /// Constructs a [`CachedCredentialSource`] from the given [`CredentialSource`]
312     /// and the given (initial) cache contents, as constructed via the
313     /// [`init_cache_from_source`] helper function.
new( wrapped: S, cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N], ) -> Self314     pub(crate) fn new(
315         wrapped: S,
316         cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
317     ) -> Self {
318         Self { wrapped, cache }
319     }
320 }
321 
322 /// Internal implementation of [`PossiblyCachedDiscoveryCryptoMaterial`] to hide
323 /// what crypto-material variants we're actually storing in cached
324 /// credential-books.
325 pub(crate) enum PossiblyCachedDiscoveryCryptoMaterialKind<'a, V: ProtocolVersion>
326 where
327     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
328 {
329     Discovery(V::DiscoveryCredential),
330     Precalculated(&'a PrecalculatedCryptoForProtocolVersion<V>),
331 }
332 
333 /// Crypto-materials that are potentially references to
334 /// already-cached precomputed variants, or raw discovery
335 /// credentials.
336 pub struct PossiblyCachedDiscoveryCryptoMaterial<'a, V: ProtocolVersion>
337 where
338     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
339 {
340     pub(crate) wrapped: PossiblyCachedDiscoveryCryptoMaterialKind<'a, V>,
341 }
342 
343 impl<'a, V: ProtocolVersion> PossiblyCachedDiscoveryCryptoMaterial<'a, V>
344 where
345     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
346 {
from_discovery_credential(discovery_credential: V::DiscoveryCredential) -> Self347     fn from_discovery_credential(discovery_credential: V::DiscoveryCredential) -> Self {
348         Self { wrapped: PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(discovery_credential) }
349     }
from_precalculated(precalculated: &'a PrecalculatedCryptoForProtocolVersion<V>) -> Self350     fn from_precalculated(precalculated: &'a PrecalculatedCryptoForProtocolVersion<V>) -> Self {
351         Self { wrapped: PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(precalculated) }
352     }
353 }
354 
355 impl<'a, V: ProtocolVersion> DiscoveryMetadataCryptoMaterial<V>
356     for PossiblyCachedDiscoveryCryptoMaterial<'a, V>
357 where
358     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
359 {
metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12]360     fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] {
361         match &self.wrapped {
362             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => x.metadata_nonce::<C>(),
363             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => x.metadata_nonce::<C>(),
364         }
365     }
366 }
367 
368 impl<'a> V0DiscoveryCryptoMaterial for PossiblyCachedDiscoveryCryptoMaterial<'a, V0> {
ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C>369     fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> {
370         match &self.wrapped {
371             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => x.ldt_adv_cipher::<C>(),
372             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => x.ldt_adv_cipher::<C>(),
373         }
374     }
375 }
376 
377 impl<'a> V1DiscoveryCryptoMaterial for PossiblyCachedDiscoveryCryptoMaterial<'a, V1> {
signed_identity_resolution_material<C: CryptoProvider>( &self, ) -> SignedSectionIdentityResolutionMaterial378     fn signed_identity_resolution_material<C: CryptoProvider>(
379         &self,
380     ) -> SignedSectionIdentityResolutionMaterial {
381         match &self.wrapped {
382             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
383                 x.signed_identity_resolution_material::<C>()
384             }
385             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
386                 x.signed_identity_resolution_material::<C>()
387             }
388         }
389     }
390 
mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, ) -> MicShortSaltSectionIdentityResolutionMaterial391     fn mic_short_salt_identity_resolution_material<C: CryptoProvider>(
392         &self,
393     ) -> MicShortSaltSectionIdentityResolutionMaterial {
394         match &self.wrapped {
395             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
396                 x.mic_short_salt_identity_resolution_material::<C>()
397             }
398             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
399                 x.mic_short_salt_identity_resolution_material::<C>()
400             }
401         }
402     }
403 
mic_extended_salt_identity_resolution_material<C: CryptoProvider>( &self, ) -> MicExtendedSaltSectionIdentityResolutionMaterial404     fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>(
405         &self,
406     ) -> MicExtendedSaltSectionIdentityResolutionMaterial {
407         match &self.wrapped {
408             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
409                 x.mic_extended_salt_identity_resolution_material::<C>()
410             }
411             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
412                 x.mic_extended_salt_identity_resolution_material::<C>()
413             }
414         }
415     }
416 
signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial417     fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial {
418         match &self.wrapped {
419             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
420                 x.signed_verification_material::<C>()
421             }
422             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
423                 x.signed_verification_material::<C>()
424             }
425         }
426     }
427 
mic_short_salt_verification_material<C: CryptoProvider>( &self, ) -> MicShortSaltSectionVerificationMaterial428     fn mic_short_salt_verification_material<C: CryptoProvider>(
429         &self,
430     ) -> MicShortSaltSectionVerificationMaterial {
431         match &self.wrapped {
432             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
433                 x.mic_short_salt_verification_material::<C>()
434             }
435             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
436                 x.mic_short_salt_verification_material::<C>()
437             }
438         }
439     }
440 
mic_extended_salt_verification_material<C: CryptoProvider>( &self, ) -> MicExtendedSaltSectionVerificationMaterial441     fn mic_extended_salt_verification_material<C: CryptoProvider>(
442         &self,
443     ) -> MicExtendedSaltSectionVerificationMaterial {
444         match &self.wrapped {
445             PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
446                 x.mic_extended_salt_verification_material::<C>()
447             }
448             PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
449                 x.mic_extended_salt_verification_material::<C>()
450             }
451         }
452     }
453 }
454 
455 impl<'a, V: ProtocolVersion, S, const N: usize> CredentialSource<'a, V>
456     for CachedCredentialSource<V, S, N>
457 where
458     Self: 'a,
459     S: CredentialSource<'a, V> + 'a,
460     S::Crypto: Borrow<V::DiscoveryCredential>,
461     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
462     PossiblyCachedDiscoveryCryptoMaterial<'a, V>: DiscoveryMetadataCryptoMaterial<V>,
463 {
464     type Matched = <S as CredentialSource<'a, V>>::Matched;
465     type Crypto = PossiblyCachedDiscoveryCryptoMaterial<'a, V>;
466     type Iterator = CachedCredentialSourceIterator<'a, V, S, N>;
467 
iter(&'a self) -> Self::Iterator468     fn iter(&'a self) -> Self::Iterator {
469         CachedCredentialSourceIterator {
470             current_index: 0,
471             cache: &self.cache,
472             source_iterator: self.wrapped.iter(),
473         }
474     }
475 }
476 
477 /// A simple credentials source for environments which are,
478 /// for all practical purposes, not space-constrained, and hence
479 /// can store an arbitrary amount of pre-calculated crypto-materials.
480 ///
481 /// Requires `alloc` as a result of internally leveraging a `Vec`.
482 #[cfg(any(feature = "alloc", test))]
483 pub struct PrecalculatedOwnedCredentialSource<V: ProtocolVersion, M: MatchedCredential>
484 where
485     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
486 {
487     credentials: Vec<(PrecalculatedCryptoForProtocolVersion<V>, M)>,
488 }
489 
490 #[cfg(any(feature = "alloc", test))]
491 impl<'a, V: ProtocolVersion + 'a, M: MatchedCredential + 'a>
492     PrecalculatedOwnedCredentialSource<V, M>
493 where
494     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
495 {
496     /// Pre-calculates crypto material for the given credentials, and constructs a
497     /// credentials source which holds owned copies of this crypto-material.
new<P: CryptoProvider>( credential_iter: impl IntoIterator<Item = MatchableCredential<V, M>>, ) -> Self498     pub fn new<P: CryptoProvider>(
499         credential_iter: impl IntoIterator<Item = MatchableCredential<V, M>>,
500     ) -> Self {
501         let credentials = credential_iter
502             .into_iter()
503             .map(|credential| {
504                 (
505                     precalculate_crypto_material::<V, P>(&credential.discovery_credential),
506                     credential.match_data,
507                 )
508             })
509             .collect();
510         Self { credentials }
511     }
512 }
513 
514 #[cfg(any(feature = "alloc", test))]
reference_crypto_and_match_data<C, M: MatchedCredential>( pair_ref: &(C, M), ) -> (&C, ReferencedMatchedCredential<M>)515 fn reference_crypto_and_match_data<C, M: MatchedCredential>(
516     pair_ref: &(C, M),
517 ) -> (&C, ReferencedMatchedCredential<M>) {
518     let (c, m) = pair_ref;
519     (c, m.into())
520 }
521 
522 #[cfg(any(feature = "alloc", test))]
523 impl<'a, V: ProtocolVersion, M: MatchedCredential> CredentialSource<'a, V>
524     for PrecalculatedOwnedCredentialSource<V, M>
525 where
526     Self: 'a,
527     precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
528     &'a PrecalculatedCryptoForProtocolVersion<V>: DiscoveryMetadataCryptoMaterial<V>,
529 {
530     type Matched = ReferencedMatchedCredential<'a, M>;
531     type Crypto = &'a PrecalculatedCryptoForProtocolVersion<V>;
532     type Iterator = core::iter::Map<
533         core::slice::Iter<'a, (PrecalculatedCryptoForProtocolVersion<V>, M)>,
534         fn(
535             &'a (PrecalculatedCryptoForProtocolVersion<V>, M),
536         )
537             -> (&'a PrecalculatedCryptoForProtocolVersion<V>, ReferencedMatchedCredential<'a, M>),
538     >;
539 
iter(&'a self) -> Self::Iterator540     fn iter(&'a self) -> Self::Iterator {
541         self.credentials.iter().map(reference_crypto_and_match_data)
542     }
543 }
544 
545 /// Type-alias for credential sources which are provided via slice credential-sources
546 /// with a pre-calculated credential cache layered on top.
547 pub type CachedSliceCredentialSource<'a, V, M, const N: usize> =
548     CachedCredentialSource<V, SliceCredentialSource<'a, V, M>, N>;
549 
550 /// A [`CredentialBook`] whose sources for V0 and V1 credentials come from the given slices
551 /// of discovery credentials, with crypto-materials for up to the given number of credentials
552 /// from the beginning of each slice kept in an in-memory cache.
553 pub type CachedSliceCredentialBook<'a, M, const N0: usize, const N1: usize> =
554     CredentialBookFromSources<
555         CachedSliceCredentialSource<'a, V0, M, N0>,
556         CachedSliceCredentialSource<'a, V1, M, N1>,
557     >;
558 
559 #[cfg(any(feature = "alloc", test))]
560 /// A credential-book which owns all of its (non-matched) credential data,
561 /// and maintains pre-calculated cryptographic information about all
562 /// stored credentials for speedy advertisement deserialization.
563 ///
564 /// Use this credential book if memory usage is not terribly tight,
565 /// and you're operating in an environment with an allocator.
566 pub type PrecalculatedOwnedCredentialBook<M> = CredentialBookFromSources<
567     PrecalculatedOwnedCredentialSource<V0, M>,
568     PrecalculatedOwnedCredentialSource<V1, M>,
569 >;
570