quadra-a-core 0.1.0-beta.1

Core protocol primitives for the quadra-a agent network
Documentation
use anyhow::{Context, Result};

use crate::e2e::crypto::{diffie_hellman_x25519, hkdf_sha256};
use crate::e2e::types::{X3DH_INFO, X3DH_SALT};

fn derive_shared_secret(parts: Vec<[u8; 32]>) -> Result<Vec<u8>> {
    let mut combined = Vec::with_capacity(parts.len() * 32);
    for part in parts {
        combined.extend_from_slice(&part);
    }

    hkdf_sha256(&combined, X3DH_SALT.as_bytes(), X3DH_INFO.as_bytes(), 32)
        .context("Failed to derive X3DH shared secret")
}

pub fn derive_x3dh_initiator_shared_secret(
    initiator_identity_private: &[u8],
    initiator_ephemeral_private: &[u8],
    recipient_identity_public: &[u8],
    recipient_signed_pre_key_public: &[u8],
    recipient_one_time_pre_key_public: Option<&[u8]>,
) -> Result<Vec<u8>> {
    let mut parts = vec![
        diffie_hellman_x25519(initiator_identity_private, recipient_signed_pre_key_public)?,
        diffie_hellman_x25519(initiator_ephemeral_private, recipient_identity_public)?,
        diffie_hellman_x25519(initiator_ephemeral_private, recipient_signed_pre_key_public)?,
    ];

    if let Some(one_time_pre_key_public) = recipient_one_time_pre_key_public {
        parts.push(diffie_hellman_x25519(
            initiator_ephemeral_private,
            one_time_pre_key_public,
        )?);
    }

    derive_shared_secret(parts)
}

pub fn derive_x3dh_responder_shared_secret(
    recipient_identity_private: &[u8],
    recipient_signed_pre_key_private: &[u8],
    initiator_identity_public: &[u8],
    initiator_ephemeral_public: &[u8],
    recipient_one_time_pre_key_private: Option<&[u8]>,
) -> Result<Vec<u8>> {
    let mut parts = vec![
        diffie_hellman_x25519(recipient_signed_pre_key_private, initiator_identity_public)?,
        diffie_hellman_x25519(recipient_identity_private, initiator_ephemeral_public)?,
        diffie_hellman_x25519(recipient_signed_pre_key_private, initiator_ephemeral_public)?,
    ];

    if let Some(one_time_pre_key_private) = recipient_one_time_pre_key_private {
        parts.push(diffie_hellman_x25519(
            one_time_pre_key_private,
            initiator_ephemeral_public,
        )?);
    }

    derive_shared_secret(parts)
}