1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// OpenTimestamps Library
// Written in 2017 by
//   Andrew Poelstra <rust-ots@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # OpenTimestamps
//!
//! This is a library to support Rust applications that interact with
//! [OpenTimestamps](https://petertodd.org/2016/opentimestamps-announcement)
//! timestamps and servers. It is written in pure Rust.
//!

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![deny(missing_docs)]

extern crate crypto;
#[macro_use] extern crate log;

pub mod attestation;
pub mod error;
pub mod hex;
pub mod op;
pub mod timestamp;
pub mod ser;

pub use ser::DetachedTimestampFile;
pub use timestamp::Timestamp;

#[cfg(test)]
mod tests {
    use super::*;

    const SMALL_TEST: &'static [u8] = b"\
\x00\x4f\x70\x65\x6e\x54\x69\x6d\x65\x73\x74\x61\x6d\x70\x73\x00\x00\x50\x72\x6f\x6f\x66\x00\xbf\x89\xe2\xe8\x84\xe8\x92\
\x94\x01\x08\xa7\x0d\xfe\x69\xc5\xa0\xd6\x28\x16\x78\x1a\xbb\x6e\x17\x77\x85\x47\x18\x62\x4a\x0d\x19\x42\x31\xad\xb1\x4c\
\x32\xee\x54\x38\xa4\xf0\x10\x7a\x46\x05\xde\x0a\x5b\x37\xcb\x21\x17\x59\xc6\x81\x2b\xfe\x2e\x08\xff\xf0\x10\x24\x4b\x79\
\xd5\x78\xaa\x38\xe3\x4f\x42\x7b\x0f\x3e\xd2\x55\xa5\x08\xf1\x04\x58\xa4\xc2\x57\xf0\x08\xa1\xa9\x2c\x61\xd5\x41\x72\x06\
\x00\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e\x2c\x2b\x68\x74\x74\x70\x73\x3a\x2f\x2f\x62\x6f\x62\x2e\x62\x74\x63\x2e\x63\x61\x6c\
\x65\x6e\x64\x61\x72\x2e\x6f\x70\x65\x6e\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\x73\x2e\x6f\x72\x67\xf0\x10\xe0\x27\x85\x91\
\xe2\x88\x68\x19\xba\x7b\x3d\xdd\x63\x2e\xd3\xfe\x08\xf1\x04\x58\xa4\xc2\x56\xf0\x08\x38\xf2\xc7\xf4\xba\xf4\xbc\xd7\x00\
\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e\x2e\x2d\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6c\x69\x63\x65\x2e\x62\x74\x63\x2e\x63\x61\
\x6c\x65\x6e\x64\x61\x72\x2e\x6f\x70\x65\x6e\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\x73\x2e\x6f\x72\x67";

