use super::Safe;
use crate::{Error, Result, SafeUrl};
use bls::SecretKey as BlsSecretKey;
use sn_interface::types::{Keypair, SecretKey};
use hex::encode;
use std::path::Path;
use xor_name::XorName;
impl Safe {
pub async fn validate_sk_for_url(&self, secret_key: &SecretKey, url: &str) -> Result<String> {
let derived_xorname = match secret_key {
SecretKey::Ed25519(sk) => {
let pk: ed25519_dalek::PublicKey = sk.into();
XorName(pk.to_bytes())
}
_ => {
return Err(Error::InvalidInput(
"Cannot form a keypair from a BlsKeyShare at this time.".to_string(),
))
}
};
let safeurl = self.parse_and_resolve_url(url).await?;
if safeurl.xorname() != derived_xorname {
Err(Error::InvalidInput(
"The URL doesn't correspond to the public key derived from the provided secret key"
.to_string(),
))
} else {
Ok(encode(derived_xorname))
}
}
pub fn new_keypair_with_pk_url(&self) -> Result<(Keypair, SafeUrl)> {
let keypair = Keypair::new_bls();
let xorname = XorName::from(keypair.public_key());
let url = SafeUrl::from_safekey(xorname)?;
Ok((keypair, url))
}
pub fn serialize_bls_key(secret_key: &BlsSecretKey, path: impl AsRef<Path>) -> Result<()> {
let hex = secret_key.to_hex();
std::fs::write(&path, hex)?;
Ok(())
}
pub fn deserialize_bls_key(path: impl AsRef<Path>) -> Result<BlsSecretKey> {
let hex = std::fs::read_to_string(path)?;
Ok(BlsSecretKey::from_hex(&hex)?)
}
}
#[cfg(test)]
mod tests {
use super::{Safe, SafeUrl};
use sn_interface::types::Keypair;
use assert_fs::prelude::*;
use bls::SecretKey as BlsSecretKey;
use color_eyre::{eyre::eyre, Result};
use predicates::prelude::*;
use xor_name::XorName;
#[test]
fn new_keypair_should_generate_bls_keypair() -> Result<()> {
let safe = Safe::dry_runner(None);
let (keypair, url) = safe.new_keypair_with_pk_url()?;
let xorname = XorName::from(keypair.public_key());
let url2 = SafeUrl::from_safekey(xorname)?;
assert_eq!(url, url2);
match keypair {
Keypair::Bls(_) => Ok(()),
_ => Err(eyre!("A BLS keypair should be generated by default.")),
}
}
#[test]
fn serialize_keypair_should_serialize_a_bls_keypair_to_file() -> Result<()> {
let tmp_dir = assert_fs::TempDir::new()?;
let serialized_keypair_file = tmp_dir.child("serialized_keypair");
let sk = BlsSecretKey::random();
Safe::serialize_bls_key(&sk, serialized_keypair_file.path())?;
serialized_keypair_file.assert(predicate::path::is_file());
let sk_hex = std::fs::read_to_string(serialized_keypair_file.path())?;
let sk2 = BlsSecretKey::from_hex(&sk_hex)?;
assert_eq!(sk, sk2);
Ok(())
}
#[test]
fn deserialize_keypair_should_deserialize_a_bls_keypair_from_file() -> Result<()> {
let tmp_dir = assert_fs::TempDir::new()?;
let serialized_keypair_file = tmp_dir.child("serialized_keypair");
let sk = BlsSecretKey::random();
Safe::serialize_bls_key(&sk, serialized_keypair_file.path())?;
let sk2 = Safe::deserialize_bls_key(serialized_keypair_file.path())?;
assert_eq!(sk, sk2);
Ok(())
}
}