use bc_rand::RandomNumberGenerator;
#[cfg(feature = "ssh")]
use ssh_key::Algorithm;
use super::{SigningPrivateKey, SigningPublicKey};
#[cfg(feature = "secp256k1")]
use crate::ECPrivateKey;
#[cfg(feature = "ed25519")]
use crate::Ed25519PrivateKey;
#[cfg(feature = "ssh")]
use crate::PrivateKeyBase;
#[cfg_attr(not(feature = "pqcrypto"), allow(unused_imports))]
use crate::{Error, Result};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "secp256k1", derive(Default))]
#[cfg_attr(
all(feature = "ed25519", not(feature = "secp256k1")),
derive(Default)
)]
pub enum SignatureScheme {
#[cfg(feature = "secp256k1")]
#[cfg_attr(feature = "secp256k1", default)]
Schnorr,
#[cfg(feature = "secp256k1")]
Ecdsa,
#[cfg(feature = "ed25519")]
#[cfg_attr(all(feature = "ed25519", not(feature = "secp256k1")), default)]
Ed25519,
#[cfg(feature = "pqcrypto")]
MLDSA44,
#[cfg(feature = "pqcrypto")]
MLDSA65,
#[cfg(feature = "pqcrypto")]
MLDSA87,
#[cfg(feature = "ssh")]
SshEd25519,
#[cfg(feature = "ssh")]
SshDsa,
#[cfg(feature = "ssh")]
SshEcdsaP256,
#[cfg(feature = "ssh")]
SshEcdsaP384,
}
impl SignatureScheme {
pub fn keypair(&self) -> (SigningPrivateKey, SigningPublicKey) {
self.keypair_opt("")
}
pub fn keypair_opt(
&self,
comment: impl Into<String>,
) -> (SigningPrivateKey, SigningPublicKey) {
#[cfg_attr(not(feature = "ssh"), allow(unused_variables))]
let comment = comment.into();
#[allow(unreachable_patterns)]
match self {
#[cfg(feature = "secp256k1")]
Self::Schnorr => {
let private_key =
SigningPrivateKey::new_schnorr(ECPrivateKey::new());
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "secp256k1")]
Self::Ecdsa => {
let private_key =
SigningPrivateKey::new_ecdsa(ECPrivateKey::new());
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "ed25519")]
Self::Ed25519 => {
let private_key =
SigningPrivateKey::new_ed25519(Ed25519PrivateKey::new());
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "pqcrypto")]
Self::MLDSA44 => {
let (private_key, public_key) = crate::MLDSA::MLDSA44.keypair();
let private_key = SigningPrivateKey::MLDSA(private_key);
let public_key = SigningPublicKey::MLDSA(public_key);
(private_key, public_key)
}
#[cfg(feature = "pqcrypto")]
Self::MLDSA65 => {
let (private_key, public_key) = crate::MLDSA::MLDSA65.keypair();
let private_key = SigningPrivateKey::MLDSA(private_key);
let public_key = SigningPublicKey::MLDSA(public_key);
(private_key, public_key)
}
#[cfg(feature = "pqcrypto")]
Self::MLDSA87 => {
let (private_key, public_key) = crate::MLDSA::MLDSA87.keypair();
let private_key = SigningPrivateKey::MLDSA(private_key);
let public_key = SigningPublicKey::MLDSA(public_key);
(private_key, public_key)
}
#[cfg(feature = "ssh")]
Self::SshEd25519 => {
let private_key_base = PrivateKeyBase::new();
let private_key = private_key_base
.ssh_signing_private_key(Algorithm::Ed25519, comment)
.unwrap();
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "ssh")]
Self::SshDsa => {
let private_key_base = PrivateKeyBase::new();
let private_key = private_key_base
.ssh_signing_private_key(Algorithm::Dsa, comment)
.unwrap();
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "ssh")]
Self::SshEcdsaP256 => {
let private_key_base = PrivateKeyBase::new();
let private_key = private_key_base
.ssh_signing_private_key(
Algorithm::Ecdsa {
curve: ssh_key::EcdsaCurve::NistP256,
},
comment,
)
.unwrap();
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(feature = "ssh")]
Self::SshEcdsaP384 => {
let private_key_base = PrivateKeyBase::new();
let private_key = private_key_base
.ssh_signing_private_key(
Algorithm::Ecdsa {
curve: ssh_key::EcdsaCurve::NistP384,
},
comment,
)
.unwrap();
let public_key = private_key.public_key().unwrap();
(private_key, public_key)
}
#[cfg(not(any(
feature = "secp256k1",
feature = "ed25519",
feature = "pqcrypto"
)))]
_ => unreachable!(),
}
}
pub fn keypair_using(
&self,
_rng: &mut impl RandomNumberGenerator,
comment: impl Into<String>,
) -> Result<(SigningPrivateKey, SigningPublicKey)> {
#[cfg_attr(not(feature = "ssh"), allow(unused_variables))]
let comment = comment.into();
#[allow(unreachable_patterns)]
match self {
#[cfg(feature = "secp256k1")]
Self::Schnorr => {
let private_key = SigningPrivateKey::new_schnorr(
ECPrivateKey::new_using(_rng),
);
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "secp256k1")]
Self::Ecdsa => {
let private_key =
SigningPrivateKey::new_ecdsa(ECPrivateKey::new_using(_rng));
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "ed25519")]
Self::Ed25519 => {
let private_key = SigningPrivateKey::new_ed25519(
Ed25519PrivateKey::new_using(_rng),
);
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "ssh")]
Self::SshEd25519 => {
let private_key_base = PrivateKeyBase::new_using(_rng);
let private_key = private_key_base
.ssh_signing_private_key(Algorithm::Ed25519, comment)
.unwrap();
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "ssh")]
Self::SshDsa => {
let private_key_base = PrivateKeyBase::new_using(_rng);
let private_key = private_key_base
.ssh_signing_private_key(Algorithm::Dsa, comment)
.unwrap();
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "ssh")]
Self::SshEcdsaP256 => {
let private_key_base = PrivateKeyBase::new_using(_rng);
let private_key = private_key_base
.ssh_signing_private_key(
Algorithm::Ecdsa {
curve: ssh_key::EcdsaCurve::NistP256,
},
comment,
)
.unwrap();
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "ssh")]
Self::SshEcdsaP384 => {
let private_key_base = PrivateKeyBase::new_using(_rng);
let private_key = private_key_base
.ssh_signing_private_key(
Algorithm::Ecdsa {
curve: ssh_key::EcdsaCurve::NistP384,
},
comment,
)
.unwrap();
let public_key = private_key.public_key().unwrap();
Ok((private_key, public_key))
}
#[cfg(feature = "pqcrypto")]
_ => Err(Error::general(
"Deterministic keypair generation not supported for this signature scheme",
)),
#[cfg(not(any(
feature = "secp256k1",
feature = "ed25519",
feature = "pqcrypto"
)))]
_ => unreachable!(),
}
}
}