Documentation
use crylib::hash::Sha256;
use crylib::hkdf;

const LABEL_PREFIX: &'static [u8] = b"tls13 ";
const MAX_LABEL_LEN: usize = 12;

pub(crate) fn hkdf_expand_label(
    key: &mut [u8],
    secret: &[u8; Sha256::HASH_SIZE],
    label: &[u8],
    context: &[u8],
) {
    assert!(label.len() <= MAX_LABEL_LEN);
    assert!(context.len() <= Sha256::HASH_SIZE);

    let mut hkdf_label = [0; size_of::<u16>()
        + 2 * size_of::<u8>()
        + LABEL_PREFIX.len()
        + MAX_LABEL_LEN
        + Sha256::HASH_SIZE];

    let mut pos = 0;
    hkdf_label[pos..][..size_of::<u16>()].copy_from_slice(&(key.len() as u16).to_be_bytes());
    pos += size_of::<u16>();

    hkdf_label[pos] = (LABEL_PREFIX.len() + label.len()) as u8;
    pos += 1;

    hkdf_label[pos..][..LABEL_PREFIX.len()].copy_from_slice(LABEL_PREFIX);
    pos += LABEL_PREFIX.len();

    hkdf_label[pos..][..label.len()].copy_from_slice(label);
    pos += label.len();

    hkdf_label[pos] = context.len() as u8;
    pos += 1;

    hkdf_label[pos..][..context.len()].copy_from_slice(context);
    pos += context.len();

    hkdf::expand::<{ Sha256::HASH_SIZE }, { Sha256::BLOCK_SIZE }, Sha256>(
        key,
        secret,
        &hkdf_label[..pos],
    );
}

pub(crate) fn derive_secret(
    secret: &[u8; Sha256::HASH_SIZE],
    label: &[u8],
    transcript: &[u8; Sha256::HASH_SIZE],
) -> [u8; Sha256::HASH_SIZE] {
    let mut derived = [0; Sha256::HASH_SIZE];
    hkdf_expand_label(&mut derived, secret, label, transcript);
    derived
}