Merge pull request #30 from garious/simplify

Unify Claim and Transaction handling
This commit is contained in:
Greg Fitzgerald 2018-03-02 12:24:44 -07:00 committed by GitHub
commit 8871bb2d8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 287 additions and 241 deletions

View File

@ -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<Event>> {
fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256Hash>>> {
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<Entry> = hist.receiver.iter().collect();
let entries: Vec<Entry<Sha256Hash>> = 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 }
```

View File

@ -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<T> = result::Result<T, AccountingError>;
pub struct Accountant {
pub historian: Historian<u64>,
@ -24,71 +35,43 @@ impl Accountant {
}
}
pub fn process_event(self: &mut Self, event: &Event<u64>) {
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<Entry<u64>> {
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<Event<u64>>> {
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<Signature, SendError<Event<u64>>> {
use log::{get_pubkey, sign_serialized};
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> Result<Signature> {
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<Event<u64>>> {
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<Signature, SendError<Event<u64>>> {
use log::{get_pubkey, sign_transaction_data};
) -> Result<Signature> {
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<u64, RecvError> {
self.sync();
Ok(*self.balances.get(pubkey).unwrap_or(&0))
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<u64> {
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);

View File

@ -1,6 +1,6 @@
use std::io;
use accountant::Accountant;
use log::{PublicKey, Signature};
use event::{PublicKey, Signature};
//use serde::Serialize;
pub struct AccountantSkel {

View File

@ -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<Signature> {
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<Signature> {
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() {

View File

@ -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();

View File

@ -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<Sha256Hash>) -> Result<(), SendError<Event<Sha256
sleep(Duration::from_millis(15));
let data = Sha256Hash::default();
let keypair = generate_keypair();
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));
hist.sender.send(event0)?;
sleep(Duration::from_millis(10));
Ok(())
@ -30,5 +26,7 @@ fn main() {
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));
}

135
src/event.rs Normal file
View File

@ -0,0 +1,135 @@
//! 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<u8, U32>;
pub type Signature = GenericArray<u8, U64>;
/// 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<T> {
Tick,
Transaction {
from: Option<PublicKey>,
to: PublicKey,
data: T,
sig: Signature,
},
}
impl<T> Event<T> {
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<T: Serialize>(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<T: Serialize>(
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<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
let to = get_pubkey(keypair);
let from: Option<PublicKey> = 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<T>(event: &Event<T>) -> Option<Signature> {
match *event {
Event::Tick => None,
Event::Transaction { sig, .. } => Some(sig),
}
}
pub fn verify_event<T: Serialize>(event: &Event<T>) -> 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<u8> = deserialize(&buf).unwrap();
assert_eq!(claim1, claim0);
}
}

View File

@ -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<T> {
pub sender: SyncSender<Event<T>>,
pub receiver: Receiver<Entry<T>>,
pub thread_hdl: JoinHandle<(Entry<T>, ExitReason)>,
pub signatures: HashSet<Signature>,
}
#[derive(Debug, PartialEq, Eq)]
@ -43,10 +45,25 @@ fn log_event<T: Serialize + Clone + Debug>(
Ok(())
}
fn verify_event_and_reserve_signature<T: Serialize>(
signatures: &mut HashSet<Signature>,
event: &Event<T>,
) -> 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<T: Serialize + Clone + Debug>(
receiver: &Receiver<Event<T>>,
sender: &SyncSender<Entry<T>>,
signatures: &mut HashMap<Signature, bool>,
num_hashes: &mut u64,
end_hash: &mut Sha256Hash,
epoch: SystemTime,
@ -64,15 +81,7 @@ fn log_events<T: Serialize + Clone + Debug>(
}
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<T: 'static + Serialize + Clone + Debug + Send>(
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<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
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<T>) -> 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<Entry<Sha256Hash>> = 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));
}
}

View File

@ -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;

View File

@ -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<u8, U32>;
pub type PublicKey = GenericArray<u8, U32>;
pub type Signature = GenericArray<u8, U64>;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Entry<T> {
@ -29,27 +27,6 @@ pub struct Entry<T> {
pub event: Event<T>,
}
/// 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<T> {
Tick,
Claim {
key: PublicKey,
data: T,
sig: Signature,
},
Transaction {
from: PublicKey,
to: PublicKey,
data: T,
sig: Signature,
},
}
impl<T> Entry<T> {
/// Creates a Entry from the number of hashes 'num_hashes' since the previous event
/// and that resulting 'end_hash'.
@ -62,36 +39,6 @@ impl<T> Entry<T> {
}
}
/// 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<T: Serialize>(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<T: Serialize>(
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<T>(event: &Event<T>) -> Option<Signature> {
match *event {
Event::Tick => None,
Event::Claim { sig, .. } => Some(sig),
Event::Transaction { sig, .. } => Some(sig),
}
}
pub fn hash_event<T>(end_hash: &Sha256Hash, event: &Event<T>) -> Sha256Hash {
match get_signature(event) {
None => *end_hash,
@ -164,29 +103,6 @@ pub fn next_tick<T: Serialize>(start_hash: &Sha256Hash, num_hashes: u64) -> Entr
next_entry(start_hash, num_hashes, Event::Tick)
}
pub fn verify_event<T: Serialize>(event: &Event<T>) -> 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<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) -> bool {
@ -219,16 +135,6 @@ pub fn verify_slice_seq<T: Serialize>(events: &[Entry<T>], 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<T: Serialize>(
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),