use std::path::Path;
use tape_api::program::tapedrive::tape_pda;
use tape_crypto::address::Address;
use tape_crypto::ed25519::{Keypair, Pubkey};
use crate::keys::helpers::{load_ed25519_keypair, load_ed25519_keypair_bytes, HelperError};
pub struct TapeKey {
keypair: Keypair,
}
impl TapeKey {
pub fn generate() -> Self {
let mut rng = rand::thread_rng();
Self {
keypair: Keypair::new(&mut rng),
}
}
pub fn load(path: impl AsRef<Path>) -> Result<Self, HelperError> {
let keypair = load_ed25519_keypair(path.as_ref())?;
Ok(Self { keypair })
}
pub fn from_json_bytes(bytes: &[u8]) -> Result<Self, HelperError> {
let keypair = load_ed25519_keypair_bytes(bytes)?;
Ok(Self { keypair })
}
pub fn save(&self, path: impl AsRef<Path>) -> Result<(), std::io::Error> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() {
std::fs::create_dir_all(parent)?;
}
}
let file = std::fs::File::create(path)?;
serde_json::to_writer(file, &self.keypair.to_keypair_bytes().to_vec())
.map_err(std::io::Error::other)
}
pub fn address(&self) -> Address {
tape_pda(self.keypair.address()).0
}
pub fn pubkey(&self) -> Pubkey {
self.keypair.pubkey()
}
pub fn keypair(&self) -> &Keypair {
&self.keypair
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate() {
let key = TapeKey::generate();
assert_eq!(key.address(), tape_pda(key.pubkey().into()).0);
}
#[test]
fn save_and_load() {
let dir = std::env::temp_dir().join("tape_key_test");
let path = dir.join("test.json");
let original = TapeKey::generate();
original.save(&path).unwrap();
let loaded = TapeKey::load(&path).unwrap();
assert_eq!(original.pubkey(), loaded.pubkey());
assert_eq!(original.address(), loaded.address());
std::fs::remove_dir_all(dir).ok();
}
#[test]
fn loads_from_json_bytes() {
let original = TapeKey::generate();
let json = serde_json::to_vec(&original.keypair.to_keypair_bytes().to_vec()).unwrap();
let loaded = TapeKey::from_json_bytes(&json).unwrap();
assert_eq!(original.pubkey(), loaded.pubkey());
assert_eq!(original.address(), loaded.address());
}
}