use hkdf::Hkdf;
use sha2::Sha256;
use zeroize::{Zeroize, Zeroizing};
#[derive(Clone, Debug, Zeroize)]
#[zeroize(drop)]
pub struct HybridSharedSecret {
bytes: Vec<u8>,
}
impl HybridSharedSecret {
pub fn new(bytes: Vec<u8>) -> Self {
Self { bytes }
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
pub fn derive_hybrid_secret(
pqc_secret: &[u8],
classical_secret: &[u8],
context: &[u8],
) -> HybridSharedSecret {
let mut ikm = Zeroizing::new(Vec::with_capacity(
pqc_secret.len() + classical_secret.len(),
));
ikm.extend_from_slice(pqc_secret);
ikm.extend_from_slice(classical_secret);
let hk = Hkdf::<Sha256>::new(Some(context), &ikm);
let mut okm = vec![0u8; 32];
hk.expand(b"oqs-safe hybrid derived secret", &mut okm)
.expect("hkdf expand failure");
HybridSharedSecret::new(okm)
}
pub fn derive_hybrid_secret_with_len(
pqc_secret: &[u8],
classical_secret: &[u8],
context: &[u8],
out_len: usize,
) -> HybridSharedSecret {
let mut ikm = Zeroizing::new(Vec::with_capacity(
pqc_secret.len() + classical_secret.len(),
));
ikm.extend_from_slice(pqc_secret);
ikm.extend_from_slice(classical_secret);
let hk = Hkdf::<Sha256>::new(Some(context), &ikm);
let mut okm = vec![0u8; out_len];
hk.expand(b"oqs-safe hybrid derived secret", &mut okm)
.expect("hkdf expand failure");
HybridSharedSecret::new(okm)
}