use maidsafe_utilities::serialisation;
use sodiumoxide::crypto::sign::{Signature, PublicKey, SecretKey};
use sodiumoxide::crypto;
use block_identifier::{BlockIdentifier, LinkDescriptor};
use error::Error;
pub fn create_link_descriptor(group: &[PublicKey]) -> LinkDescriptor {
let mut base = [0u8; 32];
for key in group.iter() {
for item in key.0.iter().cloned().enumerate() {
base[item.0] ^= item.1
}
}
base
}
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct NodeBlockProof {
key: PublicKey,
sig: Signature,
}
impl NodeBlockProof {
pub fn new(key: PublicKey, sig: Signature) -> NodeBlockProof {
NodeBlockProof {
key: key,
sig: sig,
}
}
pub fn key(&self) -> &PublicKey {
&self.key
}
pub fn sig(&self) -> &Signature {
&self.sig
}
}
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug, Clone)]
pub struct NodeBlock {
identifier: BlockIdentifier,
proof: NodeBlockProof,
}
impl NodeBlock {
pub fn new(pub_key: &PublicKey,
secret_key: &SecretKey,
data_identifier: BlockIdentifier)
-> Result<NodeBlock, Error> {
let signature =
crypto::sign::sign_detached(&try!(serialisation::serialise(&data_identifier))[..],
secret_key);
Ok(NodeBlock {
identifier: data_identifier,
proof: NodeBlockProof::new(*pub_key, signature),
})
}
pub fn identifier(&self) -> &BlockIdentifier {
&self.identifier
}
pub fn proof(&self) -> &NodeBlockProof {
&self.proof
}
pub fn validate(&self) -> bool {
let data = if let Ok(data) = serialisation::serialise(&self.identifier) {
data
} else {
return false;
};
crypto::sign::verify_detached(self.proof.sig(), &data[..], self.proof.key())
}
pub fn validate_detached(&self, identifier: BlockIdentifier) -> bool {
let data = if let Ok(data) = serialisation::serialise(&identifier) {
data
} else {
return false;
};
crypto::sign::verify_detached(self.proof.sig(), &data[..], self.proof.key())
}
}
#[cfg(test)]
mod tests {
use super::*;
use block_identifier::BlockIdentifier;
use sodiumoxide::crypto;
use sodiumoxide::crypto::hash::sha256;
#[test]
fn node_block_comparisons() {
::sodiumoxide::init();
let keys = crypto::sign::gen_keypair();
let test_data1 = BlockIdentifier::Link(sha256::hash(b"1").0);
let test_data2 = BlockIdentifier::Link(sha256::hash(b"1").0);
let test_data3 = BlockIdentifier::ImmutableData(sha256::hash(b"1"));
let test_node_data_block1 = NodeBlock::new(&keys.0, &keys.1, test_data1).expect("fail1");
let test_node_data_block2 = NodeBlock::new(&keys.0, &keys.1, test_data2).expect("fail2");
let test_node_data_block3 = NodeBlock::new(&keys.0, &keys.1, test_data3).expect("fail3");
assert!(test_node_data_block1.validate());
assert!(test_node_data_block2.validate());
assert!(test_node_data_block3.validate());
assert_eq!(test_node_data_block1.clone(), test_node_data_block2.clone());
assert!(test_node_data_block1 != test_node_data_block3.clone());
assert!(test_node_data_block2 != test_node_data_block3);
}
}