    const LARGE_TEST: &'static [u8] = b"\
\x00\x4f\x70\x65\x6e\x54\x69\x6d\x65\x73\x74\x61\x6d\x70\x73\x00\x00\x50\x72\x6f\x6f\x66\x00\xbf\x89\xe2\xe8\x84\xe8\x92\
\x94\x01\x08\x6f\xd9\xc1\xc4\xf0\x96\xb7\x7e\x6d\x44\x57\xba\xc1\xc7\xf5\x10\x10\xd3\x18\xdb\x48\x3f\x28\x68\xd3\x79\x58\
\x43\xf0\x98\xd3\x78\xf0\x10\xe2\xe2\x24\x43\x9e\x7f\x0f\xdd\x8c\x1e\xea\xc7\x3e\xa7\x39\xdb\x08\xf1\x20\xa5\x74\x44\x4a\
\xa5\x00\x02\xb6\xfe\x5a\xf2\x46\x26\x70\x0a\x4b\xfc\x95\x0d\x61\xf8\x13\x7c\xc3\x9d\xa8\x2d\x53\x27\x6c\x9d\x66\x08\xf0\
\x20\x02\xf3\x1f\xd5\xa2\xf0\xff\x08\xf7\xe0\x73\x38\x4b\x4f\xf5\x2b\xc5\xa0\x26\xf6\xfe\x42\x4a\x3b\x6c\x83\x58\x0e\x76\
\x9e\x59\xd2\x08\xf0\x20\xe0\xea\x0a\x32\x87\xcc\xb1\x0f\x39\x1c\x62\xf6\x8e\xb5\xa2\xde\x1d\x13\xbc\x24\xc5\xc0\xb4\x0f\
\x6a\x03\xe3\x6b\xbb\xa7\xaa\xb0\x08\xf0\x20\xd9\xc3\xfa\x8a\x65\xbb\x0c\xcf\xb3\x38\x5c\xc2\x03\x42\x05\x94\xe2\xe5\xa9\
\x34\x41\xbf\xf8\x5c\xcc\x53\xd1\x63\x9b\x0f\x2c\x85\x08\xf0\x20\x2f\xc4\x1f\x43\xb7\xab\xb0\x51\xf2\xe9\xee\x08\x39\xb8\
\x61\x9a\xd8\xc7\xb0\xc4\x04\xcd\xfc\xcd\xd5\xd0\x90\xbb\x3b\x42\xa8\x89\x08\xf0\x20\x0b\xae\x5b\x64\x92\x16\x89\xf7\xb3\
\xee\x1f\x86\xb1\xae\x79\xea\x7e\xd3\xd8\x22\x08\x4f\x3a\x2c\xed\xb3\x75\xd1\xc2\x36\x05\x93\x08\xf1\x20\xe9\x31\xb8\x22\
\x28\xdb\x72\xb4\x9e\x9c\x33\x9c\x3f\xd8\xa2\x48\x16\x26\x48\xc3\x0e\x3c\x03\x1d\xb5\x40\x20\x76\xf4\xe1\x9d\x48\x08\xf1\
\x20\x37\xe1\x51\xfe\x09\x9e\x20\x8f\x90\xfe\x51\x11\x65\x0f\x81\x38\xdf\xd3\x2f\xa8\x5f\x21\x30\xf1\x6c\xd5\xe9\x91\xb4\
\xf9\x48\x1c\x08\xff\xf0\x10\x2c\x2b\xd1\x10\x61\x89\x89\xd9\xa4\xc6\xbf\x60\xa8\xde\xec\x50\x08\xf1\x04\x58\x83\xf1\x71\
\xf0\x08\x6d\x45\x80\xfc\x64\xdf\xa9\x79\xff\x00\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e\x2c\x2b\x68\x74\x74\x70\x73\x3a\x2f\x2f\
\x62\x6f\x62\x2e\x62\x74\x63\x2e\x63\x61\x6c\x65\x6e\x64\x61\x72\x2e\x6f\x70\x65\x6e\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\
\x73\x2e\x6f\x72\x67\x08\xf1\xae\x01\x01\x00\x00\x00\x01\x7e\x85\x5c\xd0\x5c\xb2\x31\x1f\xea\x5f\xed\xde\xea\x21\xbe\x34\
\xa5\x98\x2e\xb3\xfb\xa9\xbd\xca\x1d\x9e\xf9\x8a\x80\x05\xe1\x22\x00\x00\x00\x00\x48\x47\x30\x44\x02\x20\x3d\x4d\xec\x68\
\x13\xb7\xe2\x87\x0e\xc5\x38\xb3\x88\x2c\xd0\x5e\x5d\xb5\x71\xd7\x51\x1b\x6e\x31\x98\x69\x46\x2b\x02\x9f\xf2\x5a\x02\x20\
\x3e\xeb\x26\x3b\x36\x1a\x2b\x48\x20\xe9\x9c\xed\xce\xa1\x47\x1a\xcd\x4b\xee\x47\x3a\x23\xa8\x2f\xaf\xcf\xf1\xbe\x13\x15\
\xb3\x45\x01\xfd\xff\xff\xff\x02\xe3\x14\x13\x00\x00\x00\x00\x00\x23\x21\x02\x76\x18\xa4\x61\xfd\x2d\x26\xc4\xba\x77\xf1\
\xf7\xcd\x8a\xc5\x57\x7e\xea\x66\x5f\xfb\xc9\xa8\xde\x3c\x2e\x55\x91\x1c\xf0\x9f\x73\xac\x00\x00\x00\x00\x00\x00\x00\x00\
\x22\x6a\x20\xf0\x04\x73\xdb\x06\x00\x08\x08\xf0\x20\xa3\xb9\x56\xff\xca\xc2\x63\xfb\xd6\x6b\x33\x1e\x9c\x06\xa4\xb0\x96\
\x34\x2c\xff\xa7\x5a\xc8\x09\x90\x50\xd8\xda\x1c\x14\x94\x10\x08\x08\xf1\x20\x6c\x3c\x90\x80\x96\x2b\x36\x5f\xc4\x3e\x1f\
\xc6\x10\xe6\x91\x23\x7e\x33\x3e\x59\x98\xf8\xa8\x5d\xe3\xac\xf5\x79\x3c\x7d\x7d\x96\x08\x08\xf1\x20\x13\x88\x3d\x43\x52\
\xa3\x8a\x7f\x1b\xe2\xf4\x3a\xe3\x8d\xc3\x8f\xd4\x75\x39\xe4\xf1\xb1\x43\x90\xbe\x7d\x27\x0b\xb3\xf8\x1d\x4e\x08\x08\xf1\
\x20\x86\xe1\xb5\x77\xf7\xc7\xa1\xfd\x34\x52\x92\x81\xba\xcd\xec\x29\x3d\xa4\xd8\xac\xe8\x62\x2a\x6c\x04\xd9\x99\x05\x7d\
\x8b\x8e\x62\x08\x08\xf0\x20\xbf\x6b\x64\xf8\x33\x89\x98\x5d\x0a\xf4\xf7\xb4\x75\x3b\xb6\x8e\x57\x09\xff\xf1\x00\xa3\xdb\
\x0c\xb6\x1e\x6e\x44\xff\x8c\xf6\xae\x08\x08\xf1\x20\xfa\x8b\x54\x69\x92\xb6\x1c\xe2\xf1\xa9\x2f\x82\xde\x54\x5d\xae\x0d\
\xa7\x03\xef\x93\x2b\x6e\x4b\xda\x52\x3f\x2a\xec\x61\x7e\x5f\x08\x08\xf0\x20\x25\x61\xe8\xf4\xc2\x4d\x32\xc2\x14\x1c\x74\
\x64\x6d\xb0\x67\x30\x7f\x6c\x6e\x17\x05\xa4\xf5\x05\xb8\xab\x81\xaf\x1c\x16\x54\xc2\x08\x08\xf1\x20\x51\x7a\x29\xcb\x81\
\x52\x6f\x3b\x28\x71\x6f\xff\xb2\x4d\x5c\x8b\x6d\x6c\xcc\xd4\xb9\x8e\xec\xc9\xaa\xf0\x00\x37\x08\xb4\x25\x22\x08\x08\x00\
\x05\x88\x96\x0d\x73\xd7\x19\x01\x03\xf7\xb6\x1b\xf0\x10\x75\x85\xd6\x34\x8e\x2c\x8a\x1c\x7e\xd0\xa6\x97\x7a\xe4\xd2\xad\
\x08\xf1\x04\x58\x83\xf1\x71\xf0\x08\x5d\xeb\x89\x67\x36\x2e\x06\xb6\xff\x00\x83\xdf\xe3\x0d\x2e\xf9\x0c\x8e\x2e\x2d\x68\
\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6c\x69\x63\x65\x2e\x62\x74\x63\x2e\x63\x61\x6c\x65\x6e\x64\x61\x72\x2e\x6f\x70\x65\x6e\
\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\x73\x2e\x6f\x72\x67\x08\xf0\x20\x41\x41\x13\x62\xbc\xe1\x8d\x16\xff\x66\x0b\x43\x1a\
\x64\x4b\xb6\xc4\xa1\xf0\x65\x55\x62\x7a\xe0\x07\x8c\x7b\xb7\x21\x48\x0e\x4b\x08\xf0\x20\xd8\x68\x49\x86\xc4\x82\x11\x22\
\xca\x9f\x66\x6c\x55\x07\xb8\x9d\x89\x6b\x81\x2b\xbe\xc9\xc1\x84\x72\x09\x96\x4d\x0c\x4f\x2e\xc3\x08\xf1\x20\xb1\x07\xd6\
\x20\x2e\x7f\x79\xca\x83\x99\x17\xda\xdb\xeb\x20\x5b\x76\x16\x83\xb4\x9d\x16\x9d\xe2\x30\x25\x45\x2b\xf5\x79\x6a\xe2\x08\
\xf0\x20\x74\xc4\x8c\x02\x9d\x2f\x8f\x5f\xd7\x40\x9e\x8f\xcf\x68\x4e\x42\xbe\xb7\x2e\xbd\x99\xfe\x6c\xef\xff\x09\xe4\x47\
\x29\x49\x06\xa7\x08\xf0\x20\x62\x9e\xe2\x17\x44\x93\x5b\x51\x8c\x36\x14\x8a\xd3\x0f\xc7\xfc\x08\x87\x89\xc2\xb0\x00\xb4\
\x69\xcb\xb5\x0a\xe6\x1a\x34\xf3\x01\x08\xf1\xae\x01\x01\x00\x00\x00\x01\xa2\xc7\x0a\xd9\x76\x8b\x47\x6e\xb8\x2e\x07\x04\
\x75\x60\x3c\xdc\xb3\x01\x41\x4f\x62\xd5\x58\x10\x06\x13\x72\x41\x2d\x91\xe1\xbf\x00\x00\x00\x00\x48\x47\x30\x44\x02\x20\
\x52\x52\xd2\x89\x09\x05\x5e\xff\x8f\xb3\xab\x68\xf9\xcc\x11\x15\x03\x2b\x75\xe6\xcc\xfb\xf3\x84\x4b\xd9\x16\x14\xdd\x73\
\x7c\xd6\x02\x20\x21\xad\xd2\xd0\xab\x18\x8f\x4d\xb5\x55\x06\x6b\x0c\x38\x22\xd4\xba\xb0\x13\x43\x91\x98\x57\xdb\xaa\x11\
\x11\x5d\xc1\x4a\xd2\x21\x01\xfd\xff\xff\xff\x02\xb4\x4d\x44\x00\x00\x00\x00\x00\x23\x21\x03\x00\x9a\x9a\x91\x2d\x43\x76\
\x26\x8e\xc1\x37\x7c\x12\xd3\xd9\x9b\xd5\x1d\xa4\xf1\xed\xd8\x2c\x22\x74\xfd\x45\xde\xe1\xe3\xac\xd1\xac\x00\x00\x00\x00\
\x00\x00\x00\x00\x22\x6a\x20\xf0\x04\x74\xdb\x06\x00\x08\x08\xf1\x20\x5a\xbb\xb3\xdc\xd1\x24\x9e\xeb\x6d\x9b\xa9\x97\x2a\
\x94\x6e\xef\x2c\xdc\x3f\x32\x50\x38\xc1\x9d\x25\x3f\x5c\xa6\xd6\x93\x83\x7b\x08\x08\xf1\x20\xe9\x89\x14\x1b\xe1\x09\xac\
\xba\x19\x78\x20\xe1\x8a\xd9\xc2\x50\x64\x5c\xc0\x9d\xa5\x32\x89\x5e\xd9\x8d\x19\x1f\xf6\xf4\x24\xd6\x08\x08\xf0\x20\x48\
\xdc\xfc\x2f\xe8\x9e\x46\x4e\xd5\x28\x31\x90\x16\x56\xa1\x3b\x9f\x8d\x78\x37\xd6\xba\xe3\xfc\xa1\x8f\x14\x4a\xe0\x03\x73\
\x50\x08\x08\xf1\x20\xb2\x42\x65\xa8\x06\x99\xfd\x93\x01\xd5\x94\xfd\x90\x25\x9b\xd0\xed\x3b\x86\x8a\xf1\xcd\x36\x42\x08\
\x84\x7e\x64\x80\xb8\xab\x57\x08\x08\xf1\x20\xd0\xa7\x95\x39\xe4\x40\xf9\x9e\xe6\x0d\xba\xdd\x27\xa0\x71\x62\x25\x52\x37\
\x14\x0e\x91\x1b\xd0\x1d\xfc\x5c\xde\xc6\xdc\xaf\xec\x08\x08\xf1\x20\xd5\x6d\xf3\x0e\x00\xef\x52\xc8\xd4\xc2\x7e\x95\xe7\
\x7e\x28\xe4\x2e\x8d\xb9\xdb\xf4\x93\x3b\xd3\xc1\xfa\x80\x3c\x79\x2c\x68\xfa\x08\x08\xf1\x20\x91\xe3\x57\x66\xb6\xcf\x6d\
\x60\xd4\xeb\x6f\xa7\x28\xc6\x87\x6e\xca\xbf\x99\x92\x81\xc8\x2e\xd2\x00\xb0\x5a\xb1\x18\x78\xab\x49\x08\x08\xf0\x20\xad\
\x0c\xbb\x07\xe6\xa6\xa3\x59\xf8\x0f\x69\xa8\x7d\xcb\xc9\xbc\x78\x04\x79\xea\x73\xd2\xbe\xb6\xf7\x3c\xd3\xb9\x25\xa2\x89\
\x41\x08\x08\xf1\x20\x4b\x38\x70\x93\xad\xcd\xe0\xb6\x91\x58\xcf\x5d\x08\xdf\xf0\xf6\x2a\xa9\x4c\x77\x41\x52\xad\xa3\x9f\
\xed\x89\x57\x63\xf6\xad\xb3\x08\x08\xf1\x20\xe1\xc1\xae\xc4\x3e\x4c\xba\x0c\xc7\x6a\xed\xf0\x74\x33\xc2\x45\xaf\x3f\x8a\
\xe2\xc0\x56\x45\xa1\x9c\x09\x09\x36\x4c\x3f\x30\x6e\x08\x08\x00\x05\x88\x96\x0d\x73\xd7\x19\x01\x03\xf5\xb6\x1b";

    #[test]
    fn round_trip() {
        let mut rt1 = vec![];
        let mut rt2 = vec![];

        let ots = DetachedTimestampFile::from_reader(SMALL_TEST);
        assert!(ots.is_ok());
        assert!(ots.unwrap().to_writer(&mut rt1).is_ok());
        assert_eq!(rt1, SMALL_TEST);

        let ots = DetachedTimestampFile::from_reader(LARGE_TEST);
        ots.as_ref().unwrap();
        assert!(ots.is_ok());
        assert!(ots.unwrap().to_writer(&mut rt2).is_ok());
        assert_eq!(rt2, LARGE_TEST);
    }
}