commit 0c020647ee9de137472eb734da2ef6620723f922 Author: Frederic Jacobs Date: Tue Nov 8 18:23:27 2016 +0100 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1aa6b6d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "lamport" +version = "0.1.0" +authors = ["Frederic Jacobs "] + +[dependencies] +rust-crypto = "^0.2.36" +rand = "^0.3" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..474958e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,197 @@ +pub extern crate crypto; +extern crate rand; + +use rand::OsRng; +use rand::Rng; +use crypto::digest::Digest; +use std::hash::{Hash, Hasher}; + +pub struct PublicKey { + zero_values: Vec>, + one_values: Vec>, + digest: T +} + +pub struct PrivateKey { + zero_values: Vec>, // For a n bits hash function: (n * n/8 bytes) for zero_values and one_values + one_values: Vec>, + digest: T, + used: bool +} + +impl Hash for PrivateKey { + fn hash(&self, state: &mut H) { + let public_key = self.public_key(); + public_key.one_values.hash(state); + public_key.zero_values.hash(state); + } +} + +pub fn verify_signature( signature: &Vec>, + data:&[u8], + public_key: &PublicKey) -> bool +{ + + let mut digest = public_key.digest.clone(); + digest.input(data); + let mut data_hash = vec![0 as u8; digest.output_bytes()]; + digest.result(data_hash.as_mut_slice()); + digest.reset(); + + for i in 0..data_hash.len() { + let byte = data_hash[i]; + for j in 0..8 { + let offset = i*8 + j; + if (byte & (1< 0 { + digest.input(signature[offset].as_slice()); + let mut hashed_value = vec![0 as u8; digest.output_bytes()]; + digest.result(hashed_value.as_mut_slice()); + digest.reset(); + if hashed_value != public_key.one_values[offset] { + return false; + } + } else { + digest.input(signature[offset].as_slice()); + let mut hashed_value = vec![0 as u8; digest.output_bytes()]; + digest.result(hashed_value.as_mut_slice()); + digest.reset(); + if hashed_value != public_key.zero_values[offset] { + return false; + } + } + } + } + + return true; +} + +impl PrivateKey { + pub fn new(digest: T) -> PrivateKey { + let generate_bit_hash_values = |hasher: &T| -> Vec> { + let mut rng = match OsRng::new() { + Ok(g) => g, + Err(e) => panic!("Failed to obtain OS RNG: {}", e) + }; + let buffer_byte = vec![0 as u8; hasher.output_bytes()]; + let mut buffer = vec![buffer_byte; hasher.output_bits()]; + + for hash in buffer.iter_mut() { + rng.fill_bytes(hash) + } + + return buffer; + }; + + let zero_values = generate_bit_hash_values(&digest); + let one_values = generate_bit_hash_values(&digest); + + return PrivateKey { zero_values: zero_values, + one_values: one_values, + digest: digest, + used: false } + } + + pub fn public_key(&self) -> PublicKey { + let mut digest = self.digest.clone(); + + let hash_values = |x: &Vec>, hash_func: &mut Digest | -> Vec> { + let buffer_byte = vec![0 as u8; hash_func.output_bytes()]; + let mut buffer = vec![buffer_byte; hash_func.output_bits()]; + + for i in 0..hash_func.output_bits(){ + hash_func.input(x[i].as_slice()); + hash_func.result(buffer[i].as_mut_slice()); + hash_func.reset(); + } + + return buffer; + }; + + let hashed_zero_values = hash_values(&self.zero_values, &mut digest); + let hashed_one_values = hash_values(&self.one_values, &mut digest); + + return PublicKey { zero_values: hashed_zero_values, + one_values: hashed_one_values, + digest: digest } + } + pub fn sign(&mut self, data: &[u8]) -> Result>, &'static str> { + if self.used { + return Err("Attempting to sign more than once."); + } + self.digest.input(data); + let mut data_hash = vec![0 as u8; self.digest.output_bytes()]; + self.digest.result(data_hash.as_mut_slice()); + self.digest.reset(); + + let mut signature = Vec::new(); + + for i in 0..data_hash.len() { + let byte = data_hash[i]; + for j in 0..8 { + let offset = i*8 + j; + if (byte & (1< 0 { + // Bit is 1 + signature.push(self.one_values[offset].clone()); + } else { + // Bit is 0 + signature.push(self.zero_values[offset].clone()); + } + } + } + self.used = true; + return Ok(signature); + } +} + +impl Drop for PrivateKey { + fn drop(&mut self) { + let zeroize_vector = |vector: &mut Vec>| { + for v2 in vector.iter_mut() { + for byte in v2.iter_mut() { + *byte = 0; + } + } + }; + + zeroize_vector(&mut self.zero_values); + zeroize_vector(&mut self.one_values); + } +} + +impl PartialEq for PrivateKey { + // ⚠️ This is not a constant-time implementation + fn eq(&self, other: &PrivateKey) -> bool { + if self.one_values.len() != other.one_values.len() { + return false; + } + if self.zero_values.len() != other.zero_values.len() { + return false; + } + + for i in 0..self.zero_values.len() { + if self.zero_values[i] != self.zero_values[i] || self.one_values[i] != other.one_values[i] { + return false + } + } + return true; + } +} + +#[cfg(test)] +use crypto::sha3::Sha3; +#[test] +fn test_public_key_length_256() { + let pk = PrivateKey::new(Sha3::sha3_256()); + assert!( pk.public_key().one_values.len() == 256 && + pk.public_key().zero_values.len() == 256); +} +#[test] +fn test_public_key_length_512() { + let pk = PrivateKey::new(Sha3::sha3_512()); + assert!( pk.public_key().one_values.len() == 512 && + pk.public_key().zero_values.len() == 512); +} + + +#[cfg(test)] +pub mod test; diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..a512779 --- /dev/null +++ b/src/test.rs @@ -0,0 +1,36 @@ +use crypto::sha3::Sha3; +use PrivateKey; +use verify_signature; + +#[cfg(test)] +#[test] +fn test_distinctive_successive_keygen() { + let mut past_buff = PrivateKey::new(Sha3::sha3_256()); + for _ in 0..100 { + let buffer = PrivateKey::new(Sha3::sha3_256()); + assert!(past_buff != buffer); + past_buff = buffer; + } +} + +#[test] +fn test_sign_verif() { + let mut priv_key = PrivateKey::new(Sha3::sha3_256()); + let data = "Hello World".as_bytes(); + let signature = priv_key.sign(data).unwrap(); + + let pub_key = priv_key.public_key(); + + assert!(verify_signature(&signature, data, &pub_key)); +} + +#[test] +fn test_sign_verif_fail() { + let mut priv_key = PrivateKey::new(Sha3::sha3_256()); + let data = "Hello Word".as_bytes(); + let signature = priv_key.sign(data).unwrap(); + + let pub_key = priv_key.public_key(); + let data2 = "Hello".as_bytes(); + assert!(!verify_signature(&signature, data2, &pub_key)); +} diff --git a/tokamak.toml b/tokamak.toml new file mode 100644 index 0000000..789eee6 --- /dev/null +++ b/tokamak.toml @@ -0,0 +1,7 @@ +[helper] +path = "" # Reserved for future helper path and configurations +[options] +save_buffers_before_run = true # Saving buffers before every cargo command run +general_warnings = true # Show general warnings +[project] +auto_format_timing = 5 # Run auto formatting for project for specified interval (seconds)