Skip to main content

fast_floe/
provider.rs

1/// A compiled-in cryptographic backend: an AEAD, KDF, and RNG bundle.
2///
3/// When exactly one backend is compiled in, everything "just works" transparently.
4///
5/// When a build contains multiple providers, bind one explicitly to
6/// a [`crate::Key`] with [`crate::Key::from_bytes_with_provider`] or
7/// [`crate::Key::generate_with_provider`].
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct Provider(ProviderKind);
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub(crate) enum ProviderKind {
13    #[cfg(feature = "aws-lc-rs")]
14    AwsLcRs,
15    #[cfg(feature = "boring")]
16    Boring,
17    #[cfg(feature = "ring")]
18    Ring,
19    #[cfg(feature = "rustcrypto")]
20    RustCrypto,
21}
22
23impl Provider {
24    /// The aws-lc-rs provider.
25    #[cfg(feature = "aws-lc-rs")]
26    pub const AWS_LC_RS: Self = Self(ProviderKind::AwsLcRs);
27
28    /// The `BoringSSL` provider.
29    #[cfg(feature = "boring")]
30    pub const BORING: Self = Self(ProviderKind::Boring);
31
32    /// The Ring provider.
33    #[cfg(feature = "ring")]
34    pub const RING: Self = Self(ProviderKind::Ring);
35
36    /// The `RustCrypto` provider.
37    #[cfg(feature = "rustcrypto")]
38    pub const RUSTCRYPTO: Self = Self(ProviderKind::RustCrypto);
39
40    /// Every provider compiled into this build.
41    pub const COMPILED: &'static [Self] = &[
42        #[cfg(feature = "aws-lc-rs")]
43        Self::AWS_LC_RS,
44        #[cfg(feature = "boring")]
45        Self::BORING,
46        #[cfg(feature = "ring")]
47        Self::RING,
48        #[cfg(feature = "rustcrypto")]
49        Self::RUSTCRYPTO,
50    ];
51
52    /// Returns the build's default provider when exactly one provider was compiled.
53    ///
54    /// Multi-provider builds deliberately have no default.
55    #[must_use]
56    pub const fn build_default() -> Option<Self> {
57        if Self::COMPILED.len() == 1 {
58            Some(Self::COMPILED[0])
59        } else {
60            None
61        }
62    }
63
64    /// Returns this provider's stable identifier.
65    #[must_use]
66    pub const fn name(self) -> &'static str {
67        match self.0 {
68            #[cfg(feature = "aws-lc-rs")]
69            ProviderKind::AwsLcRs => "aws-lc-rs",
70            #[cfg(feature = "boring")]
71            ProviderKind::Boring => "boring",
72            #[cfg(feature = "ring")]
73            ProviderKind::Ring => "ring",
74            #[cfg(feature = "rustcrypto")]
75            ProviderKind::RustCrypto => "rustcrypto",
76        }
77    }
78
79    pub(crate) const fn kind(self) -> ProviderKind {
80        self.0
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn compiled_providers_match_features() {
90        // Given the provider set selected by this build's feature flags
91        let expected = &[
92            #[cfg(feature = "aws-lc-rs")]
93            Provider::AWS_LC_RS,
94            #[cfg(feature = "boring")]
95            Provider::BORING,
96            #[cfg(feature = "ring")]
97            Provider::RING,
98            #[cfg(feature = "rustcrypto")]
99            Provider::RUSTCRYPTO,
100        ];
101
102        // Then the compiled provider list matches those features exactly
103        assert_eq!(Provider::COMPILED, expected);
104
105        // Then every provider reports its stable identifier
106        assert_eq!(
107            Provider::COMPILED
108                .iter()
109                .map(|provider| provider.name())
110                .collect::<Vec<_>>(),
111            [
112                #[cfg(feature = "aws-lc-rs")]
113                "aws-lc-rs",
114                #[cfg(feature = "boring")]
115                "boring",
116                #[cfg(feature = "ring")]
117                "ring",
118                #[cfg(feature = "rustcrypto")]
119                "rustcrypto",
120            ]
121        );
122
123        // Then a build default exists only when exactly one provider is compiled
124        assert_eq!(
125            Provider::build_default(),
126            (Provider::COMPILED.len() == 1).then_some(Provider::COMPILED[0])
127        );
128    }
129}