diff --git a/README.md b/README.md index 57a0f0e5c09270..62b451a7a96e94 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,18 @@ with by verifying each entry's hash can be generated from the hash in the previo extern crate silk; use silk::historian::Historian; -use silk::log::{verify_slice, Entry, Event, Sha256Hash}; +use silk::log::{verify_slice, Entry, Sha256Hash}; +use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event}; use std::thread::sleep; use std::time::Duration; use std::sync::mpsc::SendError; -fn create_log(hist: &Historian) -> Result<(), SendError> { +fn create_log(hist: &Historian) -> Result<(), SendError>> { sleep(Duration::from_millis(15)); let data = Sha256Hash::default(); - hist.sender.send(Event::Claim { data })?; + let keypair = generate_keypair(); + let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair)); + hist.sender.send(event0)?; sleep(Duration::from_millis(10)); Ok(()) } @@ -55,11 +58,10 @@ fn main() { let hist = Historian::new(&seed, Some(10)); create_log(&hist).expect("send error"); drop(hist.sender); - let entries: Vec = hist.receiver.iter().collect(); + let entries: Vec> = hist.receiver.iter().collect(); for entry in &entries { println!("{:?}", entry); } - // Proof-of-History: Verify the historian learned about the events // in the same order they appear in the vector. assert!(verify_slice(&entries, &seed)); @@ -70,7 +72,7 @@ Running the program should produce a log similar to: ```rust Entry { num_hashes: 0, end_hash: [0, ...], event: Tick } -Entry { num_hashes: 2, end_hash: [67, ...], event: Claim { data: [37, ...] } } +Entry { num_hashes: 2, end_hash: [67, ...], event: Transaction { data: [37, ...] } } Entry { num_hashes: 3, end_hash: [123, ...], event: Tick } ``` diff --git a/src/accountant.rs b/src/accountant.rs index 627f214badabf4..69966c49de1c37 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -2,11 +2,22 @@ //! 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}; +use std::sync::mpsc::SendError; use std::collections::HashMap; +use std::result; + +#[derive(Debug, PartialEq, Eq)] +pub enum AccountingError { + InsufficientFunds, + InvalidEvent, + SendError, +} + +pub type Result = result::Result; pub struct Accountant { pub historian: Historian, @@ -24,71 +35,43 @@ impl Accountant { } } - pub fn process_event(self: &mut Self, event: &Event) { - match *event { - Event::Claim { key, data, .. } => { - if self.balances.contains_key(&key) { - if let Some(x) = self.balances.get_mut(&key) { - *x += data; - } - } else { - self.balances.insert(key, data); - } - } - Event::Transaction { from, to, data, .. } => { - if let Some(x) = self.balances.get_mut(&from) { - *x -= data; - } - if self.balances.contains_key(&to) { - if let Some(x) = self.balances.get_mut(&to) { - *x += data; - } - } else { - self.balances.insert(to, data); - } - } - _ => (), - } - } - pub fn sync(self: &mut Self) -> Vec> { let mut entries = vec![]; while let Ok(entry) = self.historian.receiver.try_recv() { entries.push(entry); } - // TODO: Does this cause the historian's channel to get blocked? - //use log::verify_slice_u64; - //println!("accountant: verifying {} entries...", entries.len()); - //assert!(verify_slice_u64(&entries, &self.end_hash)); - //println!("accountant: Done verifying {} entries.", entries.len()); + if let Some(last_entry) = entries.last() { self.end_hash = last_entry.end_hash; } - for e in &entries { - self.process_event(&e.event); - } entries } - pub fn deposit_signed( - self: &Self, - key: PublicKey, - data: u64, - sig: Signature, - ) -> Result<(), SendError>> { - let event = Event::Claim { key, data, sig }; - self.historian.sender.send(event) + pub fn deposit_signed(self: &mut Self, to: PublicKey, data: u64, sig: Signature) -> Result<()> { + let event = Event::new_claim(to, data, sig); + if !self.historian.verify_event(&event) { + return Err(AccountingError::InvalidEvent); + } + if let Err(SendError(_)) = self.historian.sender.send(event) { + return Err(AccountingError::SendError); + } + + if self.balances.contains_key(&to) { + if let Some(x) = self.balances.get_mut(&to) { + *x += data; + } + } else { + self.balances.insert(to, data); + } + + Ok(()) } - pub fn deposit( - self: &Self, - n: u64, - keypair: &Ed25519KeyPair, - ) -> Result>> { - use log::{get_pubkey, sign_serialized}; + pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> Result { + use event::{get_pubkey, sign_claim_data}; let key = get_pubkey(keypair); - let sig = sign_serialized(&n, keypair); + let sig = sign_claim_data(&n, keypair); self.deposit_signed(key, n, sig).map(|_| sig) } @@ -98,19 +81,37 @@ impl Accountant { to: PublicKey, data: u64, sig: Signature, - ) -> Result<(), SendError>> { - if self.get_balance(&from).unwrap() < data { - // TODO: Replace the SendError result with a custom one. - println!("Error: Insufficient funds"); - return Ok(()); + ) -> Result<()> { + if self.get_balance(&from).unwrap_or(0) < data { + return Err(AccountingError::InsufficientFunds); } + let event = Event::Transaction { - from, + from: Some(from), to, data, sig, }; - self.historian.sender.send(event) + if !self.historian.verify_event(&event) { + return Err(AccountingError::InvalidEvent); + } + if let Err(SendError(_)) = self.historian.sender.send(event) { + return Err(AccountingError::SendError); + } + + if let Some(x) = self.balances.get_mut(&from) { + *x -= data; + } + + if self.balances.contains_key(&to) { + if let Some(x) = self.balances.get_mut(&to) { + *x += data; + } + } else { + self.balances.insert(to, data); + } + + Ok(()) } pub fn transfer( @@ -118,17 +119,15 @@ impl Accountant { n: u64, keypair: &Ed25519KeyPair, to: PublicKey, - ) -> Result>> { - use log::{get_pubkey, sign_transaction_data}; - + ) -> Result { + 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) } - pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> Result { - self.sync(); - Ok(*self.balances.get(pubkey).unwrap_or(&0)) + pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option { + self.balances.get(pubkey).map(|x| *x) } pub fn wait_on_signature(self: &mut Self, wait_sig: &Signature) { @@ -138,7 +137,6 @@ impl Accountant { let mut found = false; while !found { found = entries.iter().any(|e| match e.event { - Event::Claim { sig, .. } => sig == *wait_sig, Event::Transaction { sig, .. } => sig == *wait_sig, _ => false, }); @@ -153,7 +151,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] @@ -192,7 +190,10 @@ mod tests { acc.wait_on_signature(&sig); let bob_pubkey = get_pubkey(&bob_keypair); - acc.transfer(10_001, &alice_keypair, bob_pubkey).unwrap(); + assert_eq!( + acc.transfer(10_001, &alice_keypair, bob_pubkey), + Err(AccountingError::InsufficientFunds) + ); sleep(Duration::from_millis(30)); let alice_pubkey = get_pubkey(&alice_keypair); diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 0573299a7897f1..6dec3f3ea90f7c 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 ac1945fa62f86a..b43ffd1eaa4dda 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,9 +34,9 @@ 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_claim_data}; let key = get_pubkey(keypair); - let sig = sign_serialized(&n, keypair); + let sig = sign_claim_data(&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 cbc0d6dd308c71..9c5f1ac42d70be 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"; @@ -12,7 +12,7 @@ fn main() { let mut acc = AccountantStub::new(addr, socket); let alice_keypair = generate_keypair(); let alice_pubkey = get_pubkey(&alice_keypair); - let txs = 10_000; + let txs = 2_000; println!("Depositing {} units in Alice's account...", txs); let sig = acc.deposit(txs, &alice_keypair).unwrap(); acc.wait_on_signature(&sig).unwrap(); diff --git a/src/bin/demo.rs b/src/bin/demo.rs index a8f502a8755c68..c4b2121692f511 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_claim_data, Event}; use std::thread::sleep; use std::time::Duration; use std::sync::mpsc::SendError; @@ -11,11 +11,7 @@ fn create_log(hist: &Historian) -> Result<(), SendError; +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, + Transaction { + from: Option, + to: PublicKey, + data: T, + sig: Signature, + }, +} + +impl Event { + pub fn new_claim(to: PublicKey, data: T, sig: Signature) -> Self { + Event::Transaction { + from: None, + to, + data, + sig, + } + } +} + +/// 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. +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 { + let from = &Some(get_pubkey(keypair)); + sign_serialized(&(from, to, data), 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) -> Signature { + let to = get_pubkey(keypair); + let from: Option = None; + sign_serialized(&(&from, &to, data), 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::Transaction { sig, .. } => Some(sig), + } +} + +pub fn verify_event(event: &Event) -> bool { + use bincode::serialize; + if let Event::Transaction { + from, + to, + ref data, + sig, + } = *event + { + let sign_data = serialize(&(&from, &to, &data)).unwrap(); + if !verify_signature(&from.unwrap_or(to), &sign_data, &sig) { + return false; + } + } + true +} + +#[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()); + let buf = serialize(&claim0).unwrap(); + let claim1: Event = deserialize(&buf).unwrap(); + assert_eq!(claim1, claim0); + } +} diff --git a/src/historian.rs b/src/historian.rs index 1a0441451c502b..515a5746e98cfb 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -6,10 +6,11 @@ //! The resulting stream of entries represents ordered events in time. use std::thread::JoinHandle; -use std::collections::HashMap; +use std::collections::HashSet; 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; @@ -17,6 +18,7 @@ pub struct Historian { pub sender: SyncSender>, pub receiver: Receiver>, pub thread_hdl: JoinHandle<(Entry, ExitReason)>, + pub signatures: HashSet, } #[derive(Debug, PartialEq, Eq)] @@ -43,10 +45,25 @@ fn log_event( Ok(()) } +fn verify_event_and_reserve_signature( + signatures: &mut HashSet, + event: &Event, +) -> bool { + if !verify_event(&event) { + return false; + } + if let Some(sig) = get_signature(&event) { + if signatures.contains(&sig) { + return false; + } + signatures.insert(sig); + } + true +} + fn log_events( receiver: &Receiver>, sender: &SyncSender>, - signatures: &mut HashMap, num_hashes: &mut u64, end_hash: &mut Sha256Hash, epoch: SystemTime, @@ -64,15 +81,7 @@ fn log_events( } match receiver.try_recv() { Ok(event) => { - if verify_event(&event) { - if let Some(sig) = get_signature(&event) { - if signatures.contains_key(&sig) { - continue; - } - signatures.insert(sig, true); - } - log_event(sender, num_hashes, end_hash, event)?; - } + log_event(sender, num_hashes, end_hash, event)?; } Err(TryRecvError::Empty) => { return Ok(()); @@ -102,13 +111,11 @@ pub fn create_logger( let mut end_hash = start_hash; let mut num_hashes = 0; let mut num_ticks = 0; - let mut signatures = HashMap::new(); let epoch = SystemTime::now(); loop { if let Err(err) = log_events( &receiver, &sender, - &mut signatures, &mut num_hashes, &mut end_hash, epoch, @@ -129,18 +136,24 @@ impl Historian { let (sender, event_receiver) = sync_channel(1000); let (entry_sender, receiver) = sync_channel(1000); let thread_hdl = create_logger(*start_hash, ms_per_tick, event_receiver, entry_sender); + let signatures = HashSet::new(); Historian { sender, receiver, thread_hdl, + signatures, } } + pub fn verify_event(self: &mut Self, event: &Event) -> bool { + return verify_event_and_reserve_signature(&mut self.signatures, event); + } } #[cfg(test)] mod tests { use super::*; use log::*; + use event::*; use std::thread::sleep; use std::time::Duration; @@ -199,22 +212,24 @@ mod tests { } #[test] - fn test_bad_event_attack() { - let zero = Sha256Hash::default(); - let hist = Historian::new(&zero, None); + fn test_bad_event_signature() { let keypair = generate_keypair(); - let event0 = Event::Claim { - key: get_pubkey(&keypair), - data: hash(b"goodbye cruel world"), - sig: sign_serialized(&hash(b"hello, world"), &keypair), - }; - hist.sender.send(event0).unwrap(); - drop(hist.sender); - assert_eq!( - hist.thread_hdl.join().unwrap().1, - ExitReason::RecvDisconnected - ); - let entries: Vec> = hist.receiver.iter().collect(); - assert_eq!(entries.len(), 0); + let sig = sign_claim_data(&hash(b"hello, world"), &keypair); + let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig); + let mut sigs = HashSet::new(); + assert!(!verify_event_and_reserve_signature(&mut sigs, &event0)); + assert!(!sigs.contains(&sig)); + } + + #[test] + fn test_duplicate_event_signature() { + let keypair = generate_keypair(); + let to = get_pubkey(&keypair); + let data = &hash(b"hello, world"); + let sig = sign_claim_data(data, &keypair); + let event0 = Event::new_claim(to, data, sig); + let mut sigs = HashSet::new(); + assert!(verify_event_and_reserve_signature(&mut sigs, &event0)); + assert!(!verify_event_and_reserve_signature(&mut sigs, &event0)); } } diff --git a/src/lib.rs b/src/lib.rs index 6deb92941323d4..851262000a3466 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 04a3b2482301ca..c1a4a7ee4f7906 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, @@ -303,24 +209,15 @@ mod tests { let zero = Sha256Hash::default(); let one = hash(&zero); - // First, verify Claim events + // First, verify entries let keypair = generate_keypair(); - let event0 = Event::Claim { - key: get_pubkey(&keypair), - data: zero, - sig: sign_serialized(&zero, &keypair), - }; - - let event1 = Event::Claim { - key: get_pubkey(&keypair), - data: one, - sig: sign_serialized(&one, &keypair), - }; + let event0 = Event::new_claim(get_pubkey(&keypair), zero, sign_claim_data(&zero, &keypair)); + let event1 = Event::new_claim(get_pubkey(&keypair), one, sign_claim_data(&one, &keypair)); let events = vec![event0, event1]; let mut entries = create_entries(&zero, 0, events); assert!(verify_slice(&entries, &zero)); - // Next, swap two Claim events and ensure verification fails. + // Next, swap two events and ensure verification fails. let event0 = entries[0].event.clone(); let event1 = entries[1].event.clone(); entries[0].event = event1; @@ -332,11 +229,7 @@ mod tests { fn test_claim() { let keypair = generate_keypair(); let data = hash(b"hello, world"); - let event0 = Event::Claim { - key: get_pubkey(&keypair), - data, - sig: sign_serialized(&data, &keypair), - }; + let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair)); let zero = Sha256Hash::default(); let entries = create_entries(&zero, 0, vec![event0]); assert!(verify_slice(&entries, &zero)); @@ -345,11 +238,11 @@ mod tests { #[test] fn test_wrong_data_claim_attack() { let keypair = generate_keypair(); - let event0 = Event::Claim { - key: get_pubkey(&keypair), - data: hash(b"goodbye cruel world"), - sig: sign_serialized(&hash(b"hello, world"), &keypair), - }; + let event0 = Event::new_claim( + get_pubkey(&keypair), + hash(b"goodbye cruel world"), + sign_claim_data(&hash(b"hello, world"), &keypair), + ); let zero = Sha256Hash::default(); let entries = create_entries(&zero, 0, vec![event0]); assert!(!verify_slice(&entries, &zero)); @@ -362,7 +255,7 @@ mod tests { let pubkey1 = get_pubkey(&keypair1); let data = hash(b"hello, world"); let event0 = Event::Transaction { - from: get_pubkey(&keypair0), + from: Some(get_pubkey(&keypair0)), to: pubkey1, data, sig: sign_transaction_data(&data, &keypair0, &pubkey1), @@ -379,7 +272,7 @@ mod tests { let pubkey1 = get_pubkey(&keypair1); let data = hash(b"hello, world"); let event0 = Event::Transaction { - from: get_pubkey(&keypair0), + from: Some(get_pubkey(&keypair0)), to: pubkey1, data: hash(b"goodbye cruel world"), // <-- attack! sig: sign_transaction_data(&data, &keypair0, &pubkey1), @@ -397,7 +290,7 @@ mod tests { let pubkey1 = get_pubkey(&keypair1); let data = hash(b"hello, world"); let event0 = Event::Transaction { - from: get_pubkey(&keypair0), + from: Some(get_pubkey(&keypair0)), to: get_pubkey(&thief_keypair), // <-- attack! data: hash(b"goodbye cruel world"), sig: sign_transaction_data(&data, &keypair0, &pubkey1),