diff --git a/src/accountant.rs b/src/accountant.rs index 627f214bad..bf2a4a302b 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -2,7 +2,8 @@ //! event log to record transactions. Its users can deposit funds and //! transfer funds to other users. -use log::{Entry, Event, PublicKey, Sha256Hash, Signature}; +use log::{Entry, Sha256Hash}; +use event::{Event, PublicKey, Signature}; use historian::Historian; use ring::signature::Ed25519KeyPair; use std::sync::mpsc::{RecvError, SendError}; @@ -86,7 +87,7 @@ impl Accountant { n: u64, keypair: &Ed25519KeyPair, ) -> Result>> { - use log::{get_pubkey, sign_serialized}; + use event::{get_pubkey, sign_serialized}; let key = get_pubkey(keypair); let sig = sign_serialized(&n, keypair); self.deposit_signed(key, n, sig).map(|_| sig) @@ -119,7 +120,7 @@ impl Accountant { keypair: &Ed25519KeyPair, to: PublicKey, ) -> Result>> { - use log::{get_pubkey, sign_transaction_data}; + use event::{get_pubkey, sign_transaction_data}; let from = get_pubkey(keypair); let sig = sign_transaction_data(&n, keypair, &to); @@ -153,7 +154,7 @@ impl Accountant { #[cfg(test)] mod tests { use super::*; - use log::{generate_keypair, get_pubkey}; + use event::{generate_keypair, get_pubkey}; use historian::ExitReason; #[test] diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 0573299a78..6dec3f3ea9 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,6 @@ use std::io; use accountant::Accountant; -use log::{PublicKey, Signature}; +use event::{PublicKey, Signature}; //use serde::Serialize; pub struct AccountantSkel { diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index ac1945fa62..57b9e6e36c 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -5,7 +5,7 @@ use std::net::UdpSocket; use std::io; use bincode::{deserialize, serialize}; -use log::{PublicKey, Signature}; +use event::{PublicKey, Signature}; use ring::signature::Ed25519KeyPair; use accountant_skel::{Request, Response}; @@ -34,7 +34,7 @@ impl AccountantStub { } pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> io::Result { - use log::{get_pubkey, sign_serialized}; + use event::{get_pubkey, sign_serialized}; let key = get_pubkey(keypair); let sig = sign_serialized(&n, keypair); self.deposit_signed(key, n, sig).map(|_| sig) @@ -58,7 +58,7 @@ impl AccountantStub { keypair: &Ed25519KeyPair, to: PublicKey, ) -> io::Result { - use log::{get_pubkey, sign_transaction_data}; + use event::{get_pubkey, sign_transaction_data}; let from = get_pubkey(keypair); let sig = sign_transaction_data(&n, keypair, &to); self.transfer_signed(from, to, n, sig).map(|_| sig) @@ -100,7 +100,8 @@ mod tests { use accountant_skel::AccountantSkel; use std::thread::{sleep, spawn}; use std::time::Duration; - use log::{generate_keypair, get_pubkey, Sha256Hash}; + use log::Sha256Hash; + use event::{generate_keypair, get_pubkey}; #[test] fn test_accountant_stub() { diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index cbc0d6dd30..ba0d482942 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -4,7 +4,7 @@ fn main() { use silk::accountant_stub::AccountantStub; use std::time::Instant; use std::net::UdpSocket; - use silk::log::{generate_keypair, get_pubkey}; + use silk::event::{generate_keypair, get_pubkey}; let addr = "127.0.0.1:8000"; let send_addr = "127.0.0.1:8001"; diff --git a/src/bin/demo.rs b/src/bin/demo.rs index a8f502a875..c7ce456951 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -1,8 +1,8 @@ extern crate silk; use silk::historian::Historian; -use silk::log::{generate_keypair, get_pubkey, sign_serialized, verify_slice, Entry, Event, - Sha256Hash}; +use silk::log::{verify_slice, Entry, Sha256Hash}; +use silk::event::{generate_keypair, get_pubkey, sign_serialized, Event}; use std::thread::sleep; use std::time::Duration; use std::sync::mpsc::SendError; diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000000..8597394c54 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,114 @@ +//! The `log` crate provides the foundational data structures for Proof-of-History, +//! an ordered log of events in time. + +/// Each log entry contains three pieces of data. The 'num_hashes' field is the number +/// of hashes performed since the previous entry. The 'end_hash' field is the result +/// of hashing 'end_hash' from the previous entry 'num_hashes' times. The 'event' +/// field points to an Event that took place shortly after 'end_hash' was generated. +/// +/// If you divide 'num_hashes' by the amount of time it takes to generate a new hash, you +/// get a duration estimate since the last event. Since processing power increases +/// over time, one should expect the duration 'num_hashes' represents to decrease proportionally. +/// Though processing power varies across nodes, the network gives priority to the +/// fastest processor. Duration should therefore be estimated by assuming that the hash +/// was generated by the fastest processor at the time the entry was logged. + +use generic_array::GenericArray; +use generic_array::typenum::{U32, U64}; +use ring::signature::Ed25519KeyPair; +use serde::Serialize; + +pub type PublicKey = GenericArray; +pub type Signature = GenericArray; + +/// When 'event' is Tick, the event represents a simple clock tick, and exists for the +/// sole purpose of improving the performance of event log verification. A tick can +/// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging +/// a hash alongside the tick, each tick and be verified in parallel using the 'end_hash' +/// of the preceding tick to seed its hashing. +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub enum Event { + Tick, + Claim { + key: PublicKey, + data: T, + sig: Signature, + }, + Transaction { + from: PublicKey, + to: PublicKey, + data: T, + sig: Signature, + }, +} + +/// Return a new ED25519 keypair +pub fn generate_keypair() -> Ed25519KeyPair { + use ring::{rand, signature}; + use untrusted; + let rng = rand::SystemRandom::new(); + let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap(); + signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap() +} + +/// Return the public key for the given keypair +pub fn get_pubkey(keypair: &Ed25519KeyPair) -> PublicKey { + GenericArray::clone_from_slice(keypair.public_key_bytes()) +} + +/// Return a signature for the given data using the private key from the given keypair. +pub fn sign_serialized(data: &T, keypair: &Ed25519KeyPair) -> Signature { + use bincode::serialize; + let serialized = serialize(data).unwrap(); + GenericArray::clone_from_slice(keypair.sign(&serialized).as_ref()) +} + +/// Return a signature for the given transaction data using the private key from the given keypair. +pub fn sign_transaction_data( + data: &T, + keypair: &Ed25519KeyPair, + to: &PublicKey, +) -> Signature { + sign_serialized(&(data, to), keypair) +} + +/// Verify a signed message with the given public key. +pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_bytes: &[u8]) -> bool { + use untrusted; + use ring::signature; + let peer_public_key = untrusted::Input::from(peer_public_key_bytes); + let msg = untrusted::Input::from(msg_bytes); + let sig = untrusted::Input::from(sig_bytes); + signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok() +} + +pub fn get_signature(event: &Event) -> Option { + match *event { + Event::Tick => None, + Event::Claim { sig, .. } => Some(sig), + Event::Transaction { sig, .. } => Some(sig), + } +} + +pub fn verify_event(event: &Event) -> bool { + use bincode::serialize; + if let Event::Claim { key, ref data, sig } = *event { + let mut claim_data = serialize(&data).unwrap(); + if !verify_signature(&key, &claim_data, &sig) { + return false; + } + } + if let Event::Transaction { + from, + to, + ref data, + sig, + } = *event + { + let sign_data = serialize(&(&data, &to)).unwrap(); + if !verify_signature(&from, &sign_data, &sig) { + return false; + } + } + true +} diff --git a/src/historian.rs b/src/historian.rs index 1a0441451c..be30f66867 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -9,7 +9,8 @@ use std::thread::JoinHandle; use std::collections::HashMap; use std::sync::mpsc::{Receiver, SyncSender}; use std::time::{Duration, SystemTime}; -use log::{get_signature, hash, hash_event, verify_event, Entry, Event, Sha256Hash, Signature}; +use log::{hash, hash_event, Entry, Sha256Hash}; +use event::{get_signature, verify_event, Event, Signature}; use serde::Serialize; use std::fmt::Debug; @@ -141,6 +142,7 @@ impl Historian { mod tests { use super::*; use log::*; + use event::*; use std::thread::sleep; use std::time::Duration; diff --git a/src/lib.rs b/src/lib.rs index 6deb929413..851262000a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(feature = "unstable", feature(test))] pub mod log; +pub mod event; pub mod historian; pub mod accountant; pub mod accountant_skel; diff --git a/src/log.rs b/src/log.rs index 04a3b24823..56d930b523 100644 --- a/src/log.rs +++ b/src/log.rs @@ -14,13 +14,11 @@ /// was generated by the fastest processor at the time the entry was logged. use generic_array::GenericArray; -use generic_array::typenum::{U32, U64}; -use ring::signature::Ed25519KeyPair; +use generic_array::typenum::U32; use serde::Serialize; +use event::*; pub type Sha256Hash = GenericArray; -pub type PublicKey = GenericArray; -pub type Signature = GenericArray; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Entry { @@ -29,27 +27,6 @@ pub struct Entry { pub event: Event, } -/// When 'event' is Tick, the event represents a simple clock tick, and exists for the -/// sole purpose of improving the performance of event log verification. A tick can -/// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging -/// a hash alongside the tick, each tick and be verified in parallel using the 'end_hash' -/// of the preceding tick to seed its hashing. -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum Event { - Tick, - Claim { - key: PublicKey, - data: T, - sig: Signature, - }, - Transaction { - from: PublicKey, - to: PublicKey, - data: T, - sig: Signature, - }, -} - impl Entry { /// Creates a Entry from the number of hashes 'num_hashes' since the previous event /// and that resulting 'end_hash'. @@ -62,36 +39,6 @@ impl Entry { } } -/// Return a new ED25519 keypair -pub fn generate_keypair() -> Ed25519KeyPair { - use ring::{rand, signature}; - use untrusted; - let rng = rand::SystemRandom::new(); - let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap(); - signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap() -} - -/// Return the public key for the given keypair -pub fn get_pubkey(keypair: &Ed25519KeyPair) -> PublicKey { - GenericArray::clone_from_slice(keypair.public_key_bytes()) -} - -/// Return a signature for the given data using the private key from the given keypair. -pub fn sign_serialized(data: &T, keypair: &Ed25519KeyPair) -> Signature { - use bincode::serialize; - let serialized = serialize(data).unwrap(); - GenericArray::clone_from_slice(keypair.sign(&serialized).as_ref()) -} - -/// Return a signature for the given transaction data using the private key from the given keypair. -pub fn sign_transaction_data( - data: &T, - keypair: &Ed25519KeyPair, - to: &PublicKey, -) -> Signature { - sign_serialized(&(data, to), keypair) -} - /// Return a Sha256 hash for the given data. pub fn hash(val: &[u8]) -> Sha256Hash { use sha2::{Digest, Sha256}; @@ -107,14 +54,6 @@ pub fn extend_and_hash(end_hash: &Sha256Hash, val: &[u8]) -> Sha256Hash { hash(&hash_data) } -pub fn get_signature(event: &Event) -> Option { - match *event { - Event::Tick => None, - Event::Claim { sig, .. } => Some(sig), - Event::Transaction { sig, .. } => Some(sig), - } -} - pub fn hash_event(end_hash: &Sha256Hash, event: &Event) -> Sha256Hash { match get_signature(event) { None => *end_hash, @@ -164,29 +103,6 @@ pub fn next_tick(start_hash: &Sha256Hash, num_hashes: u64) -> Entr next_entry(start_hash, num_hashes, Event::Tick) } -pub fn verify_event(event: &Event) -> bool { - use bincode::serialize; - if let Event::Claim { key, ref data, sig } = *event { - let mut claim_data = serialize(&data).unwrap(); - if !verify_signature(&key, &claim_data, &sig) { - return false; - } - } - if let Event::Transaction { - from, - to, - ref data, - sig, - } = *event - { - let sign_data = serialize(&(&data, &to)).unwrap(); - if !verify_signature(&from, &sign_data, &sig) { - return false; - } - } - true -} - /// Verifies self.end_hash is the result of hashing a 'start_hash' 'self.num_hashes' times. /// If the event is not a Tick, then hash that as well. pub fn verify_entry(entry: &Entry, start_hash: &Sha256Hash) -> bool { @@ -219,16 +135,6 @@ pub fn verify_slice_seq(events: &[Entry], start_hash: &Sha256Ha event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.end_hash)) } -/// Verify a signed message with the given public key. -pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_bytes: &[u8]) -> bool { - use untrusted; - use ring::signature; - let peer_public_key = untrusted::Input::from(peer_public_key_bytes); - let msg = untrusted::Input::from(msg_bytes); - let sig = untrusted::Input::from(sig_bytes); - signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok() -} - pub fn create_entries( start_hash: &Sha256Hash, num_hashes: u64,