use super::{DataIdentifier, PrivAppendedData, verify_detached};
use error::RoutingError;
use maidsafe_utilities::serialisation::serialise;
use rust_sodium::crypto::sign::{self, PublicKey, SecretKey, Signature};
use std::collections::BTreeSet;
use xor_name::XorName;
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, RustcDecodable, RustcEncodable)]
pub enum Filter {
BlackList(BTreeSet<PublicKey>),
WhiteList(BTreeSet<PublicKey>),
}
impl Filter {
pub fn black_list<T: IntoIterator<Item = PublicKey>>(keys: T) -> Filter {
Filter::BlackList(keys.into_iter().collect())
}
pub fn white_list<T: IntoIterator<Item = PublicKey>>(keys: T) -> Filter {
Filter::WhiteList(keys.into_iter().collect())
}
}
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, RustcDecodable, RustcEncodable, Debug)]
pub struct AppendedData {
pub pointer: DataIdentifier,
pub sign_key: PublicKey,
pub signature: Signature,
}
impl AppendedData {
pub fn new(pointer: DataIdentifier,
pub_key: PublicKey,
secret_key: &SecretKey)
-> Result<AppendedData, RoutingError> {
let data_to_sign = serialise(&(&pointer, &pub_key))?;
let signature = sign::sign_detached(&data_to_sign, secret_key);
Ok(AppendedData {
pointer: pointer,
sign_key: pub_key,
signature: signature,
})
}
pub fn verify_signature(&self) -> bool {
let data_to_sign = match serialise(&(&self.pointer, &self.sign_key)) {
Err(_) => return false,
Ok(data) => data,
};
verify_detached(&self.signature, &data_to_sign, &self.sign_key)
}
}
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, RustcDecodable, RustcEncodable, Debug)]
pub enum AppendWrapper {
Pub {
append_to: XorName,
data: AppendedData,
version: u64,
},
Priv {
append_to: XorName,
data: PrivAppendedData,
sign_key: PublicKey,
version: u64,
signature: Signature,
},
}
impl AppendWrapper {
pub fn new_pub(append_to: XorName, data: AppendedData, version: u64) -> Self {
AppendWrapper::Pub {
append_to: append_to,
data: data,
version: version,
}
}
pub fn new_priv(append_to: XorName,
data: PrivAppendedData,
sign_pair: (&PublicKey, &SecretKey),
version: u64)
-> Result<AppendWrapper, RoutingError> {
let data_to_sign = serialise(&(&append_to, &data, &sign_pair.0, &version))?;
let signature = sign::sign_detached(&data_to_sign, sign_pair.1);
Ok(AppendWrapper::Priv {
append_to: append_to,
data: data,
sign_key: *sign_pair.0,
version: version,
signature: signature,
})
}
pub fn identifier(&self) -> DataIdentifier {
match *self {
AppendWrapper::Priv { append_to, .. } => DataIdentifier::PrivAppendable(append_to),
AppendWrapper::Pub { append_to, .. } => DataIdentifier::PubAppendable(append_to),
}
}
pub fn verify_signature(&self) -> bool {
match *self {
AppendWrapper::Pub { ref data, .. } => data.verify_signature(),
AppendWrapper::Priv { ref append_to,
ref data,
ref sign_key,
ref version,
ref signature } => {
let data_to_sign = match serialise(&(append_to, data, sign_key, version)) {
Err(_) => return false,
Ok(data) => data,
};
verify_detached(signature, &data_to_sign, sign_key)
}
}
}
pub fn sign_key(&self) -> &PublicKey {
match *self {
AppendWrapper::Pub { ref data, .. } => &data.sign_key,
AppendWrapper::Priv { ref sign_key, .. } => sign_key,
}
}
pub fn version(&self) -> &u64 {
match *self {
AppendWrapper::Pub { ref version, .. } |
AppendWrapper::Priv { ref version, .. } => version,
}
}
pub fn priv_appended_data(&self) -> Option<&PrivAppendedData> {
match *self {
AppendWrapper::Pub { .. } => None,
AppendWrapper::Priv { ref data, .. } => Some(data),
}
}
pub fn pub_appended_data(&self) -> Option<&AppendedData> {
match *self {
AppendWrapper::Pub { ref data, .. } => Some(data),
AppendWrapper::Priv { .. } => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use data::{DataIdentifier, PrivAppendedData};
use rand;
use rust_sodium::crypto::{box_, sign};
#[test]
fn pub_signatures() {
let pointer = DataIdentifier::Immutable(rand::random());
let (pub_key, secret_key) = sign::gen_keypair();
let mut ad = unwrap!(AppendedData::new(pointer, pub_key, &secret_key));
assert!(AppendWrapper::new_pub(rand::random(), ad.clone(), 5).verify_signature());
ad.pointer = DataIdentifier::Structured(rand::random(), 10000);
assert!(!AppendWrapper::new_pub(rand::random(), ad, 5).verify_signature());
}
#[test]
fn priv_signatures() {
let pointer = DataIdentifier::Immutable(rand::random());
let (pub_sign_key, secret_sign_key) = sign::gen_keypair();
let (pub_encrypt_key, secret_encrypt_key) = box_::gen_keypair();
let ad = unwrap!(AppendedData::new(pointer, pub_sign_key, &secret_sign_key));
let pad = unwrap!(PrivAppendedData::new(&ad, &pub_encrypt_key));
assert_eq!(ad, unwrap!(pad.open(&pub_encrypt_key, &secret_encrypt_key)));
let mut wrapper = unwrap!(AppendWrapper::new_priv(rand::random(),
pad,
(&pub_sign_key, &secret_sign_key),
5));
assert!(wrapper.verify_signature());
match wrapper {
AppendWrapper::Pub { .. } => unreachable!(),
AppendWrapper::Priv { ref mut version, .. } => *version = 6,
}
assert!(!wrapper.verify_signature());
}
}