use std::fmt;
use std::io::{Read, Write};
use error::Error;
use hex::Hexed;
use timestamp::Timestamp;
const MAGIC: &'static [u8] = b"\x00OpenTimestamps\x00\x00Proof\x00\xbf\x89\xe2\xe8\x84\xe8\x92\x94";
const VERSION: usize = 1;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct DetachedTimestampFile {
pub digest_type: DigestType,
pub timestamp: Timestamp
}
impl DetachedTimestampFile {
pub fn from_reader<R: Read>(reader: R) -> Result<DetachedTimestampFile, Error> {
trace!("Start deserializing timestampfile from reader.");
let mut deser = Deserializer::new(reader);
deser.read_magic()?;
trace!("Magic ok.");
deser.read_version()?;
trace!("Version ok.");
let digest_type = DigestType::from_tag(deser.read_byte()?)?;
trace!("Digest type: {}", digest_type);
let digest = deser.read_fixed_bytes(digest_type.digest_len())?;
trace!("Digest: {}", Hexed(&digest));
let timestamp = Timestamp::deserialize(&mut deser, digest)?;
deser.check_eof()?;
Ok(DetachedTimestampFile {
digest_type: digest_type,
timestamp: timestamp
})
}
pub fn to_writer<W: Write>(&self, writer: W) -> Result<(), Error> {
let mut ser = Serializer::new(writer);
ser.write_magic()?;
ser.write_version()?;
ser.write_byte(self.digest_type.to_tag())?;
ser.write_fixed_bytes(&self.timestamp.start_digest)?;
self.timestamp.serialize(&mut ser)
}
}
impl fmt::Display for DetachedTimestampFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{} digest of some data.", self.digest_type)?;
writeln!(f, "{}", self.timestamp)
}
}
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DigestType {
Sha1,
Sha256,
Ripemd160
}
impl DigestType {
pub fn from_tag(tag: u8) -> Result<DigestType, Error> {
match tag {
0x02 => Ok(DigestType::Sha1),
0x03 => Ok(DigestType::Ripemd160),
0x08 => Ok(DigestType::Sha256),
x => Err(Error::BadDigestTag(x))
}
}
pub fn to_tag(self) -> u8 {
match self {
DigestType::Sha1 => 0x02,
DigestType::Sha256 => 0x08,
DigestType::Ripemd160 => 0x03
}
}
pub fn digest_len(self) -> usize {
match self {
DigestType::Sha1 => 20,
DigestType::Sha256 => 32,
DigestType::Ripemd160 => 20
}
}
}
impl fmt::Display for DigestType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
DigestType::Sha1 => f.write_str("SHA1"),
DigestType::Sha256 => f.write_str("SHA256"),
DigestType::Ripemd160 => f.write_str("RIPEMD160"),
}
}
}
pub struct Deserializer<R: Read> {
reader: R
}
impl<R: Read> Deserializer<R> {
pub fn new(reader: R) -> Deserializer<R> {
Deserializer {
reader: reader
}
}
pub fn into_inner(self) -> R {
self.reader
}
pub fn read_magic(&mut self) -> Result<(), Error> {
let recv_magic = self.read_fixed_bytes(MAGIC.len())?;
if recv_magic == MAGIC {
Ok(())
} else {
Err(Error::BadMagic(recv_magic))
}
}
pub fn read_version(&mut self) -> Result<(), Error> {
let recv_version = self.read_uint()?;
if recv_version == VERSION {
Ok(())
} else {
Err(Error::BadVersion(recv_version))
}
}
pub fn read_byte(&mut self) -> Result<u8, Error> {
let mut byte = [0];
self.reader.read_exact(&mut byte)?;
Ok(byte[0])
}
pub fn read_uint(&mut self) -> Result<usize, Error> {
let mut ret = 0;
let mut shift = 0;
loop {
let byte = self.read_byte()?;
ret |= ((byte & 0x7f) as usize) << shift;
if byte & 0x80 == 0 {
break;
}
shift += 7;
}
Ok(ret)
}
pub fn read_fixed_bytes(&mut self, n: usize) -> Result<Vec<u8>, Error> {
let mut ret = vec![0; n];
self.reader.read_exact(&mut ret)?;
Ok(ret)
}
pub fn read_bytes(&mut self, min: usize, max: usize) -> Result<Vec<u8>, Error> {
let n = self.read_uint()?;
if n < min || n > max {
return Err(Error::BadLength { min: min, max: max, val: n });
}
self.read_fixed_bytes(n)
}
pub fn check_eof(&mut self) -> Result<(), Error> {
if self.reader.by_ref().bytes().next().is_none() {
Ok(())
} else {
Err(Error::TrailingBytes)
}
}
}
pub struct Serializer<W: Write> {
writer: W
}
impl<W: Write> Serializer<W> {
pub fn new(writer: W) -> Serializer<W> {
Serializer {
writer: writer
}
}
pub fn into_inner(self) -> W {
self.writer
}
pub fn write_magic(&mut self) -> Result<(), Error> {
self.write_fixed_bytes(MAGIC)
}
pub fn write_version(&mut self) -> Result<(), Error> {
self.write_uint(VERSION)
}
pub fn write_byte(&mut self, byte: u8) -> Result<(), Error> {
self.writer.write_all(&[byte]).map_err(Error::Io)
}
pub fn write_uint(&mut self, mut n: usize) -> Result<(), Error> {
if n == 0 {
self.write_byte(0x00)
} else {
while n > 0 {
if n > 0x7f {
self.write_byte((n as u8) | 0x80)?;
} else {
self.write_byte(n as u8)?;
}
n >>= 7;
}
Ok(())
}
}
pub fn write_fixed_bytes(&mut self, data: &[u8]) -> Result<(), Error> {
self.writer.write_all(data).map_err(Error::Io)
}
pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> {
self.write_uint(data.len())?;
self.write_fixed_bytes(data)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn digest_type_rt() {
macro_rules! check_digest_type {
($($tag: ident),*) => {
match DigestType {
$(DigestType::$tag => {}),*
}
$({
let tag = DigestType::$tag.to_tag();
assert!(DigestType::from_tag(tag).is_ok());
let from = DigestType::from_tag(tag).unwrap();
assert_eq!(DigestType::$tag, from);
})*
}
};
}
#[test]
fn digest_len() {
assert_eq!(DigestType::Sha1.digest_len(), 20);
assert_eq!(DigestType::Sha256.digest_len(), 32);
assert_eq!(DigestType::Ripemd160.digest_len(), 20);
}
}