use crust::Uid;
use rust_sodium::crypto::{box_, sign};
use serde::{Deserializer, Serialize, Serializer};
use serde::de::Deserialize;
use std::fmt::{self, Debug, Display, Formatter};
use tiny_keccak::sha3_256;
use xor_name::XorName;
#[derive(Clone)]
pub struct FullId {
public_id: PublicId,
private_encrypt_key: box_::SecretKey,
private_sign_key: sign::SecretKey,
}
impl FullId {
pub fn new() -> FullId {
let encrypt_keys = box_::gen_keypair();
let sign_keys = sign::gen_keypair();
FullId {
public_id: PublicId::new(encrypt_keys.0, sign_keys.0),
private_encrypt_key: encrypt_keys.1,
private_sign_key: sign_keys.1,
}
}
pub fn with_keys(
encrypt_keys: (box_::PublicKey, box_::SecretKey),
sign_keys: (sign::PublicKey, sign::SecretKey),
) -> FullId {
FullId {
public_id: PublicId::new(encrypt_keys.0, sign_keys.0),
private_encrypt_key: encrypt_keys.1,
private_sign_key: sign_keys.1,
}
}
pub fn within_range(start: &XorName, end: &XorName) -> FullId {
let mut sign_keys = sign::gen_keypair();
loop {
let name = PublicId::name_from_key(&sign_keys.0);
if name >= *start && name <= *end {
let encrypt_keys = box_::gen_keypair();
let full_id = FullId::with_keys(encrypt_keys, sign_keys);
return full_id;
}
sign_keys = sign::gen_keypair();
}
}
pub fn public_id(&self) -> &PublicId {
&self.public_id
}
pub fn public_id_mut(&mut self) -> &mut PublicId {
&mut self.public_id
}
pub fn signing_private_key(&self) -> &sign::SecretKey {
&self.private_sign_key
}
pub fn encrypting_private_key(&self) -> &box_::SecretKey {
&self.private_encrypt_key
}
}
impl Default for FullId {
fn default() -> FullId {
FullId::new()
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub struct PublicId {
name: XorName,
public_sign_key: sign::PublicKey,
public_encrypt_key: box_::PublicKey,
}
impl Uid for PublicId {}
impl Debug for PublicId {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "PublicId(name: {})", self.name)
}
}
impl Display for PublicId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Serialize for PublicId {
fn serialize<S: Serializer>(&self, serialiser: S) -> Result<S::Ok, S::Error> {
(&self.public_encrypt_key, &self.public_sign_key).serialize(serialiser)
}
}
impl<'de> Deserialize<'de> for PublicId {
fn deserialize<D: Deserializer<'de>>(deserialiser: D) -> Result<Self, D::Error> {
let (public_encrypt_key, public_sign_key): (box_::PublicKey, sign::PublicKey) =
Deserialize::deserialize(deserialiser)?;
Ok(PublicId::new(public_encrypt_key, public_sign_key))
}
}
impl PublicId {
pub fn name(&self) -> &XorName {
&self.name
}
pub fn encrypting_public_key(&self) -> &box_::PublicKey {
&self.public_encrypt_key
}
pub fn signing_public_key(&self) -> &sign::PublicKey {
&self.public_sign_key
}
fn new(public_encrypt_key: box_::PublicKey, public_sign_key: sign::PublicKey) -> PublicId {
PublicId {
public_encrypt_key: public_encrypt_key,
public_sign_key: public_sign_key,
name: Self::name_from_key(&public_sign_key),
}
}
fn name_from_key(public_sign_key: &sign::PublicKey) -> XorName {
XorName(sha3_256(&public_sign_key[..]))
}
}
#[cfg(test)]
mod tests {
use super::*;
use maidsafe_utilities::{SeededRng, serialisation};
use rust_sodium;
#[test]
fn public_id_order() {
let mut rng = SeededRng::thread_rng();
unwrap!(rust_sodium::init_with_rng(&mut rng));
let pub_id_1 = *FullId::new().public_id();
let pub_id_2;
loop {
let temp_pub_id = *FullId::new().public_id();
if temp_pub_id.name > pub_id_1.name &&
temp_pub_id.public_sign_key < pub_id_1.public_sign_key &&
temp_pub_id.public_encrypt_key < pub_id_1.public_encrypt_key
{
pub_id_2 = temp_pub_id;
break;
}
}
assert!(pub_id_1 < pub_id_2);
}
#[test]
fn serialisation() {
let mut rng = SeededRng::thread_rng();
unwrap!(rust_sodium::init_with_rng(&mut rng));
let full_id = FullId::new();
let serialised = unwrap!(serialisation::serialise(full_id.public_id()));
let parsed = unwrap!(serialisation::deserialise(&serialised));
assert_eq!(*full_id.public_id(), parsed);
}
}