use crate::{hybrid::HybridCiphertext, privacy_tiers::PrivacyTier, signature::DigitalSignature};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HandshakeMessage {
pub version: u8,
pub sender_id: Vec<u8>,
pub mlkem_pubkey: Vec<u8>,
pub x25519_pubkey: Option<Vec<u8>>,
pub suites: Vec<CipherSuite>,
pub nonce: [u8; 32],
pub encap_ct: Option<HybridCiphertext>,
pub signature: Option<DigitalSignature>,
pub privacy_tier: Option<PrivacyTier>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CipherSuite {
pub kem: String, pub sig: String, pub aead: String, pub kdf: String, }
impl CipherSuite {
pub fn default_pqc() -> Self {
Self {
kem: "ML-KEM-768".to_string(),
sig: "ML-DSA-65".to_string(),
aead: "ChaCha20-Poly1305".to_string(),
kdf: "HKDF-SHA384".to_string(),
}
}
pub fn default_hybrid() -> Self {
Self {
kem: "ML-KEM-768+X25519".to_string(),
sig: "ML-DSA-65".to_string(),
aead: "ChaCha20-Poly1305".to_string(),
kdf: "HKDF-SHA384".to_string(),
}
}
pub fn legacy() -> Self {
Self {
kem: "X25519".to_string(),
sig: "Ed25519".to_string(),
aead: "ChaCha20-Poly1305".to_string(),
kdf: "HKDF-SHA256".to_string(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyReleaseRequest {
pub lease_id: String,
pub node_mode: NodeMode,
pub node_id: String,
pub eid: Option<String>, pub attestation: Option<AttestationBundle>,
pub mlkem_encap_key: Vec<u8>,
pub privacy_tier: PrivacyTier,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NodeMode {
SoftwareOnly,
SimOnly,
SimTee,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttestationBundle {
pub cpu_quote: Option<CpuQuote>,
pub gpu_quote: Option<GpuQuote>,
pub measurement: Vec<u8>,
pub policy_hash: [u8; 32],
pub timestamp: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CpuQuote {
pub quote_type: CpuTeeType,
pub quote_data: Vec<u8>,
pub report_data: Vec<u8>,
pub measurement: Vec<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CpuTeeType {
SevSnp,
Tdx,
Sgx,
ArmCca,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GpuQuote {
pub gpu_type: GpuType,
pub nras_token: Vec<u8>,
pub device_id: Vec<u8>,
pub cc_enabled: bool,
pub tee_io_enabled: bool,
pub mig_uuid: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum GpuType {
H100,
Blackwell,
Other,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyReleaseResponse {
pub enc_dek: Vec<u8>, pub aead_alg: String,
pub key_release_cert: KeyReleaseCertificate,
pub capability_token: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyReleaseCertificate {
pub lease_id: String,
pub node_id: String,
pub measurement: Option<Vec<u8>>,
pub timestamp: u64,
pub orr_digest: Vec<u8>, pub privacy_tier: PrivacyTier,
pub signature: DigitalSignature, }
pub struct HandshakeTranscript {
messages: Vec<Vec<u8>>,
}
impl HandshakeTranscript {
pub fn new() -> Self {
Self {
messages: Vec::new(),
}
}
pub fn add_message(&mut self, msg: &[u8]) {
self.messages.push(msg.to_vec());
}
pub fn get_hash(&self) -> [u8; 32] {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
for msg in &self.messages {
hasher.update(&(msg.len() as u32).to_be_bytes());
hasher.update(msg);
}
hasher.finalize().into()
}
}
pub mod constants {
pub const PROTOCOL_VERSION: u8 = 1;
pub const MAX_HANDSHAKE_SIZE: usize = 16384;
pub const SESSION_TIMEOUT: u64 = 3600;
pub const LABEL_HANDSHAKE: &str = "hanzo-pqc-handshake-v1";
pub const LABEL_KEY_RELEASE: &str = "hanzo-pqc-key-release-v1";
pub const LABEL_HYBRID_KEX: &str = "hanzo-hybrid-v1";
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cipher_suites() {
let pqc = CipherSuite::default_pqc();
assert_eq!(pqc.kem, "ML-KEM-768");
assert_eq!(pqc.sig, "ML-DSA-65");
let hybrid = CipherSuite::default_hybrid();
assert!(hybrid.kem.contains("X25519"));
}
#[test]
fn test_transcript_hash() {
let mut transcript = HandshakeTranscript::new();
transcript.add_message(b"message1");
transcript.add_message(b"message2");
let hash1 = transcript.get_hash();
let mut transcript2 = HandshakeTranscript::new();
transcript2.add_message(b"message1");
transcript2.add_message(b"message2");
assert_eq!(hash1, transcript2.get_hash());
}
}