From 6543497c1767a628646d7fa3404fef6f9c4f6452 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 10:49:40 -0700 Subject: [PATCH 01/10] Move Transaction data into its own struct This will allow us to add addition transfer types to the log. --- src/accountant.rs | 10 +++++----- src/accountant_skel.rs | 6 +++--- src/bin/client-demo.rs | 7 ++++--- src/event.rs | 28 ++++++++++++++++------------ src/genesis.rs | 8 ++++---- src/log.rs | 14 +++++++------- 6 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index b9939656971906..08864f7c81c8e0 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,7 +3,7 @@ //! transfer funds to other users. use log::{Entry, Sha256Hash}; -use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature}; +use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature, Transfer}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -79,7 +79,7 @@ impl Accountant { return Err(AccountingError::InvalidEvent); } - if let Event::Transaction { from, data, .. } = event { + if let Event::Transaction(Transfer { from, data, .. }) = event { if self.get_balance(&from).unwrap_or(0) < data { return Err(AccountingError::InsufficientFunds); } @@ -102,7 +102,7 @@ impl Accountant { return Err(AccountingError::InvalidEvent); } - if let Event::Transaction { from, to, data, .. } = *event { + if let Event::Transaction(Transfer { from, to, data, .. }) = *event { if !Self::is_deposit(allow_deposits, &from, &to) { if let Some(x) = self.balances.get_mut(&from) { *x -= data; @@ -129,13 +129,13 @@ impl Accountant { let from = get_pubkey(keypair); let last_id = self.last_id; let sig = sign_transaction_data(&n, keypair, &to, &last_id); - let event = Event::Transaction { + let event = Event::Transaction(Transfer { from, to, data: n, last_id, sig, - }; + }); self.process_event(event).map(|_| sig) } diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 069b5cd851fef9..004f627afb8632 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,6 @@ use std::io; use accountant::Accountant; -use event::{Event, PublicKey, Signature}; +use event::{Event, PublicKey, Signature, Transfer}; use log::{Entry, Sha256Hash}; use std::net::UdpSocket; use bincode::{deserialize, serialize}; @@ -50,13 +50,13 @@ impl AccountantSkel { last_id, sig, } => { - let event = Event::Transaction { + let event = Event::Transaction(Transfer { from, to, data: val, last_id, sig, - }; + }); if let Err(err) = self.acc.process_event(event) { eprintln!("Transfer error: {:?}", err); } diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index b54331a4c4532d..5e66d0c8713e95 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -2,7 +2,8 @@ extern crate serde_json; extern crate silk; use silk::accountant_stub::AccountantStub; -use silk::event::{generate_keypair, get_pubkey, sign_transaction_data, verify_event, Event}; +use silk::event::{generate_keypair, get_pubkey, sign_transaction_data, verify_event, Event, + Transfer}; use silk::genesis::Genesis; use std::time::Instant; use std::net::UdpSocket; @@ -47,13 +48,13 @@ fn main() { println!("Verify signatures..."); let now = Instant::now(); for &(k, s) in &sigs { - let e = Event::Transaction { + let e = Event::Transaction(Transfer { from: alice_pubkey, to: k, data: one, last_id, sig: s, - }; + }); assert!(verify_event(&e)); } let duration = now.elapsed(); diff --git a/src/event.rs b/src/event.rs index 1b1fd2f386ca42..26d5d1bc73b471 100644 --- a/src/event.rs +++ b/src/event.rs @@ -25,6 +25,15 @@ use log::Sha256Hash; pub type PublicKey = GenericArray; pub type Signature = GenericArray; +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct Transfer { + pub from: PublicKey, + pub to: PublicKey, + pub data: T, + pub last_id: Sha256Hash, + pub sig: Signature, +} + /// 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 @@ -33,24 +42,19 @@ pub type Signature = GenericArray; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum Event { Tick, - Transaction { - from: PublicKey, - to: PublicKey, - data: T, - last_id: Sha256Hash, - sig: Signature, - }, + Transaction(Transfer), } impl Event { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - Event::Transaction { + let transfer = Transfer { from: to, to, data, last_id, sig, - } + }; + Event::Transaction(transfer) } } @@ -103,18 +107,18 @@ pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_byte pub fn get_signature(event: &Event) -> Option { match *event { Event::Tick => None, - Event::Transaction { sig, .. } => Some(sig), + Event::Transaction(Transfer { sig, .. }) => Some(sig), } } pub fn verify_event(event: &Event) -> bool { - if let Event::Transaction { + if let Event::Transaction(Transfer { from, to, ref data, last_id, sig, - } = *event + }) = *event { let sign_data = serialize(&(&from, &to, &data, &last_id)).unwrap(); if !verify_signature(&from, &sign_data, &sig) { diff --git a/src/genesis.rs b/src/genesis.rs index a30f35883adfb5..2d8be7c2b613af 100644 --- a/src/genesis.rs +++ b/src/genesis.rs @@ -1,6 +1,6 @@ //! A library for generating the chain's genesis block. -use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey}; +use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey, Transfer}; use log::{create_entries, hash, Entry, Sha256Hash}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; @@ -56,13 +56,13 @@ impl Genesis { let last_id = self.get_seed(); let from = self.get_pubkey(); let sig = sign_transaction_data(&data, &self.get_keypair(), to, &last_id); - Event::Transaction { + Event::Transaction(Transfer { from, to: *to, data, last_id, sig, - } + }) } pub fn create_events(&self) -> Vec> { @@ -93,7 +93,7 @@ mod tests { fn test_create_events() { let mut events = Genesis::new(100, vec![]).create_events().into_iter(); assert_eq!(events.next().unwrap(), Event::Tick); - if let Event::Transaction { from, to, .. } = events.next().unwrap() { + if let Event::Transaction(Transfer { from, to, .. }) = events.next().unwrap() { assert_eq!(from, to); } else { assert!(false); diff --git a/src/log.rs b/src/log.rs index 8d133b5b3c3155..6dc20792cad97e 100644 --- a/src/log.rs +++ b/src/log.rs @@ -169,7 +169,7 @@ pub fn next_ticks(start_hash: &Sha256Hash, num_hashes: u64, len: usize) -> Vec Date: Tue, 6 Mar 2018 10:59:47 -0700 Subject: [PATCH 02/10] Rename Request::Transfer to Request::Transaction --- src/accountant_skel.rs | 4 ++-- src/accountant_stub.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 004f627afb8632..5a95337ea76032 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -11,7 +11,7 @@ pub struct AccountantSkel { #[derive(Serialize, Deserialize, Debug)] pub enum Request { - Transfer { + Transaction { from: PublicKey, to: PublicKey, val: i64, @@ -43,7 +43,7 @@ impl AccountantSkel { pub fn process_request(self: &mut Self, msg: Request) -> Option { match msg { - Request::Transfer { + Request::Transaction { from, to, val, diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index 8e62addd36ce36..2336051bb85910 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -33,7 +33,7 @@ impl AccountantStub { last_id: Sha256Hash, sig: Signature, ) -> io::Result { - let req = Request::Transfer { + let req = Request::Transaction { from, to, val, From 282afee47e9a6dd0385e99d8072abbbf54be0d2a Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 11:03:41 -0700 Subject: [PATCH 03/10] Use Transfer struct on the client side too Sharing is caring. --- src/accountant_skel.rs | 38 +++++++------------------------------- src/accountant_stub.rs | 8 ++++---- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 5a95337ea76032..228b84020080d3 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,6 @@ use std::io; use accountant::Accountant; -use event::{Event, PublicKey, Signature, Transfer}; +use event::{Event, PublicKey, Transfer}; use log::{Entry, Sha256Hash}; use std::net::UdpSocket; use bincode::{deserialize, serialize}; @@ -11,22 +11,10 @@ pub struct AccountantSkel { #[derive(Serialize, Deserialize, Debug)] pub enum Request { - Transaction { - from: PublicKey, - to: PublicKey, - val: i64, - last_id: Sha256Hash, - sig: Signature, - }, - GetBalance { - key: PublicKey, - }, - GetEntries { - last_id: Sha256Hash, - }, - GetId { - is_last: bool, - }, + Transaction(Transfer), + GetBalance { key: PublicKey }, + GetEntries { last_id: Sha256Hash }, + GetId { is_last: bool }, } #[derive(Serialize, Deserialize, Debug)] @@ -43,20 +31,8 @@ impl AccountantSkel { pub fn process_request(self: &mut Self, msg: Request) -> Option { match msg { - Request::Transaction { - from, - to, - val, - last_id, - sig, - } => { - let event = Event::Transaction(Transfer { - from, - to, - data: val, - last_id, - sig, - }); + Request::Transaction(transfer) => { + let event = Event::Transaction(transfer); if let Err(err) = self.acc.process_event(event) { eprintln!("Transfer error: {:?}", err); } diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index 2336051bb85910..d39858e0104747 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 event::{get_pubkey, get_signature, sign_transaction_data, PublicKey, Signature}; +use event::{get_pubkey, get_signature, sign_transaction_data, PublicKey, Signature, Transfer}; use log::{Entry, Sha256Hash}; use ring::signature::Ed25519KeyPair; use accountant_skel::{Request, Response}; @@ -33,13 +33,13 @@ impl AccountantStub { last_id: Sha256Hash, sig: Signature, ) -> io::Result { - let req = Request::Transaction { + let req = Request::Transaction(Transfer { from, to, - val, + data: val, last_id, sig, - }; + }); let data = serialize(&req).unwrap(); self.socket.send_to(&data, &self.addr) } From 19296014257f22e361095879f6938137f8261178 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 11:19:55 -0700 Subject: [PATCH 04/10] Cleanup Now that Transfer is out of the enum, we don't need to pattern match to access its fields. --- src/event.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/event.rs b/src/event.rs index 26d5d1bc73b471..463b82bbaa0856 100644 --- a/src/event.rs +++ b/src/event.rs @@ -107,25 +107,20 @@ pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_byte pub fn get_signature(event: &Event) -> Option { match *event { Event::Tick => None, - Event::Transaction(Transfer { sig, .. }) => Some(sig), + Event::Transaction(ref tr) => Some(tr.sig), } } pub fn verify_event(event: &Event) -> bool { - if let Event::Transaction(Transfer { - from, - to, - ref data, - last_id, - sig, - }) = *event - { - let sign_data = serialize(&(&from, &to, &data, &last_id)).unwrap(); - if !verify_signature(&from, &sign_data, &sig) { - return false; - } + match *event { + Event::Tick => true, + Event::Transaction(ref tr) => verify_transfer(tr), } - true +} + +pub fn verify_transfer(tr: &Transfer) -> bool { + let sign_data = serialize(&(&tr.from, &tr.to, &tr.data, &tr.last_id)).unwrap(); + verify_signature(&tr.from, &sign_data, &tr.sig) } #[cfg(test)] From a2811842c8ec0dad56555466550ecb49f06452c4 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 11:43:53 -0700 Subject: [PATCH 05/10] More cleanup Far fewer branches when we process transfers outside the context of events. --- src/accountant.rs | 68 ++++++++++++++++++++++++------------------ src/accountant_skel.rs | 5 ++-- src/event.rs | 21 ++++++++----- src/historian.rs | 18 +++++------ 4 files changed, 62 insertions(+), 50 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index 08864f7c81c8e0..755a5510f10dbd 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,7 +3,8 @@ //! transfer funds to other users. use log::{Entry, Sha256Hash}; -use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature, Transfer}; +use event::{get_pubkey, sign_transaction_data, verify_transfer, Event, PublicKey, Signature, + Transfer}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -14,7 +15,8 @@ use std::result; #[derive(Debug, PartialEq, Eq)] pub enum AccountingError { InsufficientFunds, - InvalidEvent, + InvalidTransfer, + InvalidTransferSignature, SendError, } @@ -74,52 +76,60 @@ impl Accountant { allow_deposits && from == to } - pub fn process_event(self: &mut Self, event: Event) -> Result<()> { - if !verify_event(&event) { - return Err(AccountingError::InvalidEvent); + pub fn process_transfer(self: &mut Self, tr: Transfer) -> Result<()> { + if !verify_transfer(&tr) { + return Err(AccountingError::InvalidTransfer); } - if let Event::Transaction(Transfer { from, data, .. }) = event { - if self.get_balance(&from).unwrap_or(0) < data { - return Err(AccountingError::InsufficientFunds); - } + if self.get_balance(&tr.from).unwrap_or(0) < tr.data { + return Err(AccountingError::InsufficientFunds); } - self.process_verified_event(&event, false)?; - if let Err(SendError(_)) = self.historian.sender.send(event) { + self.process_verified_transfer(&tr, false)?; + if let Err(SendError(_)) = self.historian.sender.send(Event::Transaction(tr)) { return Err(AccountingError::SendError); } Ok(()) } - fn process_verified_event( + fn process_verified_transfer( self: &mut Self, - event: &Event, + tr: &Transfer, allow_deposits: bool, ) -> Result<()> { - if !reserve_signature(&mut self.historian.signatures, event) { - return Err(AccountingError::InvalidEvent); + if !reserve_signature(&mut self.historian.signatures, &tr.sig) { + return Err(AccountingError::InvalidTransferSignature); } - if let Event::Transaction(Transfer { from, to, data, .. }) = *event { - if !Self::is_deposit(allow_deposits, &from, &to) { - if let Some(x) = self.balances.get_mut(&from) { - *x -= data; - } + if !Self::is_deposit(allow_deposits, &tr.from, &tr.to) { + if let Some(x) = self.balances.get_mut(&tr.from) { + *x -= tr.data; } + } - if self.balances.contains_key(&to) { - if let Some(x) = self.balances.get_mut(&to) { - *x += data; - } - } else { - self.balances.insert(to, data); + if self.balances.contains_key(&tr.to) { + if let Some(x) = self.balances.get_mut(&tr.to) { + *x += tr.data; } + } else { + self.balances.insert(tr.to, tr.data); } + Ok(()) } + fn process_verified_event( + self: &mut Self, + event: &Event, + allow_deposits: bool, + ) -> Result<()> { + match *event { + Event::Tick => Ok(()), + Event::Transaction(ref tr) => self.process_verified_transfer(tr, allow_deposits), + } + } + pub fn transfer( self: &mut Self, n: i64, @@ -129,14 +139,14 @@ impl Accountant { let from = get_pubkey(keypair); let last_id = self.last_id; let sig = sign_transaction_data(&n, keypair, &to, &last_id); - let event = Event::Transaction(Transfer { + let tr = Transfer { from, to, data: n, last_id, sig, - }); - self.process_event(event).map(|_| sig) + }; + self.process_transfer(tr).map(|_| sig) } pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option { diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 228b84020080d3..ae820246442187 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -31,9 +31,8 @@ impl AccountantSkel { pub fn process_request(self: &mut Self, msg: Request) -> Option { match msg { - Request::Transaction(transfer) => { - let event = Event::Transaction(transfer); - if let Err(err) = self.acc.process_event(event) { + Request::Transaction(tr) => { + if let Err(err) = self.acc.process_transfer(tr) { eprintln!("Transfer error: {:?}", err); } None diff --git a/src/event.rs b/src/event.rs index 463b82bbaa0856..94f5fc47f9589b 100644 --- a/src/event.rs +++ b/src/event.rs @@ -34,6 +34,18 @@ pub struct Transfer { pub sig: Signature, } +impl Transfer { + pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { + Transfer { + from: to, + to, + data, + last_id, + sig, + } + } +} + /// 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 @@ -47,14 +59,7 @@ pub enum Event { impl Event { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - let transfer = Transfer { - from: to, - to, - data, - last_id, - sig, - }; - Event::Transaction(transfer) + Event::Transaction(Transfer::new_claim(to, data, last_id, sig)) } } diff --git a/src/historian.rs b/src/historian.rs index 6db553b4768f58..bdb019ed9a46a2 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -7,7 +7,7 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::time::Instant; use log::{hash, Entry, Sha256Hash}; use logger::{ExitReason, Logger}; -use event::{get_signature, Event, Signature}; +use event::{Event, Signature}; use serde::Serialize; use std::fmt::Debug; @@ -55,13 +55,11 @@ impl Historian { } } -pub fn reserve_signature(sigs: &mut HashSet, event: &Event) -> bool { - if let Some(sig) = get_signature(&event) { - if sigs.contains(&sig) { - return false; - } - sigs.insert(sig); +pub fn reserve_signature(sigs: &mut HashSet, sig: &Signature) -> bool { + if sigs.contains(sig) { + return false; } + sigs.insert(*sig); true } @@ -116,10 +114,10 @@ mod tests { let data = b"hello, world"; let zero = Sha256Hash::default(); let sig = sign_claim_data(&data, &keypair, &zero); - let event0 = Event::new_claim(to, &data, zero, sig); + let tr0 = Transfer::new_claim(to, &data, zero, sig); let mut sigs = HashSet::new(); - assert!(reserve_signature(&mut sigs, &event0)); - assert!(!reserve_signature(&mut sigs, &event0)); + assert!(reserve_signature(&mut sigs, &tr0.sig)); + assert!(!reserve_signature(&mut sigs, &tr0.sig)); } #[test] From 66bf889c392b48c9dd85afa9a5cd044917b5f44c Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 11:54:45 -0700 Subject: [PATCH 06/10] Rename Transfer to Transaction struct names should be nouns --- src/accountant.rs | 20 ++++++++++---------- src/accountant_skel.rs | 8 ++++---- src/accountant_stub.rs | 4 ++-- src/bin/client-demo.rs | 4 ++-- src/event.rs | 29 ++++++++--------------------- src/genesis.rs | 6 +++--- src/historian.rs | 2 +- src/log.rs | 8 ++++---- 8 files changed, 34 insertions(+), 47 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index 755a5510f10dbd..5645a9271e0925 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,8 +3,8 @@ //! transfer funds to other users. use log::{Entry, Sha256Hash}; -use event::{get_pubkey, sign_transaction_data, verify_transfer, Event, PublicKey, Signature, - Transfer}; +use event::{get_pubkey, sign_transaction_data, verify_transaction, Event, PublicKey, Signature, + Transaction}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -76,8 +76,8 @@ impl Accountant { allow_deposits && from == to } - pub fn process_transfer(self: &mut Self, tr: Transfer) -> Result<()> { - if !verify_transfer(&tr) { + pub fn process_transaction(self: &mut Self, tr: Transaction) -> Result<()> { + if !verify_transaction(&tr) { return Err(AccountingError::InvalidTransfer); } @@ -85,7 +85,7 @@ impl Accountant { return Err(AccountingError::InsufficientFunds); } - self.process_verified_transfer(&tr, false)?; + self.process_verified_transaction(&tr, false)?; if let Err(SendError(_)) = self.historian.sender.send(Event::Transaction(tr)) { return Err(AccountingError::SendError); } @@ -93,9 +93,9 @@ impl Accountant { Ok(()) } - fn process_verified_transfer( + fn process_verified_transaction( self: &mut Self, - tr: &Transfer, + tr: &Transaction, allow_deposits: bool, ) -> Result<()> { if !reserve_signature(&mut self.historian.signatures, &tr.sig) { @@ -126,7 +126,7 @@ impl Accountant { ) -> Result<()> { match *event { Event::Tick => Ok(()), - Event::Transaction(ref tr) => self.process_verified_transfer(tr, allow_deposits), + Event::Transaction(ref tr) => self.process_verified_transaction(tr, allow_deposits), } } @@ -139,14 +139,14 @@ impl Accountant { let from = get_pubkey(keypair); let last_id = self.last_id; let sig = sign_transaction_data(&n, keypair, &to, &last_id); - let tr = Transfer { + let tr = Transaction { from, to, data: n, last_id, sig, }; - self.process_transfer(tr).map(|_| sig) + self.process_transaction(tr).map(|_| sig) } pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option { diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index ae820246442187..262fe2cba87d9b 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,6 @@ use std::io; use accountant::Accountant; -use event::{Event, PublicKey, Transfer}; +use event::{PublicKey, Transaction}; use log::{Entry, Sha256Hash}; use std::net::UdpSocket; use bincode::{deserialize, serialize}; @@ -11,7 +11,7 @@ pub struct AccountantSkel { #[derive(Serialize, Deserialize, Debug)] pub enum Request { - Transaction(Transfer), + Transaction(Transaction), GetBalance { key: PublicKey }, GetEntries { last_id: Sha256Hash }, GetId { is_last: bool }, @@ -32,8 +32,8 @@ impl AccountantSkel { pub fn process_request(self: &mut Self, msg: Request) -> Option { match msg { Request::Transaction(tr) => { - if let Err(err) = self.acc.process_transfer(tr) { - eprintln!("Transfer error: {:?}", err); + if let Err(err) = self.acc.process_transaction(tr) { + eprintln!("Transaction error: {:?}", err); } None } diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index d39858e0104747..631ff5440fcf9d 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 event::{get_pubkey, get_signature, sign_transaction_data, PublicKey, Signature, Transfer}; +use event::{get_pubkey, get_signature, sign_transaction_data, PublicKey, Signature, Transaction}; use log::{Entry, Sha256Hash}; use ring::signature::Ed25519KeyPair; use accountant_skel::{Request, Response}; @@ -33,7 +33,7 @@ impl AccountantStub { last_id: Sha256Hash, sig: Signature, ) -> io::Result { - let req = Request::Transaction(Transfer { + let req = Request::Transaction(Transaction { from, to, data: val, diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 5e66d0c8713e95..2f518e8cb41ecd 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -3,7 +3,7 @@ extern crate silk; use silk::accountant_stub::AccountantStub; use silk::event::{generate_keypair, get_pubkey, sign_transaction_data, verify_event, Event, - Transfer}; + Transaction}; use silk::genesis::Genesis; use std::time::Instant; use std::net::UdpSocket; @@ -48,7 +48,7 @@ fn main() { println!("Verify signatures..."); let now = Instant::now(); for &(k, s) in &sigs { - let e = Event::Transaction(Transfer { + let e = Event::Transaction(Transaction { from: alice_pubkey, to: k, data: one, diff --git a/src/event.rs b/src/event.rs index 94f5fc47f9589b..98d426be044167 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,17 +1,4 @@ -//! 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 'id' field is the result -/// of hashing 'id' from the previous entry 'num_hashes' times. The 'event' -/// field points to an Event that took place shortly after 'id' 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. +//! The `event` crate provides the data structures for log events. use generic_array::GenericArray; use generic_array::typenum::{U32, U64}; @@ -26,7 +13,7 @@ pub type PublicKey = GenericArray; pub type Signature = GenericArray; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Transfer { +pub struct Transaction { pub from: PublicKey, pub to: PublicKey, pub data: T, @@ -34,9 +21,9 @@ pub struct Transfer { pub sig: Signature, } -impl Transfer { +impl Transaction { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - Transfer { + Transaction { from: to, to, data, @@ -54,12 +41,12 @@ impl Transfer { #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum Event { Tick, - Transaction(Transfer), + Transaction(Transaction), } impl Event { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - Event::Transaction(Transfer::new_claim(to, data, last_id, sig)) + Event::Transaction(Transaction::new_claim(to, data, last_id, sig)) } } @@ -119,11 +106,11 @@ pub fn get_signature(event: &Event) -> Option { pub fn verify_event(event: &Event) -> bool { match *event { Event::Tick => true, - Event::Transaction(ref tr) => verify_transfer(tr), + Event::Transaction(ref tr) => verify_transaction(tr), } } -pub fn verify_transfer(tr: &Transfer) -> bool { +pub fn verify_transaction(tr: &Transaction) -> bool { let sign_data = serialize(&(&tr.from, &tr.to, &tr.data, &tr.last_id)).unwrap(); verify_signature(&tr.from, &sign_data, &tr.sig) } diff --git a/src/genesis.rs b/src/genesis.rs index 2d8be7c2b613af..d379590b4fd523 100644 --- a/src/genesis.rs +++ b/src/genesis.rs @@ -1,6 +1,6 @@ //! A library for generating the chain's genesis block. -use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey, Transfer}; +use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey, Transaction}; use log::{create_entries, hash, Entry, Sha256Hash}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; @@ -56,7 +56,7 @@ impl Genesis { let last_id = self.get_seed(); let from = self.get_pubkey(); let sig = sign_transaction_data(&data, &self.get_keypair(), to, &last_id); - Event::Transaction(Transfer { + Event::Transaction(Transaction { from, to: *to, data, @@ -93,7 +93,7 @@ mod tests { fn test_create_events() { let mut events = Genesis::new(100, vec![]).create_events().into_iter(); assert_eq!(events.next().unwrap(), Event::Tick); - if let Event::Transaction(Transfer { from, to, .. }) = events.next().unwrap() { + if let Event::Transaction(Transaction { from, to, .. }) = events.next().unwrap() { assert_eq!(from, to); } else { assert!(false); diff --git a/src/historian.rs b/src/historian.rs index bdb019ed9a46a2..7b700e0613bab8 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -114,7 +114,7 @@ mod tests { let data = b"hello, world"; let zero = Sha256Hash::default(); let sig = sign_claim_data(&data, &keypair, &zero); - let tr0 = Transfer::new_claim(to, &data, zero, sig); + let tr0 = Transaction::new_claim(to, &data, zero, sig); let mut sigs = HashSet::new(); assert!(reserve_signature(&mut sigs, &tr0.sig)); assert!(!reserve_signature(&mut sigs, &tr0.sig)); diff --git a/src/log.rs b/src/log.rs index 6dc20792cad97e..b5af9abf15baaf 100644 --- a/src/log.rs +++ b/src/log.rs @@ -169,7 +169,7 @@ pub fn next_ticks(start_hash: &Sha256Hash, num_hashes: u64, len: usize) -> Vec Date: Tue, 6 Mar 2018 12:18:17 -0700 Subject: [PATCH 07/10] Give Transaction its own module --- src/accountant.rs | 7 ++- src/accountant_skel.rs | 2 +- src/accountant_stub.rs | 3 +- src/bin/client-demo.rs | 4 +- src/bin/demo.rs | 3 +- src/bin/genesis-file-demo.rs | 2 +- src/event.rs | 101 +--------------------------------- src/genesis.rs | 3 +- src/historian.rs | 4 +- src/lib.rs | 1 + src/log.rs | 3 +- src/logger.rs | 1 + src/transaction.rs | 104 +++++++++++++++++++++++++++++++++++ 13 files changed, 126 insertions(+), 112 deletions(-) create mode 100644 src/transaction.rs diff --git a/src/accountant.rs b/src/accountant.rs index 5645a9271e0925..a36243e02667a7 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -3,8 +3,9 @@ //! transfer funds to other users. use log::{Entry, Sha256Hash}; -use event::{get_pubkey, sign_transaction_data, verify_transaction, Event, PublicKey, Signature, - Transaction}; +use event::Event; +use transaction::{get_pubkey, sign_transaction_data, verify_transaction, PublicKey, Signature, + Transaction}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -157,7 +158,7 @@ impl Accountant { #[cfg(test)] mod tests { use super::*; - use event::{generate_keypair, get_pubkey}; + use transaction::{generate_keypair, get_pubkey}; use logger::ExitReason; use genesis::Creator; diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 262fe2cba87d9b..be00c762052e69 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,6 @@ use std::io; use accountant::Accountant; -use event::{PublicKey, Transaction}; +use transaction::{PublicKey, Transaction}; use log::{Entry, Sha256Hash}; use std::net::UdpSocket; use bincode::{deserialize, serialize}; diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index 631ff5440fcf9d..fa46d442b884c2 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -5,7 +5,8 @@ use std::net::UdpSocket; use std::io; use bincode::{deserialize, serialize}; -use event::{get_pubkey, get_signature, sign_transaction_data, PublicKey, Signature, Transaction}; +use event::get_signature; +use transaction::{get_pubkey, sign_transaction_data, PublicKey, Signature, Transaction}; use log::{Entry, Sha256Hash}; use ring::signature::Ed25519KeyPair; use accountant_skel::{Request, Response}; diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 2f518e8cb41ecd..0c3ebe519b26d1 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -2,8 +2,8 @@ extern crate serde_json; extern crate silk; use silk::accountant_stub::AccountantStub; -use silk::event::{generate_keypair, get_pubkey, sign_transaction_data, verify_event, Event, - Transaction}; +use silk::event::{verify_event, Event}; +use silk::transaction::{generate_keypair, get_pubkey, sign_transaction_data, Transaction}; use silk::genesis::Genesis; use std::time::Instant; use std::net::UdpSocket; diff --git a/src/bin/demo.rs b/src/bin/demo.rs index 4f6967e4188688..d7a364de8b1841 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -2,7 +2,8 @@ extern crate silk; use silk::historian::Historian; use silk::log::{verify_slice, Entry, Sha256Hash}; -use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event}; +use silk::transaction::{generate_keypair, get_pubkey, sign_claim_data}; +use silk::event::Event; use std::thread::sleep; use std::time::Duration; use std::sync::mpsc::SendError; diff --git a/src/bin/genesis-file-demo.rs b/src/bin/genesis-file-demo.rs index 26a47c5e8b94aa..4c4cbe502aa1ef 100644 --- a/src/bin/genesis-file-demo.rs +++ b/src/bin/genesis-file-demo.rs @@ -2,7 +2,7 @@ extern crate serde_json; extern crate silk; use silk::genesis::{Creator, Genesis}; -use silk::event::{generate_keypair, get_pubkey}; +use silk::transaction::{generate_keypair, get_pubkey}; fn main() { let alice = Creator { diff --git a/src/event.rs b/src/event.rs index 98d426be044167..88a44c402e8e3b 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,38 +1,9 @@ //! The `event` crate provides the data structures for log events. -use generic_array::GenericArray; -use generic_array::typenum::{U32, U64}; -use ring::signature::Ed25519KeyPair; -use ring::{rand, signature}; -use untrusted; +use transaction::{verify_transaction, PublicKey, Signature, Transaction}; use serde::Serialize; -use bincode::serialize; use log::Sha256Hash; -pub type PublicKey = GenericArray; -pub type Signature = GenericArray; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Transaction { - pub from: PublicKey, - pub to: PublicKey, - pub data: T, - pub last_id: Sha256Hash, - pub sig: Signature, -} - -impl Transaction { - pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { - Transaction { - from: to, - to, - data, - last_id, - sig, - } - } -} - /// 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 @@ -50,52 +21,6 @@ impl Event { } } -/// Return a new ED25519 keypair -pub fn generate_keypair() -> Ed25519KeyPair { - 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. -fn sign_serialized(data: &T, keypair: &Ed25519KeyPair) -> Signature { - 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, - last_id: &Sha256Hash, -) -> Signature { - let from = &get_pubkey(keypair); - sign_serialized(&(from, to, data, last_id), keypair) -} - -/// Return a signature for the given data using the private key from the given keypair. -pub fn sign_claim_data( - data: &T, - keypair: &Ed25519KeyPair, - last_id: &Sha256Hash, -) -> Signature { - sign_transaction_data(data, keypair, &get_pubkey(keypair), last_id) -} - -/// 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 { - 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, @@ -109,27 +34,3 @@ pub fn verify_event(event: &Event) -> bool { Event::Transaction(ref tr) => verify_transaction(tr), } } - -pub fn verify_transaction(tr: &Transaction) -> bool { - let sign_data = serialize(&(&tr.from, &tr.to, &tr.data, &tr.last_id)).unwrap(); - verify_signature(&tr.from, &sign_data, &tr.sig) -} - -#[cfg(test)] -mod tests { - use super::*; - use bincode::{deserialize, serialize}; - - #[test] - fn test_serialize_claim() { - let claim0 = Event::new_claim( - Default::default(), - 0u8, - Default::default(), - Default::default(), - ); - let buf = serialize(&claim0).unwrap(); - let claim1: Event = deserialize(&buf).unwrap(); - assert_eq!(claim1, claim0); - } -} diff --git a/src/genesis.rs b/src/genesis.rs index d379590b4fd523..fcc3e321f81de0 100644 --- a/src/genesis.rs +++ b/src/genesis.rs @@ -1,6 +1,7 @@ //! A library for generating the chain's genesis block. -use event::{generate_keypair, get_pubkey, sign_transaction_data, Event, PublicKey, Transaction}; +use event::Event; +use transaction::{generate_keypair, get_pubkey, sign_transaction_data, PublicKey, Transaction}; use log::{create_entries, hash, Entry, Sha256Hash}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; diff --git a/src/historian.rs b/src/historian.rs index 7b700e0613bab8..8df3eac77f35ef 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -7,7 +7,8 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::time::Instant; use log::{hash, Entry, Sha256Hash}; use logger::{ExitReason, Logger}; -use event::{Event, Signature}; +use transaction::Signature; +use event::Event; use serde::Serialize; use std::fmt::Debug; @@ -68,6 +69,7 @@ mod tests { use super::*; use log::*; use event::*; + use transaction::*; use std::thread::sleep; use std::time::Duration; diff --git a/src/lib.rs b/src/lib.rs index bf65fb2d5494e3..e264f0cd018d56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod log; pub mod logger; pub mod event; +pub mod transaction; pub mod genesis; pub mod historian; pub mod accountant; diff --git a/src/log.rs b/src/log.rs index b5af9abf15baaf..d1f17fca99adc0 100644 --- a/src/log.rs +++ b/src/log.rs @@ -169,7 +169,8 @@ pub fn next_ticks(start_hash: &Sha256Hash, num_hashes: u64, len: usize) -> Vec; +pub type Signature = GenericArray; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct Transaction { + pub from: PublicKey, + pub to: PublicKey, + pub data: T, + pub last_id: Sha256Hash, + pub sig: Signature, +} + +impl Transaction { + pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { + Transaction { + from: to, + to, + data, + last_id, + sig, + } + } +} + +/// Return a new ED25519 keypair +pub fn generate_keypair() -> Ed25519KeyPair { + 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. +fn sign_serialized(data: &T, keypair: &Ed25519KeyPair) -> Signature { + 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, + last_id: &Sha256Hash, +) -> Signature { + let from = &get_pubkey(keypair); + sign_serialized(&(from, to, data, last_id), keypair) +} + +/// Return a signature for the given data using the private key from the given keypair. +pub fn sign_claim_data( + data: &T, + keypair: &Ed25519KeyPair, + last_id: &Sha256Hash, +) -> Signature { + sign_transaction_data(data, keypair, &get_pubkey(keypair), last_id) +} + +/// 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 { + 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 verify_transaction(tr: &Transaction) -> bool { + let sign_data = serialize(&(&tr.from, &tr.to, &tr.data, &tr.last_id)).unwrap(); + verify_signature(&tr.from, &sign_data, &tr.sig) +} + +#[cfg(test)] +mod tests { + use super::*; + use bincode::{deserialize, serialize}; + + #[test] + fn test_serialize_claim() { + let claim0 = Transaction::new_claim( + Default::default(), + 0u8, + Default::default(), + Default::default(), + ); + let buf = serialize(&claim0).unwrap(); + let claim1: Transaction = deserialize(&buf).unwrap(); + assert_eq!(claim1, claim0); + } +} From b019416518019cde80ecc3a7f17b110f86c58c5d Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 12:26:39 -0700 Subject: [PATCH 08/10] Move verify into methods A little overly-coupled to Serialize, but makes the code a lot tighter --- src/accountant.rs | 5 ++--- src/accountant_stub.rs | 3 +-- src/bin/client-demo.rs | 4 ++-- src/event.rs | 24 ++++++++++++------------ src/log.rs | 8 ++++---- src/logger.rs | 2 +- src/transaction.rs | 12 ++++++------ 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/accountant.rs b/src/accountant.rs index a36243e02667a7..4cd094d2fcad7a 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -4,8 +4,7 @@ use log::{Entry, Sha256Hash}; use event::Event; -use transaction::{get_pubkey, sign_transaction_data, verify_transaction, PublicKey, Signature, - Transaction}; +use transaction::{get_pubkey, sign_transaction_data, PublicKey, Signature, Transaction}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -78,7 +77,7 @@ impl Accountant { } pub fn process_transaction(self: &mut Self, tr: Transaction) -> Result<()> { - if !verify_transaction(&tr) { + if !tr.verify() { return Err(AccountingError::InvalidTransfer); } diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index fa46d442b884c2..da53c25c6eddd0 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -5,7 +5,6 @@ use std::net::UdpSocket; use std::io; use bincode::{deserialize, serialize}; -use event::get_signature; use transaction::{get_pubkey, sign_transaction_data, PublicKey, Signature, Transaction}; use log::{Entry, Sha256Hash}; use ring::signature::Ed25519KeyPair; @@ -109,7 +108,7 @@ impl AccountantStub { if let Response::Entries { entries } = resp { for Entry { id, event, .. } in entries { self.last_id = Some(id); - if let Some(sig) = get_signature(&event) { + if let Some(sig) = event.get_signature() { if sig == *wait_sig { return Ok(()); } diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 0c3ebe519b26d1..9e9581d6deb502 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -2,7 +2,7 @@ extern crate serde_json; extern crate silk; use silk::accountant_stub::AccountantStub; -use silk::event::{verify_event, Event}; +use silk::event::Event; use silk::transaction::{generate_keypair, get_pubkey, sign_transaction_data, Transaction}; use silk::genesis::Genesis; use std::time::Instant; @@ -55,7 +55,7 @@ fn main() { last_id, sig: s, }); - assert!(verify_event(&e)); + assert!(e.verify()); } let duration = now.elapsed(); let ns = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; diff --git a/src/event.rs b/src/event.rs index 88a44c402e8e3b..c5b650bfb363e0 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,6 @@ //! The `event` crate provides the data structures for log events. -use transaction::{verify_transaction, PublicKey, Signature, Transaction}; +use transaction::{PublicKey, Signature, Transaction}; use serde::Serialize; use log::Sha256Hash; @@ -15,22 +15,22 @@ pub enum Event { Transaction(Transaction), } -impl Event { +impl Event { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { Event::Transaction(Transaction::new_claim(to, data, last_id, sig)) } -} -pub fn get_signature(event: &Event) -> Option { - match *event { - Event::Tick => None, - Event::Transaction(ref tr) => Some(tr.sig), + pub fn get_signature(&self) -> Option { + match *self { + Event::Tick => None, + Event::Transaction(ref tr) => Some(tr.sig), + } } -} -pub fn verify_event(event: &Event) -> bool { - match *event { - Event::Tick => true, - Event::Transaction(ref tr) => verify_transaction(tr), + pub fn verify(&self) -> bool { + match *self { + Event::Tick => true, + Event::Transaction(ref tr) => tr.verify(), + } } } diff --git a/src/log.rs b/src/log.rs index d1f17fca99adc0..75e60ff61be0b5 100644 --- a/src/log.rs +++ b/src/log.rs @@ -16,7 +16,7 @@ use generic_array::GenericArray; use generic_array::typenum::U32; use serde::Serialize; -use event::{get_signature, verify_event, Event}; +use event::Event; use sha2::{Digest, Sha256}; use rayon::prelude::*; @@ -64,7 +64,7 @@ pub fn next_hash( event: &Event, ) -> Sha256Hash { let mut id = *start_hash; - let sig = get_signature(event); + let sig = event.get_signature(); let start_index = if sig.is_some() { 1 } else { 0 }; for _ in start_index..num_hashes { id = hash(&id); @@ -81,7 +81,7 @@ pub fn create_entry( cur_hashes: u64, event: Event, ) -> Entry { - let sig = get_signature(&event); + let sig = event.get_signature(); let num_hashes = cur_hashes + if sig.is_some() { 1 } else { 0 }; let id = next_hash(start_hash, 0, &event); Entry { @@ -116,7 +116,7 @@ pub fn next_tick(start_hash: &Sha256Hash, num_hashes: u64) -> Entr /// Verifies self.id 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 { - if !verify_event(&entry.event) { + if !entry.event.verify() { return false; } entry.id == next_hash(start_hash, entry.num_hashes, &entry.event) diff --git a/src/logger.rs b/src/logger.rs index daca8c820a2e77..63a5d1019330fa 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -93,6 +93,6 @@ mod tests { zero, sig, ); - assert!(!verify_event(&event0)); + assert!(!event0.verify()); } } diff --git a/src/transaction.rs b/src/transaction.rs index a9e455613ae5ac..626d1c0f85fb4a 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -21,7 +21,7 @@ pub struct Transaction { pub sig: Signature, } -impl Transaction { +impl Transaction { pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self { Transaction { from: to, @@ -31,6 +31,11 @@ impl Transaction { sig, } } + + pub fn verify(&self) -> bool { + let sign_data = serialize(&(&self.from, &self.to, &self.data, &self.last_id)).unwrap(); + verify_signature(&self.from, &sign_data, &self.sig) + } } /// Return a new ED25519 keypair @@ -79,11 +84,6 @@ pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_byte signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok() } -pub fn verify_transaction(tr: &Transaction) -> bool { - let sign_data = serialize(&(&tr.from, &tr.to, &tr.data, &tr.last_id)).unwrap(); - verify_signature(&tr.from, &sign_data, &tr.sig) -} - #[cfg(test)] mod tests { use super::*; From 5d0356f74b42475174603be4e3d533cbd5368183 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 12:35:12 -0700 Subject: [PATCH 09/10] Move verify_entry to a method as well --- src/log.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/log.rs b/src/log.rs index 75e60ff61be0b5..405ac6e4c53899 100644 --- a/src/log.rs +++ b/src/log.rs @@ -29,7 +29,7 @@ pub struct Entry { pub event: Event, } -impl Entry { +impl Entry { /// Creates a Entry from the number of hashes 'num_hashes' since the previous event /// and that resulting 'id'. pub fn new_tick(num_hashes: u64, id: &Sha256Hash) -> Self { @@ -39,6 +39,15 @@ impl Entry { event: Event::Tick, } } + + /// Verifies self.id 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(&self, start_hash: &Sha256Hash) -> bool { + if !self.event.verify() { + return false; + } + self.id == next_hash(start_hash, self.num_hashes, &self.event) + } } /// Return a Sha256 hash for the given data. @@ -113,34 +122,25 @@ pub fn next_tick(start_hash: &Sha256Hash, num_hashes: u64) -> Entr } } -/// Verifies self.id 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 { - if !entry.event.verify() { - return false; - } - entry.id == next_hash(start_hash, entry.num_hashes, &entry.event) -} - /// Verifies the hashes and counts of a slice of events are all consistent. pub fn verify_slice(events: &[Entry], start_hash: &Sha256Hash) -> bool { let genesis = [Entry::new_tick(Default::default(), start_hash)]; let event_pairs = genesis.par_iter().chain(events).zip(events); - event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.id)) + event_pairs.all(|(x0, x1)| x1.verify(&x0.id)) } /// Verifies the hashes and counts of a slice of events are all consistent. pub fn verify_slice_i64(events: &[Entry], start_hash: &Sha256Hash) -> bool { let genesis = [Entry::new_tick(Default::default(), start_hash)]; let event_pairs = genesis.par_iter().chain(events).zip(events); - event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.id)) + event_pairs.all(|(x0, x1)| x1.verify(&x0.id)) } /// Verifies the hashes and events serially. Exists only for reference. pub fn verify_slice_seq(events: &[Entry], start_hash: &Sha256Hash) -> bool { let genesis = [Entry::new_tick(0, start_hash)]; let mut event_pairs = genesis.iter().chain(events).zip(events); - event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.id)) + event_pairs.all(|(x0, x1)| x1.verify(&x0.id)) } pub fn create_entries( @@ -176,10 +176,10 @@ mod tests { fn test_event_verify() { let zero = Sha256Hash::default(); let one = hash(&zero); - assert!(verify_entry::(&Entry::new_tick(0, &zero), &zero)); // base case - assert!(!verify_entry::(&Entry::new_tick(0, &zero), &one)); // base case, bad - assert!(verify_entry::(&next_tick(&zero, 1), &zero)); // inductive step - assert!(!verify_entry::(&next_tick(&zero, 1), &one)); // inductive step, bad + assert!(Entry::::new_tick(0, &zero).verify(&zero)); // base case + assert!(!Entry::::new_tick(0, &zero).verify(&one)); // base case, bad + assert!(next_tick::(&zero, 1).verify(&zero)); // inductive step + assert!(!next_tick::(&zero, 1).verify(&one)); // inductive step, bad } #[test] From 624c151ca28edf6aca3ace9193248a010e85e6fc Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 6 Mar 2018 12:48:26 -0700 Subject: [PATCH 10/10] Add signature module Because things other than transactions can be signed. --- src/accountant.rs | 5 +++-- src/accountant_skel.rs | 3 ++- src/accountant_stub.rs | 3 ++- src/bin/client-demo.rs | 3 ++- src/bin/demo.rs | 3 ++- src/bin/genesis-file-demo.rs | 2 +- src/event.rs | 3 ++- src/genesis.rs | 3 ++- src/historian.rs | 3 ++- src/lib.rs | 1 + src/log.rs | 4 ++-- src/logger.rs | 1 + src/signature.rs | 30 ++++++++++++++++++++++++++++++ src/transaction.rs | 31 ++----------------------------- 14 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 src/signature.rs diff --git a/src/accountant.rs b/src/accountant.rs index 4cd094d2fcad7a..55cf559a8e6b9c 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -4,7 +4,8 @@ use log::{Entry, Sha256Hash}; use event::Event; -use transaction::{get_pubkey, sign_transaction_data, PublicKey, Signature, Transaction}; +use transaction::{sign_transaction_data, Transaction}; +use signature::{get_pubkey, PublicKey, Signature}; use genesis::Genesis; use historian::{reserve_signature, Historian}; use ring::signature::Ed25519KeyPair; @@ -157,7 +158,7 @@ impl Accountant { #[cfg(test)] mod tests { use super::*; - use transaction::{generate_keypair, get_pubkey}; + use signature::{generate_keypair, get_pubkey}; use logger::ExitReason; use genesis::Creator; diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index be00c762052e69..4c6c12a981e5a7 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -1,6 +1,7 @@ use std::io; use accountant::Accountant; -use transaction::{PublicKey, Transaction}; +use transaction::Transaction; +use signature::PublicKey; use log::{Entry, Sha256Hash}; use std::net::UdpSocket; use bincode::{deserialize, serialize}; diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index da53c25c6eddd0..4e4b6942c07061 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -5,7 +5,8 @@ use std::net::UdpSocket; use std::io; use bincode::{deserialize, serialize}; -use transaction::{get_pubkey, sign_transaction_data, PublicKey, Signature, Transaction}; +use transaction::{sign_transaction_data, Transaction}; +use signature::{get_pubkey, PublicKey, Signature}; use log::{Entry, Sha256Hash}; use ring::signature::Ed25519KeyPair; use accountant_skel::{Request, Response}; diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 9e9581d6deb502..5a6279eef7b8a5 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -3,7 +3,8 @@ extern crate silk; use silk::accountant_stub::AccountantStub; use silk::event::Event; -use silk::transaction::{generate_keypair, get_pubkey, sign_transaction_data, Transaction}; +use silk::signature::{generate_keypair, get_pubkey}; +use silk::transaction::{sign_transaction_data, Transaction}; use silk::genesis::Genesis; use std::time::Instant; use std::net::UdpSocket; diff --git a/src/bin/demo.rs b/src/bin/demo.rs index d7a364de8b1841..aa8424c94f78a6 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -2,7 +2,8 @@ extern crate silk; use silk::historian::Historian; use silk::log::{verify_slice, Entry, Sha256Hash}; -use silk::transaction::{generate_keypair, get_pubkey, sign_claim_data}; +use silk::signature::{generate_keypair, get_pubkey}; +use silk::transaction::sign_claim_data; use silk::event::Event; use std::thread::sleep; use std::time::Duration; diff --git a/src/bin/genesis-file-demo.rs b/src/bin/genesis-file-demo.rs index 4c4cbe502aa1ef..8a8adf5d66bd0f 100644 --- a/src/bin/genesis-file-demo.rs +++ b/src/bin/genesis-file-demo.rs @@ -2,7 +2,7 @@ extern crate serde_json; extern crate silk; use silk::genesis::{Creator, Genesis}; -use silk::transaction::{generate_keypair, get_pubkey}; +use silk::signature::{generate_keypair, get_pubkey}; fn main() { let alice = Creator { diff --git a/src/event.rs b/src/event.rs index c5b650bfb363e0..c75b3b20d0a63c 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,7 @@ //! The `event` crate provides the data structures for log events. -use transaction::{PublicKey, Signature, Transaction}; +use signature::{PublicKey, Signature}; +use transaction::Transaction; use serde::Serialize; use log::Sha256Hash; diff --git a/src/genesis.rs b/src/genesis.rs index fcc3e321f81de0..ead4f053b14971 100644 --- a/src/genesis.rs +++ b/src/genesis.rs @@ -1,7 +1,8 @@ //! A library for generating the chain's genesis block. use event::Event; -use transaction::{generate_keypair, get_pubkey, sign_transaction_data, PublicKey, Transaction}; +use transaction::{sign_transaction_data, Transaction}; +use signature::{generate_keypair, get_pubkey, PublicKey}; use log::{create_entries, hash, Entry, Sha256Hash}; use ring::rand::SystemRandom; use ring::signature::Ed25519KeyPair; diff --git a/src/historian.rs b/src/historian.rs index 8df3eac77f35ef..8af1d0424dda98 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -7,7 +7,7 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::time::Instant; use log::{hash, Entry, Sha256Hash}; use logger::{ExitReason, Logger}; -use transaction::Signature; +use signature::Signature; use event::Event; use serde::Serialize; use std::fmt::Debug; @@ -70,6 +70,7 @@ mod tests { use log::*; use event::*; use transaction::*; + use signature::*; use std::thread::sleep; use std::time::Duration; diff --git a/src/lib.rs b/src/lib.rs index e264f0cd018d56..91cbf8b703da2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod log; pub mod logger; pub mod event; pub mod transaction; +pub mod signature; pub mod genesis; pub mod historian; pub mod accountant; diff --git a/src/log.rs b/src/log.rs index 405ac6e4c53899..7aea7cc1c69ff1 100644 --- a/src/log.rs +++ b/src/log.rs @@ -169,8 +169,8 @@ pub fn next_ticks(start_hash: &Sha256Hash, num_hashes: u64, len: usize) -> Vec; +pub type Signature = GenericArray; + +/// Return a new ED25519 keypair +pub fn generate_keypair() -> Ed25519KeyPair { + 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()) +} + +/// 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 { + 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() +} diff --git a/src/transaction.rs b/src/transaction.rs index 626d1c0f85fb4a..ee67a58a8b0c8d 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,17 +1,11 @@ //! The `transaction` crate provides functionality for creating log transactions. -use generic_array::GenericArray; -use generic_array::typenum::{U32, U64}; +use signature::{get_pubkey, verify_signature, PublicKey, Signature}; use ring::signature::Ed25519KeyPair; -use ring::{rand, signature}; -use untrusted; use serde::Serialize; use bincode::serialize; use log::Sha256Hash; -pub type PublicKey = GenericArray; -pub type Signature = GenericArray; - #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Transaction { pub from: PublicKey, @@ -38,22 +32,9 @@ impl Transaction { } } -/// Return a new ED25519 keypair -pub fn generate_keypair() -> Ed25519KeyPair { - 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. fn sign_serialized(data: &T, keypair: &Ed25519KeyPair) -> Signature { let serialized = serialize(data).unwrap(); - GenericArray::clone_from_slice(keypair.sign(&serialized).as_ref()) + Signature::clone_from_slice(keypair.sign(&serialized).as_ref()) } /// Return a signature for the given transaction data using the private key from the given keypair. @@ -76,14 +57,6 @@ pub fn sign_claim_data( sign_transaction_data(data, keypair, &get_pubkey(keypair), last_id) } -/// 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 { - 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() -} - #[cfg(test)] mod tests { use super::*;