1
//! [`CipherSuite`](ciphersuite::CipherSuite) implementations and all
2
//! corresponding types.
3
//!
4
//! This consists mainly of wrappers around all types requiring generic bounds
5
//! of [`CipherSuite`](ciphersuite::CipherSuite). The goal is to avoid any
6
//! user-facing types with generics. This allows users to dynamically
7
//! instantiate [`Config`](crate::Config) with arbitrary settings and store all
8
//! states and files in the same container.
9

            
10
#[cfg(feature = "blake3")]
11
mod blake3;
12
#[cfg(feature = "p256")]
13
mod p256;
14
#[cfg(feature = "pbkdf2")]
15
pub(crate) mod pbkdf2;
16
mod public_key;
17

            
18
use std::convert::TryInto;
19

            
20
use argon2::Argon2;
21
use arrayvec::ArrayVec;
22
use curve25519_dalek::{montgomery::MontgomeryPoint, ristretto::RistrettoPoint};
23
use opaque_ke::{
24
	ciphersuite, key_exchange::tripledh::TripleDH, rand::rngs::OsRng, ClientLoginFinishParameters,
25
	ClientLoginFinishResult, ClientLoginStartResult, ClientRegistrationFinishParameters,
26
	ClientRegistrationFinishResult, ClientRegistrationStartResult, ServerLoginFinishResult,
27
	ServerLoginStartParameters, ServerLoginStartResult,
28
};
29
use serde::{Deserialize, Serialize};
30
#[cfg(feature = "p256")]
31
use sha2::Sha256;
32
use sha2::Sha512;
33
#[cfg(all(feature = "p256", feature = "sha3"))]
34
use sha3::Sha3_256;
35
#[cfg(feature = "sha3")]
36
use sha3::Sha3_512;
37
use zeroize::Zeroize;
38

            
39
#[cfg(feature = "blake3")]
40
use self::blake3::Blake3;
41
#[cfg(feature = "p256")]
42
use self::p256::P256;
43
#[cfg(feature = "pbkdf2")]
44
use self::pbkdf2::Pbkdf2;
45
use self::public_key::PublicKeyExt;
46
use crate::{Error, Result};
47

            
48
/// Wrapper around multiple [`CipherSuite`](ciphersuite::CipherSuite)s to avoid
49
/// user-facing generics.
50
7362
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
51
pub(crate) enum CipherSuite {
52
	/// Ristretto255 + SHA2 + Argon2
53
	Ristretto255Sha2Argon2,
54
	/// Ristretto255 + SHA2 + PBKDF2
55
	#[cfg(feature = "pbkdf2")]
56
	Ristretto255Sha2Pbkdf2,
57
	/// Ristretto255 + SHA3 + Argon2
58
	#[cfg(feature = "sha3")]
59
	Ristretto255Sha3Argon2,
60
	/// Ristretto255 + SHA3 + PBKDF2
61
	#[cfg(all(feature = "sha3", feature = "pbkdf2"))]
62
	Ristretto255Sha3Pbkdf2,
63
	/// Ristretto255 + BLAKE3 + Argon2
64
	#[cfg(feature = "blake3")]
65
	Ristretto255Blake3Argon2,
66
	/// Ristretto255 + BLAKE3 + PBKDF2
67
	#[cfg(all(feature = "blake3", feature = "pbkdf2"))]
68
	Ristretto255Blake3Pbkdf2,
69
	/// X25519 + Ristretto255 + SHA2 + Argon2
70
	X25519Ristretto255Sha2Argon2,
71
	/// X25519 + Ristretto255 + SHA2 + PBKDF2
72
	#[cfg(feature = "pbkdf2")]
73
	X25519Ristretto255Sha2Pbkdf2,
74
	/// X25519 + Ristretto255 + SHA3 + Argon2
75
	#[cfg(feature = "sha3")]
76
	X25519Ristretto255Sha3Argon2,
77
	/// X25519 + Ristretto255 + SHA3 + PBKDF2
78
	#[cfg(all(feature = "sha3", feature = "pbkdf2"))]
79
	X25519Ristretto255Sha3Pbkdf2,
80
	/// X25519 + Ristretto255 + BLAKE3 + Argon2
81
	#[cfg(feature = "blake3")]
82
	X25519Ristretto255Blake3Argon2,
83
	/// X25519 + Ristretto255 + BLAKE3 + PBKDF2
84
	#[cfg(all(feature = "blake3", feature = "pbkdf2"))]
85
	X25519Ristretto255Blake3Pbkdf2,
86
	/// P256 + Ristretto255 + SHA2 + Argon2
87
	#[cfg(feature = "p256")]
88
	P256Ristretto255Sha2Argon2,
89
	/// P256 + Ristretto255 + SHA2 + PBKDF2
90
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
91
	P256Ristretto255Sha2Pbkdf2,
92
	/// P256 + Ristretto255 + SHA3 + Argon2
93
	#[cfg(all(feature = "p256", feature = "sha3"))]
94
	P256Ristretto255Sha3Argon2,
95
	/// P256 + Ristretto255 + SHA3 + PBKDF2
96
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
97
	P256Ristretto255Sha3Pbkdf2,
98
	/// P256 + Ristretto255 + BLAKE3 + Argon2
99
	#[cfg(all(feature = "p256", feature = "blake3"))]
100
	P256Ristretto255Blake3Argon2,
101
	/// P256 + Ristretto255 + BLAKE3 + PBKDF2
102
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
103
	P256Ristretto255Blake3Pbkdf2,
104
	/// P256 + SHA2 + Argon2
105
	#[cfg(feature = "p256")]
106
	P256Sha2Argon2,
107
	/// P256 + SHA2 + PBKDF2
108
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
109
	P256Sha2Pbkdf2,
110
	/// P256 + SHA3 + Argon2
111
	#[cfg(all(feature = "p256", feature = "sha3"))]
112
	P256Sha3Argon2,
113
	/// P256 + SHA3 + PBKDF2
114
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
115
	P256Sha3Pbkdf2,
116
	/// P256 + BLAKE3 + Argon2
117
	#[cfg(all(feature = "p256", feature = "blake3"))]
118
	P256Blake3Argon2,
119
	/// P256 + BLAKE3 + PBKDF2
120
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
121
	P256Blake3Pbkdf2,
122
	/// Ristretto255 + P256 + SHA2 + Argon2
123
	#[cfg(feature = "p256")]
124
	Ristretto255P256Sha2Argon2,
125
	/// Ristretto255 + P256 + SHA2 + PBKDF2
126
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
127
	Ristretto255P256Sha2Pbkdf2,
128
	/// Ristretto255 + P256 + SHA3 + Argon2
129
	#[cfg(all(feature = "p256", feature = "sha3"))]
130
	Ristretto255P256Sha3Argon2,
131
	/// Ristretto255 + P256 + SHA3 + PBKDF2
132
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
133
	Ristretto255P256Sha3Pbkdf2,
134
	/// Ristretto255 + P256 + BLAKE3 + Argon2
135
	#[cfg(all(feature = "p256", feature = "blake3"))]
136
	Ristretto255P256Blake3Argon2,
137
	/// Ristretto255 + P256 + BLAKE3 + PBKDF2
138
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
139
	Ristretto255P256Blake3Pbkdf2,
140
	/// X25519 + P256 + SHA2 + Argon2
141
	#[cfg(feature = "p256")]
142
	X25519P256Sha2Argon2,
143
	/// X25519 + P256 + SHA2 + PBKDF2
144
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
145
	X25519P256Sha2Pbkdf2,
146
	/// X25519 + P256 + SHA3 + Argon2
147
	#[cfg(all(feature = "p256", feature = "sha3"))]
148
	X25519P256Sha3Argon2,
149
	/// X25519 + P256 + SHA3 + PBKDF2
150
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
151
	X25519P256Sha3Pbkdf2,
152
	/// X25519 + P256 + BLAKE3 + Argon2
153
	#[cfg(all(feature = "p256", feature = "blake3"))]
154
	X25519P256Blake3Argon2,
155
	/// X25519 + P256 + BLAKE3 + PBKDF2
156
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
157
	X25519P256Blake3Pbkdf2,
158
}
159

            
160
/// Pass down parameter to [`SlowHash`](opaque_ke::slow_hash::SlowHash).
161
pub(crate) enum SlowHashParams {
162
	/// Argon2.
163
	Argon2(Argon2<'static>),
164
	/// PBKDF2.
165
	#[cfg(feature = "pbkdf2")]
166
	Pbkdf2(Pbkdf2),
167
}
168

            
169
/// Generate many [`CipherSuite`](ciphersuite::CipherSuite)s.
170
macro_rules! cipher_suite {
171
	(
172
		$($(#[$attr:meta])? [
173
			$cipher_suite:ident,
174
			$ake:ty,
175
			$group:ty,
176
			$hash:ty,
177
			$slow_hash:ident$(<$slow_hash_li:lifetime>)?$(,)?
178
		]),+$(,)?) => {
179
		$(
180
		$(#[$attr])?
181
		#[allow(clippy::missing_docs_in_private_items)]
182
		#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
183
		pub(crate) struct $cipher_suite;
184

            
185
		$(#[$attr])?
186
		impl ciphersuite::CipherSuite for $cipher_suite {
187
			type OprfGroup = $group;
188
			type KeGroup = $ake;
189
			type Hash = $hash;
190
			type KeyExchange = TripleDH;
191
			type SlowHash = $slow_hash$(<$slow_hash_li>)?;
192
		}
193
		)+
194

            
195
		/// [`opaque_ke::ClientRegistration`] wrapper.
196
		#[allow(clippy::missing_docs_in_private_items)]
197
288
		#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
198
		pub(crate) enum ClientRegistration {
199
			$($(#[$attr])? $cipher_suite(opaque_ke::ClientRegistration<$cipher_suite>),)+
200
		}
201

            
202
		impl ClientRegistration {
203
			/// [`opaque_ke::ClientRegistration::start()`] wrapper.
204
230
			pub(crate) fn register(
205
230
				cipher_suite: CipherSuite,
206
230
				password: &[u8],
207
230
			) -> Result<(Self, RegistrationRequest)> {
208
230
				match cipher_suite {
209
					$($(#[$attr])? CipherSuite::$cipher_suite => {
210
6
						let result = opaque_ke::ClientRegistration::start(&mut OsRng, password)?;
211
6
						let ClientRegistrationStartResult { state, message } = result;
212
6
						Ok((
213
6
							Self::$cipher_suite(state),
214
6
							RegistrationRequest::$cipher_suite(message),
215
6
						))
216
					})+
217
				}
218
230
			}
219

            
220
			/// [`opaque_ke::ClientRegistration::finish()`] wrapper.
221
230
			pub(crate) fn finish(
222
230
				self,
223
230
				response: RegistrationResponse,
224
230
				slow_hash: &SlowHashParams,
225
230
			) -> Result<(RegistrationFinalization, [u8; 33], ArrayVec<u8, 64>)> {
226
230
				match (self, response, slow_hash) {
227
					$($(#[$attr])? (
228
6
						Self::$cipher_suite(state),
229
6
						RegistrationResponse::$cipher_suite(response),
230
6
						SlowHashParams::$slow_hash(slow_hash),
231
					) => {
232
6
						let result = state.finish(
233
6
							&mut OsRng,
234
6
							response,
235
6
							ClientRegistrationFinishParameters::new(None, Some(slow_hash)),
236
6
						)?;
237
						let ClientRegistrationFinishResult {
238
6
							message,
239
6
							mut export_key,
240
6
							server_s_pk,
241
6
						} = result;
242
6

            
243
6
						let new_export_key = export_key
244
6
							.as_slice()
245
6
							.try_into()
246
6
							.expect("unexpected size");
247
6
						export_key.zeroize();
248
6

            
249
6
						Ok((
250
6
							RegistrationFinalization::$cipher_suite(message),
251
6
							server_s_pk.into_array(),
252
6
							new_export_key,
253
6
						))
254
					})+
255
					_ => Err(Error::Config),
256
				}
257
230
			}
258
		}
259

            
260
		/// [`opaque_ke::ClientLogin`] wrapper.
261
		#[allow(clippy::missing_docs_in_private_items)]
262
288
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
263
		pub(crate) enum ClientLogin {
264
			$($(#[$attr])? $cipher_suite(opaque_ke::ClientLogin<$cipher_suite>),)+
265
		}
266

            
267
		impl ClientLogin {
268
			/// [`opaque_ke::ClientLogin::start()`] wrapper.
269
228
			pub(crate) fn login(
270
228
				cipher_suite: CipherSuite,
271
228
				password: &[u8],
272
228
			) -> Result<(Self, LoginRequest)> {
273
228
				match cipher_suite {
274
					$($(#[$attr])? CipherSuite::$cipher_suite => {
275
6
						let result = opaque_ke::ClientLogin::start(&mut OsRng, password)?;
276
6
						let ClientLoginStartResult { state, message } = result;
277
6
						Ok((
278
6
							Self::$cipher_suite(state),
279
6
							LoginRequest::$cipher_suite(message),
280
6
						))
281
					})+
282
				}
283
228
			}
284

            
285
			/// [`opaque_ke::ClientLogin::finish()`] wrapper.
286
227
			pub(crate) fn finish(
287
227
				self,
288
227
				response: LoginResponse,
289
227
				slow_hash: &SlowHashParams,
290
227
			) -> Result<(LoginFinalization, [u8; 33], ArrayVec<u8, 64>)> {
291
227
				match (self, response, slow_hash) {
292
					$($(#[$attr])? (
293
6
						Self::$cipher_suite(state),
294
6
						LoginResponse::$cipher_suite(response),
295
6
						SlowHashParams::$slow_hash(slow_hash),
296
					) => {
297
6
						let result =
298
6
							state.finish(
299
6
								response,
300
6
								ClientLoginFinishParameters::new(None, None, Some(slow_hash)),
301
6
							)?;
302
						let ClientLoginFinishResult {
303
6
							message,
304
6
							mut export_key,
305
6
							server_s_pk,
306
6
							..
307
6
						} = result;
308
6

            
309
6
						let new_export_key = export_key
310
6
							.as_slice()
311
6
							.try_into()
312
6
							.expect("unexpected size");
313
6
						export_key.zeroize();
314
6

            
315
6
						Ok((
316
6
							LoginFinalization::$cipher_suite(message),
317
6
							server_s_pk.into_array(),
318
6
							new_export_key,
319
6
						))
320
					})+
321
					_ => Err(Error::Config),
322
				}
323
227
			}
324
		}
325

            
326
		/// [`opaque_ke::ServerSetup`] wrapper.
327
		#[allow(clippy::missing_docs_in_private_items)]
328
288
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
329
		pub(crate) enum ServerSetup {
330
			$($(#[$attr])? $cipher_suite(opaque_ke::ServerSetup<$cipher_suite>),)+
331
		}
332

            
333
		impl ServerSetup {
334
			/// [`opaque_ke::ServerSetup::new()`] wrapper.
335
234
			pub(crate) fn new(cipher_suite: CipherSuite) -> Self {
336
234
				match cipher_suite {
337
					$($(#[$attr])? CipherSuite::$cipher_suite =>
338
6
						Self::$cipher_suite(opaque_ke::ServerSetup::new(&mut OsRng)),)+
339
				}
340
234
			}
341

            
342
			/// [`opaque_ke::ServerSetup::keypair()`] wrapper.
343
686
			pub(crate) fn public_key(&self) -> [u8; 33] {
344
686
				match self {
345
18
					$($(#[$attr])? ServerSetup::$cipher_suite(server_setup) =>
346
18
						server_setup.keypair().public().to_array(),)+
347
				}
348
686
			}
349
		}
350

            
351
		/// [`opaque_ke::ServerRegistration`] wrapper.
352
		#[allow(clippy::missing_docs_in_private_items)]
353
288
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
354
		pub(crate) enum ServerFile {
355
			$($(#[$attr])? $cipher_suite(opaque_ke::ServerRegistration<$cipher_suite>),)+
356
		}
357

            
358
		/// [`opaque_ke::ServerRegistration`] wrapper.
359
		#[allow(clippy::missing_docs_in_private_items)]
360
288
		#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
361
		pub(crate) enum ServerRegistration {
362
			$($(#[$attr])? $cipher_suite,)+
363
		}
364

            
365
		impl ServerRegistration {
366
			/// [`opaque_ke::ServerRegistration::start()`] wrapper.
367
230
			pub(crate) fn register(
368
230
				server_setup: &ServerSetup,
369
230
				request: RegistrationRequest,
370
230
			) -> Result<(Self, RegistrationResponse)> {
371
230
				match (server_setup, request) {
372
					$($(#[$attr])? (
373
6
						ServerSetup::$cipher_suite(server_setup),
374
6
						RegistrationRequest::$cipher_suite(request),
375
					) => {
376
6
						let response =
377
6
							opaque_ke::ServerRegistration::start(
378
6
								server_setup,
379
6
								request,
380
6
								&[]
381
6
							)?.message;
382
6
						Ok((
383
6
							Self::$cipher_suite,
384
6
							RegistrationResponse::$cipher_suite(response),
385
6
						))
386
					})+
387
					_ => Err(Error::Config),
388
				}
389
230
			}
390

            
391
			/// [`opaque_ke::ServerRegistration::finish()`] wrapper.
392
229
			pub(crate) fn finish(self, finalization: RegistrationFinalization
393
229
			) -> Result<ServerFile> {
394
229
				match (self, finalization) {
395
					$($(#[$attr])? (
396
						Self::$cipher_suite,
397
6
						RegistrationFinalization::$cipher_suite(finalization),
398
6
					) => {
399
6
						let file = opaque_ke::ServerRegistration::finish(finalization);
400
6
						Ok(ServerFile::$cipher_suite(file))
401
					})+
402
					_ => Err(Error::Config),
403
				}
404
229
			}
405
		}
406

            
407
		/// [`opaque_ke::ServerLogin`] wrapper.
408
		#[allow(clippy::missing_docs_in_private_items)]
409
288
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
410
		pub(crate) enum ServerLogin {
411
			$($(#[$attr])? $cipher_suite(opaque_ke::ServerLogin<$cipher_suite>),)+
412
		}
413

            
414
		impl ServerLogin {
415
			/// [`opaque_ke::ServerLogin::start()`] wrapper.
416
229
			pub(crate) fn login(
417
229
				setup: &ServerSetup,
418
229
				file: Option<(ServerFile, [u8; 33])>,
419
229
				request: LoginRequest,
420
229
			) -> Result<(Self, LoginResponse)> {
421
229
				match (setup, request) {
422
					$($(#[$attr])? (
423
6
						ServerSetup::$cipher_suite(server_setup),
424
6
						LoginRequest::$cipher_suite(request),
425
					) => {
426
6
						let file = match file {
427
6
							Some((ServerFile::$cipher_suite(file), public_key)) => {
428
6
								if !server_setup.keypair().public().is_array(public_key) {
429
									return Err(Error::ServerFile);
430
226
								}
431

            
432
6
								Some(file)
433
							},
434
							Some(_) => return Err(Error::Config),
435
							None => None,
436
						};
437

            
438
6
						let result = opaque_ke::ServerLogin::start(
439
6
							&mut OsRng,
440
6
							server_setup,
441
6
							file,
442
6
							request,
443
6
							&[],
444
6
							ServerLoginStartParameters::default(),
445
6
						)?;
446
6
						let ServerLoginStartResult { state, message } = result;
447
6
						Ok((
448
6
							Self::$cipher_suite(state),
449
6
							LoginResponse::$cipher_suite(message),
450
6
						))
451
					})+
452
					_ => Err(Error::Config),
453
				}
454
229
			}
455

            
456
			/// [`opaque_ke::ClientLogin::finish()`] wrapper.
457
224
			pub(crate) fn finish(self, finalization: LoginFinalization) -> Result<()> {
458
224
				match (self, finalization) {
459
					$($(#[$attr])? (
460
6
						Self::$cipher_suite(state),
461
6
						LoginFinalization::$cipher_suite(finalization),
462
					) => {
463
6
						let result = state.finish(finalization)?;
464
						let ServerLoginFinishResult { .. } = result;
465

            
466
6
						Ok(())
467
					})+
468
					_ => Err(Error::Config),
469
				}
470
224
			}
471
		}
472

            
473
		/// [`opaque_ke::RegistrationRequest`] wrapper.
474
		#[allow(clippy::missing_docs_in_private_items)]
475
290
		#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
476
		pub(crate) enum RegistrationRequest {
477
			$($(#[$attr])? $cipher_suite(opaque_ke::RegistrationRequest<$cipher_suite>),)+
478
		}
479

            
480
		/// [`opaque_ke::RegistrationResponse`] wrapper.
481
		#[allow(clippy::missing_docs_in_private_items)]
482
290
		#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
483
		pub(crate) enum RegistrationResponse {
484
			$($(#[$attr])? $cipher_suite(opaque_ke::RegistrationResponse<$cipher_suite>),)+
485
		}
486

            
487
		/// [`opaque_ke::RegistrationUpload`] wrapper.
488
		#[allow(clippy::missing_docs_in_private_items)]
489
290
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
490
		pub(crate) enum RegistrationFinalization {
491
			$($(#[$attr])? $cipher_suite(opaque_ke::RegistrationUpload<$cipher_suite>),)+
492
		}
493

            
494
		/// [`opaque_ke::CredentialRequest`] wrapper.
495
		#[allow(clippy::missing_docs_in_private_items)]
496
290
		#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
497
		pub(crate) enum LoginRequest {
498
			$($(#[$attr])? $cipher_suite(opaque_ke::CredentialRequest<$cipher_suite>),)+
499
		}
500

            
501
		/// [`opaque_ke::CredentialResponse`] wrapper.
502
		#[allow(clippy::missing_docs_in_private_items)]
503
290
		#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
504
		pub(crate) enum LoginResponse {
505
			$($(#[$attr])? $cipher_suite(opaque_ke::CredentialResponse<$cipher_suite>),)+
506
		}
507

            
508
		/// [`opaque_ke::CredentialFinalization`] wrapper.
509
		#[allow(clippy::missing_docs_in_private_items)]
510
290
		#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
511
		pub(crate) enum LoginFinalization {
512
			$($(#[$attr])? $cipher_suite(opaque_ke::CredentialFinalization<$cipher_suite>),)+
513
		}
514
	};
515
}
516

            
517
cipher_suite!(
518
	[Ristretto255Sha2Argon2, RistrettoPoint, RistrettoPoint, Sha512, Argon2<'static>],
519
	#[cfg(feature = "pbkdf2")]
520
	[Ristretto255Sha2Pbkdf2, RistrettoPoint, RistrettoPoint, Sha512, Pbkdf2],
521
	#[cfg(feature = "sha3")]
522
	[Ristretto255Sha3Argon2, RistrettoPoint, RistrettoPoint, Sha3_512, Argon2<'static>],
523
	#[cfg(all(feature = "sha3", feature = "pbkdf2"))]
524
	[Ristretto255Sha3Pbkdf2, RistrettoPoint, RistrettoPoint, Sha3_512, Pbkdf2],
525
	#[cfg(feature = "blake3")]
526
	[Ristretto255Blake3Argon2, RistrettoPoint, RistrettoPoint, Blake3, Argon2<'static>],
527
	#[cfg(all(feature = "blake3", feature = "pbkdf2"))]
528
	[Ristretto255Blake3Pbkdf2, RistrettoPoint, RistrettoPoint, Blake3, Pbkdf2],
529
	[X25519Ristretto255Sha2Argon2, MontgomeryPoint, RistrettoPoint, Sha512, Argon2<'static>],
530
	#[cfg(feature = "pbkdf2")]
531
	[X25519Ristretto255Sha2Pbkdf2, MontgomeryPoint, RistrettoPoint, Sha512, Pbkdf2],
532
	#[cfg(feature = "sha3")]
533
	[X25519Ristretto255Sha3Argon2, MontgomeryPoint, RistrettoPoint, Sha3_512, Argon2<'static>],
534
	#[cfg(all(feature = "sha3", feature = "pbkdf2"))]
535
	[X25519Ristretto255Sha3Pbkdf2, MontgomeryPoint, RistrettoPoint, Sha3_512, Pbkdf2],
536
	#[cfg(feature = "blake3")]
537
	[X25519Ristretto255Blake3Argon2, MontgomeryPoint, RistrettoPoint, Blake3, Argon2<'static>],
538
	#[cfg(all(feature = "blake3", feature = "pbkdf2"))]
539
	[X25519Ristretto255Blake3Pbkdf2, MontgomeryPoint, RistrettoPoint, Blake3, Pbkdf2],
540
	#[cfg(feature = "p256")]
541
	[P256Ristretto255Sha2Argon2, P256, RistrettoPoint, Sha512, Argon2<'static>],
542
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
543
	[P256Ristretto255Sha2Pbkdf2, P256, RistrettoPoint, Sha512, Pbkdf2],
544
	#[cfg(all(feature = "p256", feature = "sha3"))]
545
	[P256Ristretto255Sha3Argon2, P256, RistrettoPoint, Sha3_512, Argon2<'static>],
546
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
547
	[P256Ristretto255Sha3Pbkdf2, P256, RistrettoPoint, Sha3_512, Pbkdf2],
548
	#[cfg(all(feature = "p256", feature = "blake3"))]
549
	[P256Ristretto255Blake3Argon2, P256, RistrettoPoint, Blake3, Argon2<'static>],
550
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
551
	[P256Ristretto255Blake3Pbkdf2, P256, RistrettoPoint, Blake3, Pbkdf2],
552
	#[cfg(feature = "p256")]
553
	[P256Sha2Argon2, P256, P256, Sha256, Argon2<'static>],
554
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
555
	[P256Sha2Pbkdf2, P256, P256, Sha256, Pbkdf2],
556
	#[cfg(all(feature = "p256", feature = "sha3"))]
557
	[P256Sha3Argon2, P256, P256, Sha3_256, Argon2<'static>],
558
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
559
	[P256Sha3Pbkdf2, P256, P256, Sha3_256, Pbkdf2],
560
	#[cfg(all(feature = "p256", feature = "blake3"))]
561
	[P256Blake3Argon2, P256, P256, ::blake3::Hasher, Argon2<'static>],
562
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
563
	[P256Blake3Pbkdf2, P256, P256, ::blake3::Hasher, Pbkdf2],
564
	#[cfg(feature = "p256")]
565
	[Ristretto255P256Sha2Argon2, RistrettoPoint, P256, Sha256, Argon2<'static>],
566
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
567
	[Ristretto255P256Sha2Pbkdf2, RistrettoPoint, P256, Sha256, Pbkdf2],
568
	#[cfg(all(feature = "p256", feature = "sha3"))]
569
	[Ristretto255P256Sha3Argon2, RistrettoPoint, P256, Sha3_256, Argon2<'static>],
570
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
571
	[Ristretto255P256Sha3Pbkdf2, RistrettoPoint, P256, Sha3_256, Pbkdf2],
572
	#[cfg(all(feature = "p256", feature = "blake3"))]
573
	[Ristretto255P256Blake3Argon2, RistrettoPoint, P256, ::blake3::Hasher, Argon2<'static>],
574
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
575
	[Ristretto255P256Blake3Pbkdf2, RistrettoPoint, P256, ::blake3::Hasher, Pbkdf2],
576
	#[cfg(feature = "p256")]
577
	[X25519P256Sha2Argon2, MontgomeryPoint, P256, Sha256, Argon2<'static>],
578
	#[cfg(all(feature = "p256", feature = "pbkdf2"))]
579
	[X25519P256Sha2Pbkdf2, MontgomeryPoint, P256, Sha256, Pbkdf2],
580
	#[cfg(all(feature = "p256", feature = "sha3"))]
581
	[X25519P256Sha3Argon2, MontgomeryPoint, P256, Sha3_256, Argon2<'static>],
582
	#[cfg(all(feature = "p256", feature = "sha3", feature = "pbkdf2"))]
583
	[X25519P256Sha3Pbkdf2, MontgomeryPoint, P256, Sha3_256, Pbkdf2],
584
	#[cfg(all(feature = "p256", feature = "blake3"))]
585
	[X25519P256Blake3Argon2, MontgomeryPoint, P256, ::blake3::Hasher, Argon2<'static>],
586
	#[cfg(all(feature = "p256", feature = "blake3", feature = "pbkdf2"))]
587
	[X25519P256Blake3Pbkdf2, MontgomeryPoint, P256, ::blake3::Hasher, Pbkdf2],
588
);