2018-03-02 08:43:54 -07:00
|
|
|
//! 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
|
2018-03-04 07:34:38 -07:00
|
|
|
/// 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.
|
2018-03-02 08:43:54 -07:00
|
|
|
///
|
|
|
|
/// 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;
|
2018-03-04 07:28:51 -07:00
|
|
|
use ring::{rand, signature};
|
|
|
|
use untrusted;
|
2018-03-02 08:43:54 -07:00
|
|
|
use serde::Serialize;
|
2018-03-04 07:28:51 -07:00
|
|
|
use bincode::serialize;
|
2018-03-05 12:48:09 -07:00
|
|
|
use log::Sha256Hash;
|
2018-03-02 08:43:54 -07:00
|
|
|
|
|
|
|
pub type PublicKey = GenericArray<u8, U32>;
|
|
|
|
pub type Signature = GenericArray<u8, U64>;
|
|
|
|
|
2018-03-06 10:49:40 -07:00
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
pub struct Transfer<T> {
|
|
|
|
pub from: PublicKey,
|
|
|
|
pub to: PublicKey,
|
|
|
|
pub data: T,
|
|
|
|
pub last_id: Sha256Hash,
|
|
|
|
pub sig: Signature,
|
|
|
|
}
|
|
|
|
|
2018-03-02 08:43:54 -07:00
|
|
|
/// 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
|
2018-03-04 07:34:38 -07:00
|
|
|
/// a hash alongside the tick, each tick and be verified in parallel using the 'id'
|
2018-03-02 08:43:54 -07:00
|
|
|
/// of the preceding tick to seed its hashing.
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
pub enum Event<T> {
|
|
|
|
Tick,
|
2018-03-06 10:49:40 -07:00
|
|
|
Transaction(Transfer<T>),
|
2018-03-02 08:43:54 -07:00
|
|
|
}
|
|
|
|
|
2018-03-02 10:58:43 -07:00
|
|
|
impl<T> Event<T> {
|
2018-03-05 12:48:09 -07:00
|
|
|
pub fn new_claim(to: PublicKey, data: T, last_id: Sha256Hash, sig: Signature) -> Self {
|
2018-03-06 10:49:40 -07:00
|
|
|
let transfer = Transfer {
|
2018-03-03 20:41:05 -07:00
|
|
|
from: to,
|
2018-03-02 11:48:56 -07:00
|
|
|
to,
|
|
|
|
data,
|
2018-03-05 12:48:09 -07:00
|
|
|
last_id,
|
2018-03-02 11:48:56 -07:00
|
|
|
sig,
|
2018-03-06 10:49:40 -07:00
|
|
|
};
|
|
|
|
Event::Transaction(transfer)
|
2018-03-02 10:58:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-02 08:43:54 -07:00
|
|
|
/// 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.
|
2018-03-02 11:46:19 -07:00
|
|
|
fn sign_serialized<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
|
2018-03-02 08:43:54 -07:00
|
|
|
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,
|
2018-03-05 12:48:09 -07:00
|
|
|
last_id: &Sha256Hash,
|
2018-03-02 08:43:54 -07:00
|
|
|
) -> Signature {
|
2018-03-03 20:41:05 -07:00
|
|
|
let from = &get_pubkey(keypair);
|
2018-03-05 12:48:09 -07:00
|
|
|
sign_serialized(&(from, to, data, last_id), keypair)
|
2018-03-02 08:43:54 -07:00
|
|
|
}
|
|
|
|
|
2018-03-02 11:46:19 -07:00
|
|
|
/// Return a signature for the given data using the private key from the given keypair.
|
2018-03-05 12:48:09 -07:00
|
|
|
pub fn sign_claim_data<T: Serialize>(
|
|
|
|
data: &T,
|
|
|
|
keypair: &Ed25519KeyPair,
|
|
|
|
last_id: &Sha256Hash,
|
|
|
|
) -> Signature {
|
|
|
|
sign_transaction_data(data, keypair, &get_pubkey(keypair), last_id)
|
2018-03-02 11:46:19 -07:00
|
|
|
}
|
|
|
|
|
2018-03-02 08:43:54 -07:00
|
|
|
/// 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<T>(event: &Event<T>) -> Option<Signature> {
|
|
|
|
match *event {
|
|
|
|
Event::Tick => None,
|
2018-03-06 10:49:40 -07:00
|
|
|
Event::Transaction(Transfer { sig, .. }) => Some(sig),
|
2018-03-02 08:43:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn verify_event<T: Serialize>(event: &Event<T>) -> bool {
|
2018-03-06 10:49:40 -07:00
|
|
|
if let Event::Transaction(Transfer {
|
2018-03-02 08:43:54 -07:00
|
|
|
from,
|
|
|
|
to,
|
|
|
|
ref data,
|
2018-03-05 12:48:09 -07:00
|
|
|
last_id,
|
2018-03-02 08:43:54 -07:00
|
|
|
sig,
|
2018-03-06 10:49:40 -07:00
|
|
|
}) = *event
|
2018-03-02 08:43:54 -07:00
|
|
|
{
|
2018-03-05 12:48:09 -07:00
|
|
|
let sign_data = serialize(&(&from, &to, &data, &last_id)).unwrap();
|
2018-03-03 20:41:05 -07:00
|
|
|
if !verify_signature(&from, &sign_data, &sig) {
|
2018-03-02 08:43:54 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
2018-03-02 11:46:19 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use bincode::{deserialize, serialize};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serialize_claim() {
|
2018-03-05 12:48:09 -07:00
|
|
|
let claim0 = Event::new_claim(
|
|
|
|
Default::default(),
|
|
|
|
0u8,
|
|
|
|
Default::default(),
|
|
|
|
Default::default(),
|
|
|
|
);
|
2018-03-02 11:46:19 -07:00
|
|
|
let buf = serialize(&claim0).unwrap();
|
2018-03-02 12:03:59 -07:00
|
|
|
let claim1: Event<u8> = deserialize(&buf).unwrap();
|
2018-03-02 11:46:19 -07:00
|
|
|
assert_eq!(claim1, claim0);
|
|
|
|
}
|
|
|
|
}
|