pub use lichen_core::{Address, Keypair as CoreKeypair, PqPublicKey, PqSignature, Pubkey};
pub struct Keypair(CoreKeypair);
impl Keypair {
pub fn new() -> Self {
Self(CoreKeypair::new())
}
pub fn from_seed(seed: &[u8; 32]) -> Self {
Self(CoreKeypair::from_seed(seed))
}
pub fn pubkey(&self) -> Pubkey {
self.0.pubkey()
}
pub fn public_key(&self) -> PqPublicKey {
self.0.public_key()
}
pub fn to_seed(&self) -> [u8; 32] {
self.0.to_seed()
}
pub fn sign(&self, message: &[u8]) -> PqSignature {
self.0.sign(message)
}
pub fn verify(address: &Pubkey, message: &[u8], signature: &PqSignature) -> bool {
CoreKeypair::verify(address, message, signature)
}
pub fn inner(&self) -> &CoreKeypair {
&self.0
}
}
impl Default for Keypair {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_keypair_has_unique_pubkey() {
let kp1 = Keypair::new();
let kp2 = Keypair::new();
assert_ne!(kp1.pubkey(), kp2.pubkey());
}
#[test]
fn from_seed_deterministic() {
let seed = [42u8; 32];
let kp1 = Keypair::from_seed(&seed);
let kp2 = Keypair::from_seed(&seed);
assert_eq!(kp1.pubkey(), kp2.pubkey());
}
#[test]
fn different_seeds_different_keys() {
let kp1 = Keypair::from_seed(&[1u8; 32]);
let kp2 = Keypair::from_seed(&[2u8; 32]);
assert_ne!(kp1.pubkey(), kp2.pubkey());
}
#[test]
fn to_seed_roundtrip() {
let seed = [99u8; 32];
let kp = Keypair::from_seed(&seed);
assert_eq!(kp.to_seed(), seed);
}
#[test]
fn public_key_roundtrip_matches_address() {
let kp = Keypair::new();
assert_eq!(kp.public_key().address(), kp.pubkey());
}
#[test]
fn sign_produces_valid_pq_signature() {
let kp = Keypair::new();
let sig = kp.sign(b"hello lichen");
assert!(sig.validate().is_ok());
assert_eq!(sig.signer_address(), kp.pubkey());
assert!(sig.sig.len() > 64);
}
#[test]
fn sign_deterministic() {
let kp = Keypair::from_seed(&[7u8; 32]);
let sig1 = kp.sign(b"msg");
let sig2 = kp.sign(b"msg");
assert_eq!(sig1, sig2);
}
#[test]
fn sign_different_messages_differ() {
let kp = Keypair::new();
let sig1 = kp.sign(b"aaa");
let sig2 = kp.sign(b"bbb");
assert_ne!(sig1, sig2);
}
#[test]
fn inner_returns_core_keypair() {
let kp = Keypair::from_seed(&[5u8; 32]);
assert_eq!(kp.inner().pubkey(), kp.pubkey());
}
#[test]
fn verify_accepts_self_contained_signature() {
let kp = Keypair::from_seed(&[6u8; 32]);
let message = b"pq rust sdk";
let signature = kp.sign(message);
assert!(Keypair::verify(&kp.pubkey(), message, &signature));
assert!(!Keypair::verify(&kp.pubkey(), b"tampered", &signature));
}
#[test]
fn default_works() {
let kp = Keypair::default();
let _ = kp.pubkey();
}
#[test]
fn pubkey_is_32_bytes() {
let kp = Keypair::new();
assert_eq!(kp.pubkey().0.len(), 32);
}
}