1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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(())
}
}