2021-03-22 19:20:51 +01:00
|
|
|
extern crate rand;
|
|
|
|
|
extern crate ed25519_dalek;
|
2019-12-01 22:45:25 +01:00
|
|
|
extern crate serde;
|
2021-01-18 00:18:35 +01:00
|
|
|
extern crate serde_json;
|
|
|
|
|
|
2021-03-10 22:21:50 +01:00
|
|
|
use std::thread;
|
2021-01-18 00:18:35 +01:00
|
|
|
use std::fs;
|
|
|
|
|
use std::fs::File;
|
2021-02-14 18:20:30 +01:00
|
|
|
use std::io::Write;
|
2019-12-01 22:45:25 +01:00
|
|
|
use std::path::Path;
|
2021-03-10 22:21:50 +01:00
|
|
|
use std::sync::{Arc, atomic, Mutex};
|
|
|
|
|
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
|
|
|
|
|
2021-03-22 19:20:51 +01:00
|
|
|
use ed25519_dalek::Keypair;
|
2021-02-21 21:56:56 +01:00
|
|
|
#[allow(unused_imports)]
|
2021-03-10 22:21:50 +01:00
|
|
|
use log::{debug, error, info, trace, warn};
|
|
|
|
|
|
|
|
|
|
use crate::blockchain::hash_utils::*;
|
2021-03-21 14:34:32 +01:00
|
|
|
use crate::Context;
|
2021-03-10 22:21:50 +01:00
|
|
|
use crate::event::Event;
|
2021-03-21 01:31:33 +01:00
|
|
|
use crate::commons::KEYSTORE_DIFFICULTY;
|
2021-03-10 22:21:50 +01:00
|
|
|
use crate::bytes::Bytes;
|
|
|
|
|
use blakeout::Blakeout;
|
|
|
|
|
use std::time::Instant;
|
|
|
|
|
use std::cell::RefCell;
|
2021-03-22 19:20:51 +01:00
|
|
|
use self::ed25519_dalek::{Signer, PublicKey, Verifier, SecretKey};
|
|
|
|
|
use self::ed25519_dalek::ed25519::signature::Signature;
|
|
|
|
|
use rand_old::{CryptoRng, RngCore};
|
|
|
|
|
use rand_old::rngs::OsRng;
|
2019-12-01 22:45:25 +01:00
|
|
|
|
2021-03-22 19:20:51 +01:00
|
|
|
#[derive(Debug)]
|
2020-04-18 21:31:40 +02:00
|
|
|
pub struct Keystore {
|
2021-03-22 19:20:51 +01:00
|
|
|
keypair: Keypair,
|
2021-03-10 22:21:50 +01:00
|
|
|
hash: RefCell<Bytes>,
|
2021-02-15 23:09:30 +01:00
|
|
|
path: String,
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-04-18 21:31:40 +02:00
|
|
|
impl Keystore {
|
2019-12-01 22:45:25 +01:00
|
|
|
pub fn new() -> Self {
|
2021-03-22 19:20:51 +01:00
|
|
|
let mut csprng = OsRng::default();
|
|
|
|
|
let keypair = ed25519_dalek::Keypair::generate(&mut csprng);
|
|
|
|
|
Keystore { keypair, hash: RefCell::new(Bytes::default()), path: String::new() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from_random<R>(csprng: &mut R) -> Self where R: CryptoRng + RngCore {
|
|
|
|
|
let keypair = ed25519_dalek::Keypair::generate(csprng);
|
|
|
|
|
Keystore { keypair, hash: RefCell::new(Bytes::default()), path: String::new() }
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from_bytes(seed: &[u8]) -> Self {
|
2021-03-22 19:20:51 +01:00
|
|
|
let keypair = Keypair::from_bytes(seed).expect("Error creating keypair from bytes!");
|
|
|
|
|
Keystore { keypair, hash: RefCell::new(Bytes::default()), path: String::new() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from_random_bytes(key: &[u8]) -> Self {
|
|
|
|
|
let secret = SecretKey::from_bytes(&key).unwrap();
|
|
|
|
|
let public = PublicKey::from(&secret);
|
|
|
|
|
let keypair = Keypair { secret, public };
|
|
|
|
|
Keystore { keypair, hash: RefCell::new(Bytes::default()), path: String::new() }
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from_file(filename: &str, _password: &str) -> Option<Self> {
|
2021-02-15 23:09:30 +01:00
|
|
|
let path = Path::new(filename);
|
|
|
|
|
match fs::read(&path) {
|
2019-12-01 22:45:25 +01:00
|
|
|
Ok(key) => {
|
2021-03-22 19:20:51 +01:00
|
|
|
if key.len() == 32 {
|
|
|
|
|
return Some(Keystore::from_random_bytes(key.as_slice()));
|
|
|
|
|
}
|
2021-02-15 23:09:30 +01:00
|
|
|
let mut keystore = Self::from_bytes(key.as_slice());
|
|
|
|
|
keystore.path = path.to_str().unwrap().to_owned();
|
|
|
|
|
Some(keystore)
|
2021-03-07 02:12:00 +01:00
|
|
|
}
|
2019-12-01 22:45:25 +01:00
|
|
|
Err(_) => {
|
|
|
|
|
None
|
2021-03-07 02:12:00 +01:00
|
|
|
}
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-15 23:09:30 +01:00
|
|
|
pub fn save(&mut self, filename: &str, _password: &str) {
|
2021-01-18 00:18:35 +01:00
|
|
|
match File::create(Path::new(filename)) {
|
|
|
|
|
Ok(mut f) => {
|
|
|
|
|
//TODO implement key encryption
|
2021-03-22 19:20:51 +01:00
|
|
|
let bytes = self.keypair.to_bytes();
|
|
|
|
|
f.write_all(&bytes).expect("Error saving keystore");
|
2021-02-15 23:09:30 +01:00
|
|
|
self.path = filename.to_owned();
|
2021-01-18 00:18:35 +01:00
|
|
|
}
|
2021-02-20 16:28:10 +01:00
|
|
|
Err(_) => { error!("Error saving key file!"); }
|
2021-01-18 00:18:35 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_public(&self) -> Bytes {
|
2021-03-22 19:20:51 +01:00
|
|
|
Bytes::from_bytes(&self.keypair.public.to_bytes())
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-18 00:18:35 +01:00
|
|
|
pub fn get_private(&self) -> Bytes {
|
2021-03-22 19:20:51 +01:00
|
|
|
Bytes::from_bytes(&self.keypair.secret.to_bytes())
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-15 23:09:30 +01:00
|
|
|
pub fn get_path(&self) -> &str {
|
|
|
|
|
&self.path
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 22:21:50 +01:00
|
|
|
pub fn get_hash(&self) -> Bytes {
|
|
|
|
|
if self.hash.borrow().is_empty() {
|
2021-03-22 19:20:51 +01:00
|
|
|
self.hash.replace(blakeout_data(&self.get_public()));
|
2021-03-10 22:21:50 +01:00
|
|
|
}
|
|
|
|
|
self.hash.borrow().clone()
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-01 22:45:25 +01:00
|
|
|
pub fn sign(&self, message: &[u8]) -> [u8; 64] {
|
2021-03-22 19:20:51 +01:00
|
|
|
self.keypair.sign(message).to_bytes()
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-14 18:20:30 +01:00
|
|
|
pub fn check(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
|
2021-03-22 19:20:51 +01:00
|
|
|
let key = PublicKey::from_bytes(public_key).expect("Wrong public key!");
|
|
|
|
|
let signature = Signature::from_bytes(signature).unwrap();
|
|
|
|
|
match key.verify(message, &signature) {
|
|
|
|
|
Ok(_) => { true }
|
|
|
|
|
Err(_) => { false }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Clone for Keystore {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
let keypair = Keypair::from_bytes(&self.keypair.to_bytes()).unwrap();
|
|
|
|
|
Self { keypair, hash: RefCell::new(Bytes::default()), path: self.path.clone() }
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-12 01:36:54 +01:00
|
|
|
/// Checks if some public key is "strong" enough to mine domains
|
|
|
|
|
/// TODO Optimize by caching Blakeout somewhere
|
|
|
|
|
pub fn check_public_key_strength(key: &Bytes, strength: usize) -> bool {
|
2021-03-22 19:20:51 +01:00
|
|
|
let bytes = blakeout_data(&key);
|
2021-03-12 01:36:54 +01:00
|
|
|
hash_is_good(&bytes, strength)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 22:21:50 +01:00
|
|
|
pub fn create_key(context: Arc<Mutex<Context>>) {
|
|
|
|
|
let mining = Arc::new(AtomicBool::new(true));
|
|
|
|
|
let miners_count = Arc::new(AtomicUsize::new(0));
|
|
|
|
|
{ context.lock().unwrap().bus.post(Event::KeyGeneratorStarted); }
|
2021-03-21 14:34:32 +01:00
|
|
|
for _cpu in 0..num_cpus::get() {
|
2021-03-23 11:41:50 +01:00
|
|
|
let context = Arc::clone(&context);
|
2021-03-10 22:21:50 +01:00
|
|
|
let mining = mining.clone();
|
|
|
|
|
let miners_count = miners_count.clone();
|
|
|
|
|
thread::spawn(move || {
|
|
|
|
|
miners_count.fetch_add(1, atomic::Ordering::SeqCst);
|
|
|
|
|
match generate_key(KEYSTORE_DIFFICULTY, mining.clone()) {
|
|
|
|
|
None => {
|
|
|
|
|
debug!("Keystore mining finished");
|
|
|
|
|
}
|
|
|
|
|
Some(keystore) => {
|
|
|
|
|
mining.store(false, atomic::Ordering::SeqCst);
|
|
|
|
|
let mut context = context.lock().unwrap();
|
|
|
|
|
let hash = keystore.get_hash().to_string();
|
|
|
|
|
info!("Key mined successfully: {:?}, hash: {}", &keystore.get_public(), &hash);
|
|
|
|
|
context.bus.post(Event::KeyCreated { path: keystore.get_path().to_owned(), public: keystore.get_public().to_string(), hash });
|
|
|
|
|
context.set_keystore(keystore);
|
|
|
|
|
}
|
2021-01-14 18:34:43 +01:00
|
|
|
}
|
2021-03-10 22:21:50 +01:00
|
|
|
let miners = miners_count.fetch_sub(1, atomic::Ordering::SeqCst) - 1;
|
|
|
|
|
if miners == 0 {
|
|
|
|
|
context.lock().unwrap().bus.post(Event::KeyGeneratorStopped);
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
2021-03-10 22:21:50 +01:00
|
|
|
context.lock().unwrap().bus.register(move |_uuid, e| {
|
|
|
|
|
if e == Event::ActionStopMining {
|
|
|
|
|
info!("Stopping keystore miner");
|
|
|
|
|
mining.store(false, atomic::Ordering::SeqCst);
|
|
|
|
|
false
|
2019-12-01 22:45:25 +01:00
|
|
|
} else {
|
2021-03-10 22:21:50 +01:00
|
|
|
true
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
2021-03-10 22:21:50 +01:00
|
|
|
});
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-10 22:21:50 +01:00
|
|
|
fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore> {
|
2021-03-22 19:20:51 +01:00
|
|
|
use self::rand::RngCore;
|
2021-03-10 22:21:50 +01:00
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
let mut time = Instant::now();
|
|
|
|
|
let mut count = 0u128;
|
2021-03-22 19:20:51 +01:00
|
|
|
let mut digest = Blakeout::default();
|
|
|
|
|
let mut buf = [0u8; 32];
|
2021-03-10 22:21:50 +01:00
|
|
|
loop {
|
|
|
|
|
rng.fill_bytes(&mut buf);
|
2021-03-22 19:20:51 +01:00
|
|
|
let keystore = Keystore::from_random_bytes(&buf);
|
2021-03-10 22:21:50 +01:00
|
|
|
digest.reset();
|
2021-03-22 19:20:51 +01:00
|
|
|
digest.update(keystore.get_public().as_slice());
|
|
|
|
|
if hash_is_good(digest.result(), difficulty) {
|
2021-03-16 18:16:31 +01:00
|
|
|
info!("Generated keypair with public key: {:?} and hash {:?}", &keystore.get_public(), &keystore.get_hash());
|
2021-03-10 22:21:50 +01:00
|
|
|
return Some(keystore);
|
|
|
|
|
}
|
|
|
|
|
if !mining.load(atomic::Ordering::SeqCst) {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let elapsed = time.elapsed().as_millis();
|
|
|
|
|
if elapsed >= 60000 {
|
|
|
|
|
debug!("Mining speed {} H/s", count / 60);
|
|
|
|
|
time = Instant::now();
|
|
|
|
|
count = 0;
|
|
|
|
|
}
|
|
|
|
|
count += 1;
|
2019-12-01 22:45:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-14 18:20:30 +01:00
|
|
|
|
2021-02-20 16:28:10 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2021-03-12 01:36:54 +01:00
|
|
|
use crate::Keystore;
|
2021-02-21 21:56:56 +01:00
|
|
|
|
2021-02-20 16:28:10 +01:00
|
|
|
#[test]
|
|
|
|
|
pub fn test_signature() {
|
|
|
|
|
let keystore: Keystore = Keystore::new();
|
|
|
|
|
let data = b"{ identity: 178135D209C697625E3EC71DA5C760382E54936F824EE5083908DA66B14ECE18,\
|
2021-02-14 18:20:30 +01:00
|
|
|
confirmation: A4A0AFECD1A511825226F0D3437C6C6BDAE83554040AA7AEB49DEFEAB0AE9EA4 }";
|
2021-02-20 16:28:10 +01:00
|
|
|
let signature = keystore.sign(data);
|
2021-03-12 01:36:54 +01:00
|
|
|
assert!(Keystore::check(data, &keystore.get_public(), &signature), "Wrong signature!")
|
2021-03-06 21:28:06 +01:00
|
|
|
}
|
2021-02-20 16:28:10 +01:00
|
|
|
}
|