@opendataformats/simplestamp

0.2.0 • Public • Published

Build Status

Coverage Status

SimpleStamp

ECMAScript/JS 6 Node library for creating compact, portable Open Timestamps attestations.

OpenTimestamps

Peter Todd has an excellent and thorough description of the benefits and implementation in his blog post OpenTimestamps: Scalable, Trust-Minimized, Distributed Timestamping with Bitcoin. Along with the OpenTimestamps website provide the best background information.

Motivation

Blockchain technology offers a multitude of benefits, the most appealing being the immutable proof at a point in time. The primary use being cryptocurrency ownership, the second being the state machine offered by smart contracts.

Most companies and projects find immutable proof to be the most appealing aspect, and aren't as interested in the currency or contract components.

Implementation

This implementation is client only, using a highly extensible and portable data model. The underlying data is stored in a series of Protocol Buffers, which allow for the structure and binary format to be extended easily.

Protocol Buffers are also language agnostic, with the ability to auto generate code to read, write, and manipulate the data models in most of the top tier programming languages; Javascript, Java, Python, Objective-C, C++, Dart, Go, Ruby, and C#. This means the timestamp binary data will be able to be handled as widely as possible.

Agnostic

SimpleStamp is agnostic to the storage of the Timestamp itself. Once generated, it can be stored in a file, database, etc by calling Timestamp.toBinary() and saving the Buffer data. The data can then be reloaded with Timestamp.fromBinary(Buffer).

SimpleStamp also does not dictate that the Timestamp be of a file, or what method the hash was generated from.

Data Model

A Timestamp has the following fields, as defined in the protobuf.

simplestamp.v1.Timestamp

Defined in timestamp.proto

message SimpleStamp {
  // The binary hash of the data this timestamp is for.
  // Most likely the SHA256 of a file.
  bytes hash = 1;

  // The random data that is appended to the hash on creation.  This results in
  // stamping the same file multiple times and getting a unique stamp. The value
  // submitted to the server is then: SHA256(CONCAT(hash, nonce))
  bytes nonce = 2;

  // The attestations made
  repeated simplestamp.v1.Attestation attestations = 3;

  // The UNIX timestamp of when this was originally created
  uint32 created = 4;

  // OPTIONALS - The following fields are optional
  //
  // If these fields are set, they will be included when computing the digest hash, ie
  // digestHash = SHA256(CONCAT(hash, nonce, source, identity))

  // URL, file name, or general description for where the data
  // used to generate the hash came from.
  string source = 5;

  // Identity of the organization and/or person stamping
  simplestamp.v1.Identity identity = 6;

  // Where the timestamp was created and it's trajectory if moving
  simplestamp.v1.Location location = 7;

  // Assorted free form details for the creator to describe the purpose or intent
  string description = 8;

  // Cryptographic signature of the hash sent to digest. This lets the person making
  // the Timestamp use a private key to sign, so others can validate with their
  // public key.
  bytes signature = 9;

  // Unique identifier for the key used to sign. Open ended, to help identity which key was
  // used. Should not contain anything from the key itself.
  string key_id = 10;
}

The structure of the components of a Timestamp are in the following protobuf definitions:

simplestamp.v1.Attestation

Defined in attestation.proto

An Attestation is created for each calendar server the hash is sent to. It will contain the details of the server, including the operations the server reported to be performed on the hash to derive the proof.

simplestamp.v1.Identity

Defined in indentity.proto

(optional) Identity of the person who created and submitted the Timestamp. The fields mimic those in an SSL certificate; country code, state/province, city, organization, section/division, common name, email address, and full name.

This can be set during creation by calling .setIdentity().

timestamp.setIdentity(
  'US',               // Country Code
  'NY',               // State/Province
  'New York',         // City
  'My Company',       // Organization
  'Engineering',      // Section/Division
  'Corp Eng',         // Common Name
  'eng@example.com',  // Email Address
  'John Smith',       // Full Name
);

Identity information needs to be set before .stamp() is called as the idenity information is used to compute the digest hash sent to the calendar servers.

simplestamp.v1.Location

Defined in location.proto

(optional) The location of where the Timestamp was created, in latitude and longitude, with additional fields for altitude and trajectory.

This can be set during creation by calling .setLocation().

timestamp.setLocation(
  40.73111,   // Latitude
  -73.99689,  // Longitude
  120,        // Altitude, meters
  10,         // Accuracy, meters
  217.39,     // Direction, degrees
  42,         // Velocity
);

Computing the hash

The hash that is sent to the calendar servers to be included is the combination of the following:

  1. Hash of the source data
  2. Nonce, random data to make timestamps of the same data unique
  3. (optional) Source, the filename, URL, etc to the data
  4. (optional) Identity, the company name, division, email address, etc of the person creating the timestamp
  5. (optional) Location, the GPS and trajectory of the Timestamp.

Those values are concatenated in binary, in that order, and then run through SHA256 twice, to generate the hash sent to the calendar servers.

Using

Creating a new Timestamp

const SimpleStamp = require('simplestamp');

// Compute the hash of the data

const timestamp = new SimpleStamp(hash);

// The following fields are optional
timestamp.setSource('Filename, URL, etc');
timestamp.setIdentity(
  'US',
  'NY',
  'New York',
  undefined,
  undefined,
  undefined,
  'me@example.com',
  'John Smith',
);
timestamp.setLocation(
  40.73111,
  -73.99689,
);

// Sends the digested hash to the calendar server for attestation
timestamp.stamp();

Updating a Timestamp

After some time has passed, the calendar server will submit a transaction to the blockchain. The additional data for the attestation will be downloaded, parsed, and added to the Timestamp by running:

timestamp.update();

Saving a Timestamp

Serialize the internal Timestamp protocol buffer to portable binary and save the data to a storage layer of choice; filesystem, database, etc.

const /** @type {Buffer} */ data = timestamp.toBinary();
fs.writeFileSync('./myfile.timestamp', data);

Loading a Timestamp

Loading the binary representation into the wrapped SimpleStamp class is done by the static .fromBinary class method.

const SimpleStamp = require('simplestamp');

const data = fs.readFileSync('./myfile.timestamp');
const timestamp = SimpleStamp.fromBinary(data);

Testing

Run tests from the source root. This will also generate the JSDocs and lint the code.

./bin/run.tests.sh

Dependents (0)

Package Sidebar

Install

npm i @opendataformats/simplestamp

Weekly Downloads

2

Version

0.2.0

License

Unlicense

Unpacked Size

121 kB

Total Files

23

Last publish

Collaborators

  • davidarvan