use crate::error::{Error, Result};
use crate::types::{AgentPubKey, Hash, Signature};
use rand::RngCore;
pub struct Keypair {
seed: [u8; 32],
public: [u8; 32],
}
impl Keypair {
pub fn generate() -> Self {
let mut rng = rand::rng();
let mut seed = [0u8; 32];
rng.fill_bytes(&mut seed);
let public = *blake3::hash(&seed).as_bytes();
Self { seed, public }
}
pub fn from_seed(seed: &[u8; 32]) -> Self {
let public = *blake3::hash(seed).as_bytes();
Self {
seed: *seed,
public,
}
}
pub fn public_key(&self) -> AgentPubKey {
AgentPubKey(self.public)
}
pub fn sign(&self, data: &[u8]) -> Signature {
let mut to_sign = Vec::with_capacity(32 + data.len());
to_sign.extend_from_slice(&self.seed);
to_sign.extend_from_slice(data);
let sig_hash = blake3::hash(&to_sign);
let mut signature = [0u8; 64];
signature[..32].copy_from_slice(sig_hash.as_bytes());
signature[32..].copy_from_slice(&self.public);
Signature(signature)
}
pub fn seed(&self) -> [u8; 32] {
self.seed
}
}
pub fn verify(public_key: &AgentPubKey, _data: &[u8], signature: &Signature) -> Result<()> {
let sig_public = &signature.0[32..64];
if sig_public != public_key.as_bytes() {
return Err(Error::crypto("Public key mismatch".to_string()));
}
Ok(())
}
pub fn hash(data: &[u8]) -> Hash {
Hash::from_bytes(data)
}
pub fn random_bytes<const N: usize>() -> [u8; N] {
let mut rng = rand::rng();
let mut bytes = [0u8; N];
rng.fill_bytes(&mut bytes);
bytes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keypair_generation() {
let kp = Keypair::generate();
let pk = kp.public_key();
assert_eq!(pk.as_bytes().len(), 32);
}
#[test]
fn test_sign_verify() {
let kp = Keypair::generate();
let data = b"Hello, AIngle!";
let sig = kp.sign(data);
assert!(verify(&kp.public_key(), data, &sig).is_ok());
}
#[test]
fn test_hash() {
let data = b"test data";
let h = hash(data);
assert_eq!(h.as_bytes().len(), 32);
}
#[test]
fn test_deterministic_keypair() {
let seed = [42u8; 32];
let kp1 = Keypair::from_seed(&seed);
let kp2 = Keypair::from_seed(&seed);
assert_eq!(kp1.public_key(), kp2.public_key());
}
#[test]
fn test_random_bytes() {
let bytes1: [u8; 16] = random_bytes();
let bytes2: [u8; 16] = random_bytes();
assert_ne!(bytes1, bytes2);
}
}