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
}
}