use ed25519_dalek::{Signature, Signer, SigningKey};
use provn_sdk::{sign_claim, Claim};
use sha2::{Digest, Sha256};
use uuid::Uuid;
use zeroize::Zeroize;
#[derive(Debug, Zeroize, Clone)]
#[zeroize(drop)]
pub struct AttestAgent {
#[zeroize(skip)]
pub signing_key: SigningKey,
#[zeroize(skip)]
pub id: String, pub sealed_seed: Option<Vec<u8>>,
}
impl AttestAgent {
pub fn new() -> Self {
let signing_key = provn_sdk::generate_keypair();
let id = format!(
"aid:ed25519:{}",
hex::encode(signing_key.verifying_key().to_bytes())
);
Self {
signing_key,
id,
sealed_seed: None,
}
}
pub fn from_seed(mut seed: [u8; 32]) -> Self {
let signing_key = SigningKey::from_bytes(&seed);
seed.zeroize();
let id = format!(
"aid:ed25519:{}",
hex::encode(signing_key.verifying_key().to_bytes())
);
Self {
signing_key,
id,
sealed_seed: None,
}
}
pub fn with_sealed_seed(mut self, sealed_seed: Vec<u8>) -> Self {
self.sealed_seed = Some(sealed_seed);
self
}
pub fn to_vex_uuid(&self) -> Uuid {
let mut hasher = Sha256::new();
hasher.update(self.signing_key.verifying_key().as_bytes());
let hash = hasher.finalize();
Uuid::from_slice(&hash[..16]).expect("Hash slice must be 16 bytes")
}
pub fn sign_claim(&self, data: String) -> provn_sdk::SignedClaim {
let claim = Claim::new(data);
sign_claim(&claim, &self.signing_key).expect("Ecosystem signing failure")
}
pub fn sign(&self, data: &[u8]) -> Signature {
self.signing_key.sign(data)
}
}
impl Default for AttestAgent {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_identity_alignment() {
let agent = AttestAgent::new();
let vex_id = agent.to_vex_uuid();
println!("Attest ID: {}", agent.id);
println!("VEX Context ID: {}", vex_id);
assert_eq!(vex_id, agent.to_vex_uuid());
}
#[test]
fn test_sdk_signing() {
let agent = AttestAgent::new();
let payload = "agent-did-something".to_string();
let signed = agent.sign_claim(payload);
println!("Signature: {}", signed.signature);
assert!(provn_sdk::verify_claim(&signed).unwrap());
}
}