1use crate::error::{Error, Result};
16
17fn check_default(registry_has: bool, kind: &'static str, identifier: &str) -> Result<()> {
19 if registry_has {
20 Ok(())
21 } else {
22 Err(Error::UnknownIdentifier {
23 kind,
24 identifier: identifier.to_string(),
25 })
26 }
27}
28
29macro_rules! manager_facade {
44 (
45 $(#[$struct_doc:meta])*
46 $name:ident, $capability:path, $kind:literal,
47 $(
48 $(#[$method_doc:meta])*
49 $method:ident with $with:ident ( $($arg:ident: $ty:ty),* $(,)? )
50 -> $ret:ty
51 ),* $(,)?
52 ) => {
53 $(#[$struct_doc])*
54 #[derive(Debug)]
55 pub struct $name {
56 registry: $crate::registry::Registry<Box<dyn $capability>>,
57 default_identifier: String,
58 }
59
60 impl $name {
61 pub fn new(
64 registry: $crate::registry::Registry<Box<dyn $capability>>,
65 default_identifier: impl Into<String>,
66 ) -> $crate::error::Result<Self> {
67 let default_identifier = default_identifier.into();
68 $crate::manager::check_default(
69 registry.has(&default_identifier),
70 $kind,
71 &default_identifier,
72 )?;
73 Ok(Self {
74 registry,
75 default_identifier,
76 })
77 }
78
79 $(
80 $(#[$method_doc])*
81 pub fn $method(&self, $($arg: $ty),*) -> $ret {
82 self.$with(&self.default_identifier $(, $arg)*)
83 }
84
85 pub fn $with(&self, identifier: &str $(, $arg: $ty)*) -> $ret {
86 self.registry.get(identifier)?.$method($($arg),*)
87 }
88 )*
89
90 pub fn registry(&self) -> &$crate::registry::Registry<Box<dyn $capability>> {
91 &self.registry
92 }
93
94 pub fn registry_mut(
95 &mut self,
96 ) -> &mut $crate::registry::Registry<Box<dyn $capability>> {
97 &mut self.registry
98 }
99
100 pub fn default_identifier(&self) -> &str {
101 &self.default_identifier
102 }
103
104 pub fn set_default_identifier(
105 &mut self,
106 identifier: impl Into<String>,
107 ) -> $crate::error::Result<()> {
108 let identifier = identifier.into();
109 $crate::manager::check_default(
110 self.registry.has(&identifier),
111 $kind,
112 &identifier,
113 )?;
114 self.default_identifier = identifier;
115 Ok(())
116 }
117 }
118 };
119}
120
121mod asymmetric;
122pub use asymmetric::{KeyAgreementManager, SignatureManager};
123
124manager_facade! {
125 EncryptionManager, crate::contract::SymmetricCipher, "symmetric cipher",
127 encrypt with encrypt_with(plaintext: &[u8])
128 -> crate::error::Result<Vec<u8>>,
129 decrypt with decrypt_with(ciphertext: &[u8])
130 -> crate::error::Result<Vec<u8>>,
131}
132
133manager_facade! {
134 AsymmetricCryptoManager, crate::contract::AsymmetricCipher, "asymmetric cipher",
136 encrypt with encrypt_with(plaintext: &[u8], public_key_hex: &str)
138 -> crate::error::Result<String>,
139 decrypt with decrypt_with(ciphertext_hex: &str, private_key_hex: &str)
140 -> crate::error::Result<Vec<u8>>,
141}
142
143manager_facade! {
144 HashingManager, crate::contract::Hasher, "hasher",
146 digest with digest_with(data: &[u8])
147 -> crate::error::Result<Vec<u8>>,
148 digest_hex with digest_hex_with(data: &[u8])
149 -> crate::error::Result<String>,
150}
151
152manager_facade! {
153 KeyDerivationManager, crate::contract::KeyDerivation, "key derivation",
155 derive with derive_with(ikm: &[u8], salt: &[u8], length: usize, info: &[u8])
156 -> crate::error::Result<Vec<u8>>,
157}
158
159manager_facade! {
160 PasswordBasedKdfManager, crate::contract::PasswordBasedKdf, "password-based kdf",
162 derive_from_password with derive_from_password_with(
163 password: &[u8], salt: &[u8], length: usize
164 ) -> crate::error::Result<Vec<u8>>,
165}
166
167manager_facade! {
168 KeyEncapsulationManager, crate::contract::KeyEncapsulation, "key encapsulation",
170 generate with generate_with()
172 -> crate::error::Result<(String, String)>,
173 encapsulate with encapsulate_with(public_key_hex: &str)
175 -> crate::error::Result<(String, String)>,
176 decapsulate with decapsulate_with(ciphertext_hex: &str, private_key_hex: &str)
178 -> crate::error::Result<String>,
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use crate::contract::{
185 AsymmetricCipher, Hasher, KeyAgreement, KeyDerivation, KeyEncapsulation, PasswordBasedKdf,
186 Signer, SymmetricCipher,
187 };
188 use crate::registry::Registry;
189
190 #[test]
196 fn unknown_default_kind_is_pinned_for_every_facade() {
197 fn unknown(kind: &'static str) -> Error {
198 Error::UnknownIdentifier {
199 kind,
200 identifier: "missing".to_string(),
201 }
202 }
203
204 assert_eq!(
205 EncryptionManager::new(
206 Registry::<Box<dyn SymmetricCipher>>::new("unused"),
207 "missing"
208 )
209 .unwrap_err(),
210 unknown("symmetric cipher")
211 );
212 assert_eq!(
213 AsymmetricCryptoManager::new(
214 Registry::<Box<dyn AsymmetricCipher>>::new("unused"),
215 "missing"
216 )
217 .unwrap_err(),
218 unknown("asymmetric cipher")
219 );
220 assert_eq!(
221 HashingManager::new(Registry::<Box<dyn Hasher>>::new("unused"), "missing").unwrap_err(),
222 unknown("hasher")
223 );
224 assert_eq!(
225 KeyDerivationManager::new(Registry::<Box<dyn KeyDerivation>>::new("unused"), "missing")
226 .unwrap_err(),
227 unknown("key derivation")
228 );
229 assert_eq!(
230 PasswordBasedKdfManager::new(
231 Registry::<Box<dyn PasswordBasedKdf>>::new("unused"),
232 "missing"
233 )
234 .unwrap_err(),
235 unknown("password-based kdf")
236 );
237 assert_eq!(
238 KeyEncapsulationManager::new(
239 Registry::<Box<dyn KeyEncapsulation>>::new("unused"),
240 "missing"
241 )
242 .unwrap_err(),
243 unknown("key encapsulation")
244 );
245 assert_eq!(
246 SignatureManager::new(Registry::<Box<dyn Signer>>::new("unused"), "missing")
247 .unwrap_err(),
248 unknown("signer")
249 );
250 assert_eq!(
251 KeyAgreementManager::new(Registry::<Box<dyn KeyAgreement>>::new("unused"), "missing")
252 .unwrap_err(),
253 unknown("key agreement")
254 );
255 }
256}