This commit is contained in:
parent
6e5c985719
commit
1b796d0ce7
46 changed files with 1755 additions and 691 deletions
|
|
@ -200,6 +200,35 @@ impl Keyring {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generates the independent KEM, classical-signature, and PQ-signature keys concurrently.
|
||||
#[cfg(all(
|
||||
feature = "mlkem-tls",
|
||||
feature = "ml-dsa",
|
||||
feature = "ed25519-dalek",
|
||||
feature = "parallel"
|
||||
))]
|
||||
pub async fn generate_parallel() -> Self {
|
||||
let kem_handle = tokio::task::spawn_blocking(crate::kem::HybridKem::generate_keypair);
|
||||
let ed_handle = tokio::task::spawn_blocking(crate::sign::Ed25519Signer::generate);
|
||||
let pq_handle = tokio::task::spawn_blocking(crate::sign::MlDsaSigner::generate);
|
||||
|
||||
let (kem_result, ed_result, pq_result) = tokio::join!(kem_handle, ed_handle, pq_handle);
|
||||
let (kem_sk, kem_pk) = kem_result.expect("key generation task must not panic");
|
||||
let (_ed_signer, sig_cl_sk, sig_cl_pk) =
|
||||
ed_result.expect("key generation task must not panic");
|
||||
let (_pq_signer, sig_pq_sk, sig_pq_pk) =
|
||||
pq_result.expect("key generation task must not panic");
|
||||
|
||||
Self {
|
||||
kem_public_key: kem_pk,
|
||||
kem_secret_key: kem_sk,
|
||||
sig_pq_public_key: sig_pq_pk,
|
||||
sig_pq_secret_key: sig_pq_sk,
|
||||
sig_cl_public_key: sig_cl_pk,
|
||||
sig_cl_secret_key: sig_cl_sk,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_key_bundle(&self) -> PublicKeyBundle {
|
||||
PublicKeyBundle {
|
||||
kem_public_key: self.kem_public_key.clone(),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ pub mod auth;
|
|||
pub mod error;
|
||||
pub mod keypair;
|
||||
|
||||
use std::sync::Once;
|
||||
|
||||
static CRYPTO_INIT: Once = Once::new();
|
||||
|
||||
#[cfg(feature = "sha2")]
|
||||
pub mod hash;
|
||||
|
||||
|
|
@ -12,6 +16,9 @@ pub mod kdf;
|
|||
#[cfg(any(feature = "ed25519-dalek", feature = "ml-dsa"))]
|
||||
pub mod sign;
|
||||
|
||||
#[cfg(all(feature = "ed25519-dalek", feature = "ml-dsa", feature = "parallel"))]
|
||||
pub mod sign_parallel;
|
||||
|
||||
#[cfg(any(feature = "ed25519-dalek", feature = "ml-dsa"))]
|
||||
pub use sign::SigAlgorithm;
|
||||
|
||||
|
|
@ -59,6 +66,16 @@ pub use kem::{Encapsulated, HybridKem};
|
|||
|
||||
pub use enc::EncryptionType;
|
||||
|
||||
/// Install Rustls' AWS-LC provider once for the entire process.
|
||||
///
|
||||
/// Rustls only accepts one process-wide default provider. Calling this helper
|
||||
/// from every TLS entry point makes that initialization idempotent.
|
||||
pub fn ensure_crypto_provider() {
|
||||
CRYPTO_INIT.call_once(|| {
|
||||
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "mlkem-tls", feature = "hkdf"))]
|
||||
pub use enc::{decrypt_with, encrypt_for};
|
||||
|
||||
|
|
|
|||
73
crypto/src/sign_parallel.rs
Normal file
73
crypto/src/sign_parallel.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
//! Parallel helpers for dual (classical + post-quantum) signatures.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::task;
|
||||
|
||||
use crate::{
|
||||
CryptoError, SignaturePqPublicKey, SignaturePublicKey, SignatureScheme, verify_ed25519,
|
||||
verify_ml_dsa,
|
||||
};
|
||||
|
||||
/// Signs a message with the classical and PQ schemes concurrently on Tokio's blocking pool.
|
||||
pub async fn sign_dual_parallel<S1, S2>(
|
||||
ed_signer: S1,
|
||||
pq_signer: S2,
|
||||
message: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>), CryptoError>
|
||||
where
|
||||
S1: SignatureScheme + Send + 'static,
|
||||
S2: SignatureScheme + Send + 'static,
|
||||
{
|
||||
let ed_message = message.clone();
|
||||
let ed_handle = task::spawn_blocking(move || ed_signer.sign(&ed_message));
|
||||
let pq_handle = task::spawn_blocking(move || pq_signer.sign(&message));
|
||||
|
||||
let (ed_result, pq_result) = tokio::join!(ed_handle, pq_handle);
|
||||
let ed_signature = ed_result.map_err(|_| CryptoError::SigningFailed)??;
|
||||
let pq_signature = pq_result.map_err(|_| CryptoError::SigningFailed)??;
|
||||
Ok((ed_signature, pq_signature))
|
||||
}
|
||||
|
||||
/// Signs with an owned classical signer and a shared PQ signer.
|
||||
///
|
||||
/// This avoids reconstructing the ML-DSA signing key when a host signs both
|
||||
/// the challenge and the final response in one authentication handshake.
|
||||
pub async fn sign_dual_parallel_shared_pq<S1, S2>(
|
||||
ed_signer: S1,
|
||||
pq_signer: Arc<S2>,
|
||||
message: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>), CryptoError>
|
||||
where
|
||||
S1: SignatureScheme + Send + 'static,
|
||||
S2: SignatureScheme + Send + Sync + 'static,
|
||||
{
|
||||
let ed_message = message.clone();
|
||||
let ed_handle = task::spawn_blocking(move || ed_signer.sign(&ed_message));
|
||||
let pq_handle = task::spawn_blocking(move || pq_signer.sign(&message));
|
||||
|
||||
let (ed_result, pq_result) = tokio::join!(ed_handle, pq_handle);
|
||||
let ed_signature = ed_result.map_err(|_| CryptoError::SigningFailed)??;
|
||||
let pq_signature = pq_result.map_err(|_| CryptoError::SigningFailed)??;
|
||||
Ok((ed_signature, pq_signature))
|
||||
}
|
||||
|
||||
/// Verifies the classical and PQ signatures concurrently on Tokio's blocking pool.
|
||||
pub async fn verify_dual_parallel(
|
||||
ed_public_key: SignaturePublicKey,
|
||||
pq_public_key: SignaturePqPublicKey,
|
||||
message: Vec<u8>,
|
||||
ed_signature: Vec<u8>,
|
||||
pq_signature: Vec<u8>,
|
||||
) -> Result<(), CryptoError> {
|
||||
let ed_message = message.clone();
|
||||
let ed_handle =
|
||||
task::spawn_blocking(move || verify_ed25519(&ed_public_key, &ed_message, &ed_signature));
|
||||
let pq_handle =
|
||||
task::spawn_blocking(move || verify_ml_dsa(&pq_public_key, &message, &pq_signature));
|
||||
|
||||
let (ed_result, pq_result) = tokio::join!(ed_handle, pq_handle);
|
||||
ed_result.map_err(|_| CryptoError::VerificationFailed)??;
|
||||
pq_result.map_err(|_| CryptoError::VerificationFailed)??;
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Reference in a new issue