use bip32::Seed;
use std::fmt;
pub const ECDSA_SECP256K1_KEY_GENERATION_SEED_SIZE: usize = 32;
pub const ECDSA_SECP256K1_ROOT_SEED_SIZE: usize = 64;
pub const ECDSA_SECP256K1_DOMAIN_SEPARATOR: &[u8] = b"Bitcoin seed";
pub const ECDSA_SECP256K1_SIGNING_KEY_SIZE: usize = 32;
pub const ECDSA_SECP256K1_VERIFYING_KEY_SIZE: usize = 33;
pub const ECDSA_SECP256K1_SIGNATURE_SIZE: usize = 64;
pub const FALCON512_KEY_GENERATION_SEED_SIZE: usize = 32;
pub const FALCON512_ROOT_SEED_SIZE: usize = 64;
pub const FALCON512_DOMAIN_SEPARATOR: &[u8] = b"Falcon-512 seed";
pub const FALCON512_SIGNING_KEY_SIZE: usize = 1281;
pub const FALCON512_VERIFYING_KEY_SIZE: usize = 897;
pub const FALCON512_SIGNATURE_SIZE: usize = 666;
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_KEY_GENERATION_SEED_SIZE")]
pub const ML_DSA_44_KEY_GENERATION_SEED_SIZE: usize = 32;
pub const ML_DSA_65_KEY_GENERATION_SEED_SIZE: usize = 32;
pub const ML_DSA_87_KEY_GENERATION_SEED_SIZE: usize = 32;
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_ROOT_SEED_SIZE")]
pub const ML_DSA_44_ROOT_SEED_SIZE: usize = 64;
pub const ML_DSA_65_ROOT_SEED_SIZE: usize = 64;
pub const ML_DSA_87_ROOT_SEED_SIZE: usize = 64;
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_DOMAIN_SEPARATOR")]
pub const ML_DSA_44_DOMAIN_SEPARATOR: &[u8] = b"ML-DSA-44 seed";
pub const ML_DSA_65_DOMAIN_SEPARATOR: &[u8] = b"ML-DSA-65 seed";
pub const ML_DSA_87_DOMAIN_SEPARATOR: &[u8] = b"ML-DSA-87 seed";
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_SIGNING_KEY_SIZE")]
pub const ML_DSA_44_SIGNING_KEY_SIZE: usize = 2560;
pub const ML_DSA_65_SIGNING_KEY_SIZE: usize = 4032;
pub const ML_DSA_87_SIGNING_KEY_SIZE: usize = 4896;
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_VERIFYING_KEY_SIZE")]
pub const ML_DSA_44_VERIFYING_KEY_SIZE: usize = 1312;
pub const ML_DSA_65_VERIFYING_KEY_SIZE: usize = 1952;
pub const ML_DSA_87_VERIFYING_KEY_SIZE: usize = 2592;
#[deprecated(since = "0.3.0", note = "use ML_DSA_65_SIGNATURE_SIZE")]
pub const ML_DSA_44_SIGNATURE_SIZE: usize = 2420;
pub const ML_DSA_65_SIGNATURE_SIZE: usize = 3309;
pub const ML_DSA_87_SIGNATURE_SIZE: usize = 4627;
pub const MAYO_1_KEY_GENERATION_SEED_SIZE: usize = 24;
pub const MAYO_2_KEY_GENERATION_SEED_SIZE: usize = 24;
pub const MAYO_3_KEY_GENERATION_SEED_SIZE: usize = 32;
pub const MAYO_1_ROOT_SEED_SIZE: usize = 64;
pub const MAYO_2_ROOT_SEED_SIZE: usize = 64;
pub const MAYO_3_ROOT_SEED_SIZE: usize = 64;
pub const MAYO_1_DOMAIN_SEPARATOR: &[u8] = b"MAYO-1 seed";
pub const MAYO_2_DOMAIN_SEPARATOR: &[u8] = b"MAYO-2 seed";
pub const MAYO_3_DOMAIN_SEPARATOR: &[u8] = b"MAYO-3 seed";
pub const MAYO_1_SIGNING_KEY_SIZE: usize = 24;
pub const MAYO_2_SIGNING_KEY_SIZE: usize = 24;
pub const MAYO_3_SIGNING_KEY_SIZE: usize = 32;
pub const MAYO_1_VERIFYING_KEY_SIZE: usize = 1420;
pub const MAYO_2_VERIFYING_KEY_SIZE: usize = 4368;
pub const MAYO_3_VERIFYING_KEY_SIZE: usize = 2986;
pub const MAYO_1_SIGNATURE_SIZE: usize = 454;
pub const MAYO_2_SIGNATURE_SIZE: usize = 216;
pub const MAYO_3_SIGNATURE_SIZE: usize = 681;
pub const BIP44_NON_HARDENED_BASE_PATH: &str = "m/44'/60'/0'/0";
pub const BIP44_HARDENED_BASE_PATH: &str = "m/44'/60'/0'/0'";
pub enum SignatureSeed {
ECDSAsecp256k1(Seed),
Falcon512(Seed),
#[deprecated(since = "0.3.0", note = "use MlDsa65")]
MlDsa44(Seed),
MlDsa65(Seed),
MlDsa87(Seed),
Mayo1(Seed),
Mayo2(Seed),
Mayo3(Seed),
}
impl fmt::Debug for SignatureSeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let variant = match self {
SignatureSeed::ECDSAsecp256k1(_) => "ECDSAsecp256k1",
SignatureSeed::Falcon512(_) => "Falcon512",
SignatureSeed::MlDsa44(_) => "MlDsa44",
SignatureSeed::MlDsa65(_) => "MlDsa65",
SignatureSeed::MlDsa87(_) => "MlDsa87",
SignatureSeed::Mayo1(_) => "Mayo1",
SignatureSeed::Mayo2(_) => "Mayo2",
SignatureSeed::Mayo3(_) => "Mayo3",
};
let seed_bytes = self.as_seed().as_bytes().to_vec();
let masked_seed = format!("<{} bytes hidden>", seed_bytes.len());
f.debug_struct("SignatureSeed")
.field("scheme", &variant)
.field("seed", &masked_seed)
.finish()
}
}
impl SignatureSeed {
pub fn as_seed(&self) -> &Seed {
match self {
SignatureSeed::ECDSAsecp256k1(seed) => seed,
SignatureSeed::Falcon512(seed) => seed,
SignatureSeed::MlDsa44(seed) => seed,
SignatureSeed::MlDsa65(seed) => seed,
SignatureSeed::MlDsa87(seed) => seed,
SignatureSeed::Mayo1(seed) => seed,
SignatureSeed::Mayo2(seed) => seed,
SignatureSeed::Mayo3(seed) => seed,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum SignatureScheme {
EcdsaSecp256k1,
Falcon512,
#[deprecated(since = "0.3.0", note = "use MlDsa65")]
MlDsa44,
MlDsa65,
MlDsa87,
Mayo1,
Mayo2,
Mayo3,
}
impl SignatureScheme {
pub fn bip44_non_hardened_base_path(&self) -> Result<&'static str, SignatureSchemeError> {
match self {
SignatureScheme::EcdsaSecp256k1 => Ok(BIP44_NON_HARDENED_BASE_PATH),
_ => Err(SignatureSchemeError::InvalidScheme),
}
}
pub fn bip44_hardened_base_path(&self) -> Result<&'static str, SignatureSchemeError> {
match self {
SignatureScheme::EcdsaSecp256k1
| SignatureScheme::Falcon512
| SignatureScheme::MlDsa44
| SignatureScheme::MlDsa65
| SignatureScheme::MlDsa87
| SignatureScheme::Mayo1
| SignatureScheme::Mayo2
| SignatureScheme::Mayo3 => Ok(BIP44_HARDENED_BASE_PATH),
}
}
pub fn key_generation_seed_size(&self) -> usize {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_KEY_GENERATION_SEED_SIZE,
SignatureScheme::Falcon512 => FALCON512_KEY_GENERATION_SEED_SIZE,
SignatureScheme::MlDsa44 => ML_DSA_44_KEY_GENERATION_SEED_SIZE,
SignatureScheme::MlDsa65 => ML_DSA_65_KEY_GENERATION_SEED_SIZE,
SignatureScheme::MlDsa87 => ML_DSA_87_KEY_GENERATION_SEED_SIZE,
SignatureScheme::Mayo1 => MAYO_1_KEY_GENERATION_SEED_SIZE,
SignatureScheme::Mayo2 => MAYO_2_KEY_GENERATION_SEED_SIZE,
SignatureScheme::Mayo3 => MAYO_3_KEY_GENERATION_SEED_SIZE,
}
}
pub fn root_seed_size(&self) -> usize {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_ROOT_SEED_SIZE,
SignatureScheme::Falcon512 => FALCON512_ROOT_SEED_SIZE,
SignatureScheme::MlDsa44 => ML_DSA_44_ROOT_SEED_SIZE,
SignatureScheme::MlDsa65 => ML_DSA_65_ROOT_SEED_SIZE,
SignatureScheme::MlDsa87 => ML_DSA_87_ROOT_SEED_SIZE,
SignatureScheme::Mayo1 => MAYO_1_ROOT_SEED_SIZE,
SignatureScheme::Mayo2 => MAYO_2_ROOT_SEED_SIZE,
SignatureScheme::Mayo3 => MAYO_3_ROOT_SEED_SIZE,
}
}
pub fn domain_separator(&self) -> &[u8] {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_DOMAIN_SEPARATOR,
SignatureScheme::Falcon512 => FALCON512_DOMAIN_SEPARATOR,
SignatureScheme::MlDsa44 => ML_DSA_44_DOMAIN_SEPARATOR,
SignatureScheme::MlDsa65 => ML_DSA_65_DOMAIN_SEPARATOR,
SignatureScheme::MlDsa87 => ML_DSA_87_DOMAIN_SEPARATOR,
SignatureScheme::Mayo1 => MAYO_1_DOMAIN_SEPARATOR,
SignatureScheme::Mayo2 => MAYO_2_DOMAIN_SEPARATOR,
SignatureScheme::Mayo3 => MAYO_3_DOMAIN_SEPARATOR,
}
}
pub fn signing_key_size(&self) -> usize {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_SIGNING_KEY_SIZE,
SignatureScheme::Falcon512 => FALCON512_SIGNING_KEY_SIZE,
SignatureScheme::MlDsa44 => ML_DSA_44_SIGNING_KEY_SIZE,
SignatureScheme::MlDsa65 => ML_DSA_65_SIGNING_KEY_SIZE,
SignatureScheme::MlDsa87 => ML_DSA_87_SIGNING_KEY_SIZE,
SignatureScheme::Mayo1 => MAYO_1_SIGNING_KEY_SIZE,
SignatureScheme::Mayo2 => MAYO_2_SIGNING_KEY_SIZE,
SignatureScheme::Mayo3 => MAYO_3_SIGNING_KEY_SIZE,
}
}
pub fn verifying_key_size(&self) -> usize {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_VERIFYING_KEY_SIZE,
SignatureScheme::Falcon512 => FALCON512_VERIFYING_KEY_SIZE,
SignatureScheme::MlDsa44 => ML_DSA_44_VERIFYING_KEY_SIZE,
SignatureScheme::MlDsa65 => ML_DSA_65_VERIFYING_KEY_SIZE,
SignatureScheme::MlDsa87 => ML_DSA_87_VERIFYING_KEY_SIZE,
SignatureScheme::Mayo1 => MAYO_1_VERIFYING_KEY_SIZE,
SignatureScheme::Mayo2 => MAYO_2_VERIFYING_KEY_SIZE,
SignatureScheme::Mayo3 => MAYO_3_VERIFYING_KEY_SIZE,
}
}
pub fn signature_size(&self) -> usize {
match self {
SignatureScheme::EcdsaSecp256k1 => ECDSA_SECP256K1_SIGNATURE_SIZE,
SignatureScheme::Falcon512 => FALCON512_SIGNATURE_SIZE,
SignatureScheme::MlDsa44 => ML_DSA_44_SIGNATURE_SIZE,
SignatureScheme::MlDsa65 => ML_DSA_65_SIGNATURE_SIZE,
SignatureScheme::MlDsa87 => ML_DSA_87_SIGNATURE_SIZE,
SignatureScheme::Mayo1 => MAYO_1_SIGNATURE_SIZE,
SignatureScheme::Mayo2 => MAYO_2_SIGNATURE_SIZE,
SignatureScheme::Mayo3 => MAYO_3_SIGNATURE_SIZE,
}
}
}
#[derive(Clone, Copy, Debug, thiserror::Error)]
pub enum SignatureSchemeError {
#[error("Invalid derivation path: {0}")]
InvalidDerivationPath(#[from] bip32::Error),
#[error("Invalid scheme")]
InvalidScheme,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_signature_scheme_debug_display() {
let seed = Seed::new([0u8; 64]);
let signature_seed = SignatureSeed::ECDSAsecp256k1(seed);
assert_eq!(
format!("{:?}", signature_seed),
"SignatureSeed { scheme: \"ECDSAsecp256k1\", seed: \"<64 bytes hidden>\" }"
);
}
}