use crate::kem::KemScheme;
use bip32::Seed;
use std::fmt;
pub(crate) const HQC_KEY_GENERATION_SEED_SIZE: usize = 32;
pub(crate) const HQC_ROOT_SEED_SIZE: usize = 64;
pub(crate) const HQC_HARDENED_BASE_PATH: &str = "m/44'/60'/0'/0'";
pub(crate) const HQC_128_DOMAIN_SEPARATOR: &[u8] = b"HQC-128 seed";
pub(crate) const HQC_192_DOMAIN_SEPARATOR: &[u8] = b"HQC-192 seed";
pub(crate) const HQC_256_DOMAIN_SEPARATOR: &[u8] = b"HQC-256 seed";
pub struct KemSeed {
scheme: KemScheme,
seed: Seed,
}
impl KemSeed {
pub(crate) fn new(scheme: KemScheme, seed: Seed) -> Self {
Self { scheme, seed }
}
pub fn scheme(&self) -> KemScheme {
self.scheme
}
pub fn as_seed(&self) -> &Seed {
&self.seed
}
}
impl fmt::Debug for KemSeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("KemSeed")
.field("scheme", &self.scheme)
.field("seed", &"<64 bytes hidden>")
.finish()
}
}
#[derive(Debug, thiserror::Error)]
pub enum HhdKemSchemeError {
#[error("KEM scheme '{0}' does not support HHD key derivation")]
UnsupportedScheme(KemScheme),
#[error("invalid KEM derivation path: {0}")]
InvalidDerivationPath(String),
}
pub(crate) fn ensure_hhd_supported(scheme: KemScheme) -> Result<(), HhdKemSchemeError> {
if matches!(
scheme,
KemScheme::Hqc128 | KemScheme::Hqc192 | KemScheme::Hqc256
) {
Ok(())
} else {
Err(HhdKemSchemeError::UnsupportedScheme(scheme))
}
}
pub(crate) fn domain_separator(scheme: KemScheme) -> Result<&'static [u8], HhdKemSchemeError> {
if scheme == KemScheme::Hqc128 {
Ok(HQC_128_DOMAIN_SEPARATOR)
} else if scheme == KemScheme::Hqc192 {
Ok(HQC_192_DOMAIN_SEPARATOR)
} else if scheme == KemScheme::Hqc256 {
Ok(HQC_256_DOMAIN_SEPARATOR)
} else {
Err(HhdKemSchemeError::UnsupportedScheme(scheme))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kem_seed_debug_redacts_seed_material() {
let seed = KemSeed::new(KemScheme::Hqc128, Seed::new([0x42; HQC_ROOT_SEED_SIZE]));
let debug = format!("{seed:?}");
assert!(debug.contains("Hqc128"));
assert!(debug.contains("<64 bytes hidden>"));
assert!(!debug.contains("42, 42"));
assert_eq!(seed.scheme(), KemScheme::Hqc128);
assert_eq!(seed.as_seed().as_bytes(), &[0x42; HQC_ROOT_SEED_SIZE]);
}
}