dpt 0.3.1

Ethereum's Distributed Peer Table implementation in Rust.
use util::{keccak256, pk2id, id2pk};
use std::net::SocketAddr;
use secp256k1::{self, SecretKey, Signature, Message, RecoveryId};
use bigint::{H256, H512};
use tokio_core::net::UdpCodec;
use std::io;

macro_rules! try_none {
    ( $ex:expr ) => {
        match $ex {
            Ok(val) => val,
            Err(_) => return Ok(None),
        }
    }
}

pub struct DPTCodec {
    secret_key: SecretKey,
}

pub struct DPTCodecMessage {
    pub addr: SocketAddr,
    pub typ: u8,
    pub data: Vec<u8>
}

impl DPTCodec {
    pub fn new(secret_key: SecretKey) -> Self {
        DPTCodec {
            secret_key
        }
    }
}

impl UdpCodec for DPTCodec {
    type In = Option<(DPTCodecMessage, H512, H256)>;
    type Out = DPTCodecMessage;

    fn decode(&mut self, src: &SocketAddr, buf: &[u8]) -> Result<Self::In, io::Error> {
        if buf.len() < 98 {
            return Ok(None);
        }

        let hash = keccak256(&buf[32..]);
        let check_hash = H256::from(&buf[0..32]);
        if check_hash != hash {
            return Ok(None);
        }

        let sighash = keccak256(&buf[97..]);
        let rec_id = try_none!(RecoveryId::parse(buf[96]));
        let sig = {
            let mut ret = [0u8; 64];
            for i in 0..64 {
                ret[i] = buf[32 + i];
            }
            Signature::parse(&ret)
        };
        let message = {
            let mut ret = [0u8; 32];
            for i in 0..32 {
                ret[i] = sighash[i];
            }
            Message::parse(&ret)
        };
        let public_key = try_none!(secp256k1::recover(&message, &sig, &rec_id));
        let remote_id = pk2id(&public_key);

        let typ = buf[97];
        let mut data = Vec::new();
        for i in 98..buf.len() {
            data.push(buf[i]);
        }

        Ok(Some((DPTCodecMessage { addr: src.clone(), typ, data }, remote_id, hash)))
    }

    fn encode(&mut self, mut msg: DPTCodecMessage, buf: &mut Vec<u8>) -> SocketAddr {
        let mut typdata = Vec::new();
        typdata.push(msg.typ);
        typdata.append(&mut msg.data);

        let sighash = keccak256(&typdata);
        let message = {
            let mut ret = [0u8; 32];
            for i in 0..32 {
                ret[i] = sighash[i];
            }
            Message::parse(&ret)
        };
        let (sig, rec) = secp256k1::sign(&message, &self.secret_key).unwrap();

        let mut hashdata = Vec::new();
        for d in sig.serialize().as_ref() {
            hashdata.push(*d);
        }
        hashdata.push(rec.serialize());
        hashdata.append(&mut typdata);

        let hash = keccak256(&hashdata);

        for i in 0..32 {
            buf.push(hash[i]);
        }
        buf.append(&mut hashdata);

        msg.addr
    }
}