use super::KeyManager;
use crate::{error::Error, keys::PublicKey};
use universal_wallet::{contents::Content, prelude::*};
pub const CURRENT: &str = "current";
const NEXT: &str = "next";
pub const CRYPTO: &str = "crypto";
pub fn incept_keys(wallet: &mut UnlockedWallet) -> Result<(), Error> {
let mut current = KeyPair::random_pair(KeyType::Ed25519VerificationKey2018)?;
current.public_key.controller = vec![CURRENT.into()];
wallet.set_content(CURRENT, Content::KeyPair(current));
let mut next = KeyPair::random_pair(KeyType::Ed25519VerificationKey2018)?;
next.public_key.controller = vec![NEXT.into()];
wallet.set_content(NEXT, Content::KeyPair(next));
let mut crypto = KeyPair::random_pair(KeyType::X25519KeyAgreementKey2019)?;
crypto.public_key.controller = vec![CRYPTO.into()];
wallet.set_content(CRYPTO, Content::KeyPair(crypto));
Ok(())
}
fn get_public_key(wallet: &UnlockedWallet, which: &str) -> Result<PublicKey, Error> {
if let Some(key) = wallet.get_key(which) {
match key.content {
Content::KeyPair(keys) => {
let pb_key = keys.public_key.public_key;
if pb_key.is_empty() {
return Err(Error::PublicKeyError("empty public key".into()));
}
Ok(PublicKey::new(pb_key))
}
Content::Entropy(_) => Err(Error::PublicKeyError("wrong content type".into())),
Content::PublicKey(pk) => {
if pk.public_key.is_empty() {
return Err(Error::PublicKeyError("empty public key".into()));
}
Ok(PublicKey::new(pk.public_key))
}
}
} else {
Err(Error::PublicKeyError("content not found".into()))
}
}
impl KeyManager for UnlockedWallet {
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
Ok(UnlockedWallet::sign_raw(self, CURRENT, msg)?)
}
fn public_key(&self) -> Result<PublicKey, Error> {
get_public_key(self, CURRENT)
}
fn next_public_key(&self) -> Result<PublicKey, Error> {
get_public_key(self, NEXT)
}
fn rotate(&mut self) -> Result<(), Error> {
if self.next_public_key()?.is_empty() {
return Err(Error::WalletError(universal_wallet::Error::KeyNotFound));
}
if let Some(new_current_set) = self.get_content_by_controller(NEXT) {
let new_current_content = match new_current_set.clone() {
Content::KeyPair(kp) => kp.set_controller(vec![CURRENT.into()]),
_ => return Err(Error::WalletError(universal_wallet::Error::WrongKeyType)),
};
self.set_content(CURRENT, Content::KeyPair(new_current_content));
let next = KeyPair::random_pair(KeyType::Ed25519VerificationKey2018)?;
self.set_content(
NEXT,
Content::KeyPair(next.set_controller(vec![NEXT.into()])),
);
Ok(())
} else {
Err(Error::WalletError(universal_wallet::Error::KeyNotFound))
}
}
}
#[test]
fn key_inception_test() {
let mut wallet = UnlockedWallet::new("test");
incept_keys(&mut wallet).unwrap();
let next = wallet.get_content_by_controller(NEXT);
assert!(next.is_some());
match next.unwrap() {
Content::KeyPair(_) => (),
_ => panic!("next is not a KeyPair!"),
}
let current = wallet.get_content_by_controller(CURRENT);
assert!(current.is_some());
match current.unwrap() {
Content::KeyPair(_) => (),
_ => panic!("current is not a KeyPair!"),
}
let crypto = wallet.get_content_by_controller(CRYPTO);
assert!(crypto.is_some());
match crypto.unwrap() {
Content::KeyPair(_) => (),
_ => panic!("crypto is not a KeyPair!"),
}
}