Difference between revisions of "Timestamp Service"

From Snowblossom Wiki
Jump to: navigation, search
(Design)
 
(6 intermediate revisions by the same user not shown)
Line 15: Line 15:
  
 
== Uses ==
 
== Uses ==
The cheap is super important.  Often, we probably won't know the value of data or having a proof on it until much later.   
+
The cheap is super important.  Often, we probably won't know the value of data or having a proof on it until much later.
 +
 
 +
So for example, an app that saved the hash of every picture you took on your phone might be coolMost wouldn't matter, but it would be nice if you ever needed to later prove that one of the pictures was not edited after the time of the timestamp.
 +
 
 +
So images, videos, even video streams (if you can get low level enough into the video stream to decide what data to predictably hash on).  Documents.  Source code.  Things I haven't thought of.
  
 
== API ==
 
== API ==
Line 21: Line 25:
 
The API is simple.  One call that provides the data to include and the result is some transaction ID for the timestamp.
 
The API is simple.  One call that provides the data to include and the result is some transaction ID for the timestamp.
 
Then some time later, the user can call again with the transaction ID and get the entire proof.
 
Then some time later, the user can call again with the transaction ID and get the entire proof.
 +
 +
* /api/v1/info - get general info about the service
 +
* /api/v1/publish?hash=XXXX - publish a hash. The hash must be a hex encoded string
 +
* /api/v1/getproof?transaction_hash=XXXX - check on a transaction hash, which is given as an output to a publish
 +
 +
== Instances ==
 +
 +
We are running an instance that anyone is free to use at [https://timestamp.snowblossom.org/api/v1/info https://timestamp.snowblossom.org/]
 +
 +
[https://timestamp.snowblossom.org/api/v1/info Info]
 +
[https://timestamp.snowblossom.org/api/v1/publish?hash=c638dd867d7d49fc626e8aed0aef56c1b62da71ff43622d26c0b859e449dfc07 Publish]
 +
[https://timestamp.snowblossom.org/api/v1/getproof?transaction_hash=b21cd8220f6c900cdbeeac406b7d81c27f3ae11ea04f06f4599d2f867b91896a  GetProof]
  
 
== Design ==
 
== Design ==
Line 40: Line 56:
  
 
Example proof, which proves that the data_hash of 710150e9eb6d7b7377e75d82f43bb4a84fc3ea42f08ea56bd594c4be7c4fb3b2 was included in Snowblossom Block [https://explorer.snowblossom.org/?search=0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8 0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8].
 
Example proof, which proves that the data_hash of 710150e9eb6d7b7377e75d82f43bb4a84fc3ea42f08ea56bd594c4be7c4fb3b2 was included in Snowblossom Block [https://explorer.snowblossom.org/?search=0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8 0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8].
 +
 +
The number of steps will depend on the depth of the merkle trees for timestamp data going into the channel block, the number of channel blocks until one that is included in the public blockchain and the merkle depth of transactions in the blockchain.
  
 
  {
 
  {
Line 356: Line 374:
 
   "snow_transaction": "c3be5a72e6ab2d6fabf3eae673cf4e6491d551946b48a4b2270cf75fc4b4c2bb"
 
   "snow_transaction": "c3be5a72e6ab2d6fabf3eae673cf4e6491d551946b48a4b2270cf75fc4b4c2bb"
 
  }
 
  }
 +
 +
A user of the service can either request and save proofs (which stand on their own with no additional metadata required) or the user can have their own snowblossom channels node join the timestamp service channel and replicate the metadata.  That way, their own node could always generate proofs as needed.
  
 
== Version Plan ==
 
== Version Plan ==
Line 364: Line 384:
  
 
== Scaling ==
 
== Scaling ==
 +
 +
For such a service to be really useful, it needs to scale and continue to be inexpensive.
 +
 +
Here is an example architecture that would work:
 +
 +
API endpoint goes to a request router.  The request router knows which backends (each running their own channel) are availible.
 +
Request router sends timestamp requests to an available backend.
 +
Request router sends proof requests to the appropriate backend for the chain the transaction is on.
 +
 +
The backend nodes operate on channels each with an active-active configuration where any of the nodes on a channel could accept timestamp requests, service proof lookups or generate blocks.  There would have to be a little coordination to avoid creating blocks close in time and confusing the channel's mempool.  Same for deciding when to save state to the upstream timestamp service.
 +
 +
So imagine the backend nodes as pairs, each pair servicing one channel.  Then the occasionally save state to an upstream timestamp service.  Add more pairs running channels as needed for the load.
 +
 +
The upstream master timestamp service would occasionally save to public blockchains.
 +
 +
With this model, we can extend to a very high request rate while still only saving a transaction on a public chain every few blocks.

Latest revision as of 08:55, 9 March 2024

Overview

A timestamp service is one where a user submits some data (or a hash of some data) and gets back a document that proves the data existed at that time.

Traditionally this was done by Trusted Timestamp services. These would sign the data with their keys and return a signed and dated document.

This depended on the trusthwothiness, security and impartiality of the service provider in addition to regular public key infrastructure PKI.

In the blockchain world, we like to ask "Do we really need to trust someone for this? Can we make it trustless?"

The answer is of course, yes, we can. We can take some data and embed it into a transaction that gets folded into the next block in a chain. This is not new, we've been doing this since nearly the start of Bitcoin. Example from myself: Bitcoin Timestamp

However, this means making transactions on the public ledger, which are not cheap. Merkle Trees to the rescue. We can take a bunch of data we want to timestamp, combine it all using a merkle tree and embed that single result in the blockchain. That is the purpose of this project, to be able to make cheap blockchain based timestamps.


Uses

The cheap is super important. Often, we probably won't know the value of data or having a proof on it until much later.

So for example, an app that saved the hash of every picture you took on your phone might be cool. Most wouldn't matter, but it would be nice if you ever needed to later prove that one of the pictures was not edited after the time of the timestamp.

So images, videos, even video streams (if you can get low level enough into the video stream to decide what data to predictably hash on). Documents. Source code. Things I haven't thought of.

API

The API is simple. One call that provides the data to include and the result is some transaction ID for the timestamp. Then some time later, the user can call again with the transaction ID and get the entire proof.

  • /api/v1/info - get general info about the service
  • /api/v1/publish?hash=XXXX - publish a hash. The hash must be a hex encoded string
  • /api/v1/getproof?transaction_hash=XXXX - check on a transaction hash, which is given as an output to a publish

Instances

We are running an instance that anyone is free to use at https://timestamp.snowblossom.org/

Info Publish GetProof

Design

This timestamp service uses Channels as the metadata storage layer. Requested timestamp data is encoded into ContentInfo objects that are placed in Snowblossom Channels blocks for the channel the timestamp service is running as. Then on a schedule, the top channel block is encoded as the tx_extra field in a cryptocurrency transaction.

Once that is done and the resulting cryptocurrency transaction is confirmed into a block, then it is possible for the timestamp service to generate the complete proof all the way from the input data to the block hash of a cryptocurrency block.

The structure of the proof will be a series of hash steps that look like:

M = input data

Each step will define a hash algorithm, a prefix and a postfix string. M = hash( prefix + M + postfix )

The final M will be the block hash of a cryptocurrency block that can be verified with a local node or a block explorer.

All strings are hex encoded binary and all hash operations should occur on the binary data. Put another way, a 64 character long hex string needs to be converted to a 32 byte array before doing any hash operations.

Example proof, which proves that the data_hash of 710150e9eb6d7b7377e75d82f43bb4a84fc3ea42f08ea56bd594c4be7c4fb3b2 was included in Snowblossom Block 0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8.

The number of steps will depend on the depth of the merkle trees for timestamp data going into the channel block, the number of channel blocks until one that is included in the public blockchain and the merkle depth of transactions in the blockchain.

{
 "snow_block": "0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8",
 "data_hash": "710150e9eb6d7b7377e75d82f43bb4a84fc3ea42f08ea56bd594c4be7c4fb3b2",
 "proofs": [
   {
     "output": "49f3b7c82f9086ac4a787b12f28d953271d8e52e6d57fe67c3b6466ed72ef437",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10b4d3bae3e131aa017f0a20b82b7a9edd0fb5faaacf7b9c7877dedf74f00feb3fd0ffc95ff4203271a94db418202220",
     "postfix_data": "2a142e74b7bd6036178436b129bead2095b4a2da0bb0d2012056b2407d8c038a50ad01c546ff7037acd46871fa3a281fbf29ced7e982be2325",
     "action": "hash",
     "label": "transaction payload",
     "mid_data": "710150e9eb6d7b7377e75d82f43bb4a84fc3ea42f08ea56bd594c4be7c4fb3b2",
     "algo": "Skein-256-256"
   },
   {
     "output": "d5f022da0cd087b926179af71d5d68d3858926fed74787347b5684b4be97119e",
     "prefix_data": "",
     "postfix_data": "304502210099df6b4d399ff3e101c04e41b72e62524752c3d287fafe9dfe31ff7ffc23dda902201c985cd2b85847d27ae1c2247c9cc605c67e0e13792db5fba86f266479505ab4",
     "action": "hash",
     "label": "transaction outer",
     "mid_data": "49f3b7c82f9086ac4a787b12f28d953271d8e52e6d57fe67c3b6466ed72ef437",
     "algo": "Skein-256-256"
   },
   {
     "output": "411949ff64a54d4301ac5ccbf5e67999c5f4a1d499254f1599f165931a428139",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e8c3bde3e131a2016608011090161a142e74b7bd6036178436b129bead2095b4a2da0bb022202b9d8f6a293e4749ff1de445996ab1982ca0c66d2f9e475a0470281d3e6e82363220",
     "postfix_data": "38e8c3bde3e131",
     "action": "hash",
     "label": "block payload",
     "mid_data": "d5f022da0cd087b926179af71d5d68d3858926fed74787347b5684b4be97119e",
     "algo": "Skein-256-256"
   },
   {
     "output": "565a051329f8dfd2f8c0787ecf97df682d522026e38bf0b4f718a91c4d114ce8",
     "prefix_data": "",
     "postfix_data": "304602210094127432d522878c481771815f0b08f0dc74c83cf60a2d03dbdb257f3b8619e9022100e591e96ee5cff085bf2ee41b173a6d111c41186dfe4db11b0ee7514520072285",
     "action": "hash",
     "label": "block outer",
     "mid_data": "411949ff64a54d4301ac5ccbf5e67999c5f4a1d499254f1599f165931a428139",
     "algo": "Skein-256-256"
   },
   {
     "output": "e312bbac7a5f8134b5dac041a8d858442b5f7e8d1e9fc8e26b7377fbf449bb10",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10a7edc4e3e131a2016608011091161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "322028cbab24a483b47034af702dbcc8d4e78211bb16901d9bf2669eca3eaf93c06638a7edc4e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "565a051329f8dfd2f8c0787ecf97df682d522026e38bf0b4f718a91c4d114ce8",
     "algo": "Skein-256-256"
   },
   {
     "output": "b4cd4316465c7abcd8a4bd6816e9e6970dc4c255d92a05e508e0875f463a9bc0",
     "prefix_data": "",
     "postfix_data": "3046022100ea4cb42e77918a287ce9bb4c9372dcb56124feba27b210c198a230931b0e4a6c022100dc76a79d68b103d6655d0a0f4cb93c31588b3402c5d360fc697c8bc2400202c7",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "e312bbac7a5f8134b5dac041a8d858442b5f7e8d1e9fc8e26b7377fbf449bb10",
     "algo": "Skein-256-256"
   },
   {
     "output": "1126cc1f6a30d0790489f5ce40efec834ac9f202503a8697e38b77f7eb70b80e",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e796cce3e131a2016608011092161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "322075a3a001c4d79659006842c0118ddd7e2a2a5f0b867e2bd3bf02a3ee9695aaed38e796cce3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "b4cd4316465c7abcd8a4bd6816e9e6970dc4c255d92a05e508e0875f463a9bc0",
     "algo": "Skein-256-256"
   },
   {
     "output": "1badbbf025a4ed85b9544b07217df889ecd8f60c845458083b723eca0e84d29d",
     "prefix_data": "",
     "postfix_data": "304402202f0a44742b02709b2961bcd805c507527749d9d0d33ca9bf37bc26c4e83ace95022013c775d28823b283e4a9002d2865cffa014deb55133a9f22aaecf9d7a367c06a",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "1126cc1f6a30d0790489f5ce40efec834ac9f202503a8697e38b77f7eb70b80e",
     "algo": "Skein-256-256"
   },
   {
     "output": "a258424398a45b6e60804267c8546577b0a22d7de8ddafd1818f28190c6ba1a4",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10a8c0d3e3e131a2016608011093161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "3220c3383909249d5ae30659888a94dda0397c3247bf4a877c37f4a251ce1861929c38a8c0d3e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "1badbbf025a4ed85b9544b07217df889ecd8f60c845458083b723eca0e84d29d",
     "algo": "Skein-256-256"
   },
   {
     "output": "f8b8ce1090d4fb1d0f07bc7e1f7b2eed0bdab5e0ea45e139920a4ad7647d0c50",
     "prefix_data": "",
     "postfix_data": "3046022100dc8433156e2568c4e43fdfef0d2ce30489980a64adceb5f41f225b3ed341cd720221008769e368c6dffc252198d4c64c298642191f0a7e7a748d516f8031cc57e392c8",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "a258424398a45b6e60804267c8546577b0a22d7de8ddafd1818f28190c6ba1a4",
     "algo": "Skein-256-256"
   },
   {
     "output": "076e82df4ad0baff75cb9d29b125d24b7c2ba692ad5b11d2e1089f21951a2ac8",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e7e9dae3e131a2016608011094161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "32207f1696622d4e1baae075ab6e4a808d32e19a505a75530052dc45c3649e85726438e7e9dae3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "f8b8ce1090d4fb1d0f07bc7e1f7b2eed0bdab5e0ea45e139920a4ad7647d0c50",
     "algo": "Skein-256-256"
   },
   {
     "output": "d75e66cb7577aa33ca29efe783956ac52ea0d0dc0c594f1fd544d09383edc18a",
     "prefix_data": "",
     "postfix_data": "3044022003bc9542824945aa70973fb277090546d63f6786e6074eeb34cd13f3c50331b502201f371bc771cb34044e797351ad7554bcab65a2a1c802ab267651a195dcada878",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "076e82df4ad0baff75cb9d29b125d24b7c2ba692ad5b11d2e1089f21951a2ac8",
     "algo": "Skein-256-256"
   },
   {
     "output": "a1b4b2fdb4a88c7a0be1622969d6ee895f8d277296248e1b3c2ee97857da8bbd",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10a993e2e3e131a2016608011095161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "322043fb9d34172ff2fe03948270638da9cc412e73ee4cdf472a39afee3d8f3aa6fa38a893e2e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "d75e66cb7577aa33ca29efe783956ac52ea0d0dc0c594f1fd544d09383edc18a",
     "algo": "Skein-256-256"
   },
   {
     "output": "fa692ea57b6cc00301b74e43ee883a0ee1ad14e727296cd1185a881d2ac6b334",
     "prefix_data": "",
     "postfix_data": "304402205d974b41c97dde821edfa37695aeb30958049f4e0847ea119a90197ca99cd30a02204342468b8d9a57c83605011c32e46ceab3ef5af5103f1b9d18e65d82c596cace",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "a1b4b2fdb4a88c7a0be1622969d6ee895f8d277296248e1b3c2ee97857da8bbd",
     "algo": "Skein-256-256"
   },
   {
     "output": "9aaf7c7a9fa59108595902fd0d5299d0652fab2654ec6a153b66fde9270f5081",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e8bce9e3e131a2016608011096161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "3220393a2c4d3b05def1ad3d34ea6aeff9c37473e8025f368f0c61f0b18ef2f77be038e8bce9e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "fa692ea57b6cc00301b74e43ee883a0ee1ad14e727296cd1185a881d2ac6b334",
     "algo": "Skein-256-256"
   },
   {
     "output": "e759e9e9e47dd7f12f9d31f3c82a42b3b2497f0a6adda49a8f0113d1cf40d19a",
     "prefix_data": "",
     "postfix_data": "304502204339a508ecafd9b5a63e9aa60afc5cf8e4b7bc5f665065aee026215016c7b654022100ddb053a9bd0d1468a90d06628237265128b2a9987c9fad7cd9bb221246bd77f7",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "9aaf7c7a9fa59108595902fd0d5299d0652fab2654ec6a153b66fde9270f5081",
     "algo": "Skein-256-256"
   },
   {
     "output": "0da7eedddb27a71d1f8b966cc38a99e94b147b9afbed4f9caf66dac3f64bcce6",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10a8e6f0e3e131a2016608011097161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "32200b4ddc38bf088ef57f0cb96a83117257e47e85a9d21064ea65b511f4ee0d37e938a8e6f0e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "e759e9e9e47dd7f12f9d31f3c82a42b3b2497f0a6adda49a8f0113d1cf40d19a",
     "algo": "Skein-256-256"
   },
   {
     "output": "97c417aa95f05c7a9a3fbd3cae48941ebb328f53e114c13237e15bd4a30740d9",
     "prefix_data": "",
     "postfix_data": "3045022100c2945652229417e75d99fdffa11846f64be02ba97dc1e13c9cbe0f2c8a11672d022048a9f74f085cfd468b160596a42453a8d38af3da6a7fe402866d4aff679302a7",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "0da7eedddb27a71d1f8b966cc38a99e94b147b9afbed4f9caf66dac3f64bcce6",
     "algo": "Skein-256-256"
   },
   {
     "output": "883718f2d638d77a4ebaf2f9ab5953cc53235c38e47d90909be91d88a4ccdb68",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e88ff8e3e131a2016608011098161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "32204cb2dd58bcc6eb9d5118e9b17ee8e700fb1b227cb01447303e6852ffd32d4abb38e88ff8e3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "97c417aa95f05c7a9a3fbd3cae48941ebb328f53e114c13237e15bd4a30740d9",
     "algo": "Skein-256-256"
   },
   {
     "output": "aa78e8bf5cc7fd1eb3ab7c63ad68d3095e946b2b1aeacc9bf01f1fbdde18d513",
     "prefix_data": "",
     "postfix_data": "30450221009d031ce0c5014ead018dda4a2ba65d7fa2fba1d0f65dc10ac02e6a36219a9a3f022026599e551b57196789152ae2fb9a2ae9f9627501359eeb5d66292a6297ee6cfa",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "883718f2d638d77a4ebaf2f9ab5953cc53235c38e47d90909be91d88a4ccdb68",
     "algo": "Skein-256-256"
   },
   {
     "output": "9ba69d92a20a944560552d6f8f83512b75bbd15ca89fb5e0c2c6d6df12d0dd74",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10a8b9ffe3e131a2016608011099161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "32200811b8b7383d841b6c878d6f7dc39ee4a5c6b27e5c055fb5d107c0aa2e0846af38a8b9ffe3e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "aa78e8bf5cc7fd1eb3ab7c63ad68d3095e946b2b1aeacc9bf01f1fbdde18d513",
     "algo": "Skein-256-256"
   },
   {
     "output": "45ad167039ba0ef4cb7af43b7d787bfa35d16d9f18e0d5fa2a2595739f0bd154",
     "prefix_data": "",
     "postfix_data": "304502207e79e97cf8cef396e3c6a6fcb08aa98390c44182becc393ff13d756d716f0635022100cffce8f2b911d7c930a02857202d4a850c690e1e760517bfabd64e6e37a007de",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "9ba69d92a20a944560552d6f8f83512b75bbd15ca89fb5e0c2c6d6df12d0dd74",
     "algo": "Skein-256-256"
   },
   {
     "output": "7abe420906b785e5baf20944db6efb4e91e2e387c9f6761cfa5583bd28e90a08",
     "prefix_data": "0a290801122508011221023bf6b14c3b03f0ed8b9b642dba44167c3535bbd7d68b4a3b32f63ddda746dc8e10e8e286e4e131a201660801109a161a142e74b7bd6036178436b129bead2095b4a2da0bb02220",
     "postfix_data": "3220bfecfcaf4c7bb13c210dcbd643791a988a97f3be42d7453a8fa868e8ac1800be38e8e286e4e131",
     "action": "hash",
     "label": "channel block path payload",
     "mid_data": "45ad167039ba0ef4cb7af43b7d787bfa35d16d9f18e0d5fa2a2595739f0bd154",
     "algo": "Skein-256-256"
   },
   {
     "output": "c30aad00cfee24452be412e40bde662bce32c82a89f307ee917733bbbeefea6c",
     "prefix_data": "",
     "postfix_data": "30450220571a29f8ee83901f537fd013c216390dd07106dfa0d5fa783c52887cbeb6d3c1022100ef805fef432440f5fafbc9d897bcaab79ede7c57e032515755f9b1b2ff909ea1",
     "action": "hash",
     "label": "channel block path outer",
     "mid_data": "7abe420906b785e5baf20944db6efb4e91e2e387c9f6761cfa5583bd28e90a08",
     "algo": "Skein-256-256"
   },
   {
     "output": "c3be5a72e6ab2d6fabf3eae673cf4e6491d551946b48a4b2270cf75fc4b4c2bb",
     "prefix_data": "080122380a149adb8a3c67660a5ebc8db83f69cf525783f3d17d12204c6c0e011ed421cbda86dceea00c51248516cdfe838f13abcf509d61a186bed02a1b08a0b4e31712149adb8a3c67660a5ebc8db83f69cf525783f3d17d322908011225080112210284bb49bd3f7ddabc1dc8dc257c74e995bcfa62493215710a1f885fed95af127a40d7065220",
     "postfix_data": "",
     "action": "hash",
     "label": "snow tx has channel block hash",
     "mid_data": "c30aad00cfee24452be412e40bde662bce32c82a89f307ee917733bbbeefea6c",
     "algo": "Skein-256-256"
   },
   {
     "output": "69a7ea6037c7e05899248fdfdff4e5b264ef157509c1ea5b27c477b5795cc804",
     "prefix_data": "9468a809e1d7815d0683541931268e9facc17e45ff4a7eabbce7ffcb11a2c997",
     "postfix_data": "",
     "action": "hash",
     "label": "merkle right",
     "mid_data": "c3be5a72e6ab2d6fabf3eae673cf4e6491d551946b48a4b2270cf75fc4b4c2bb",
     "algo": "Skein-256-256"
   },
   {
     "output": "7115e6ac4f08eda934e1a5ca3e72035b7f224a157cf790906333401cf0064a2d",
     "prefix_data": "",
     "postfix_data": "4e50cf9f67d76d62d14c1217f279567fa1c54b926315df596b71de929c051fde",
     "action": "hash",
     "label": "merkle left",
     "mid_data": "69a7ea6037c7e05899248fdfdff4e5b264ef157509c1ea5b27c477b5795cc804",
     "algo": "Skein-256-256"
   },
   {
     "output": "96968de1dbe63b3723e86d68f672362166b826c7710e9b073fab41a02c0a7796",
     "prefix_data": "2c89f35817fc051f865bda04000000020004aeb20000018e1c869322000000090000000000131e991e09fa2694657603c9d26d5578fc582f422c5b71bb9bd337",
     "postfix_data": "483d59f8110c4385124fe6750fade03b395eb4a5dda12788b8253ce15085429c00000000002917a199dd3484bc37b0dae90b65578600b4a75e18b0f48429266100000000000002a100000003",
     "action": "hash",
     "label": "snow pow",
     "mid_data": "7115e6ac4f08eda934e1a5ca3e72035b7f224a157cf790906333401cf0064a2d",
     "algo": "Skein-256-256"
   },
   {
     "output": "2c6c12de3a5d2b1d7fe3c72c855b443603d9d54dcdc9fd39a6e4ac8c32e0f1cf",
     "prefix_data": "",
     "postfix_data": "78d974a450cdccd36ab7d61bbb892142",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "96968de1dbe63b3723e86d68f672362166b826c7710e9b073fab41a02c0a7796",
     "algo": "Skein-256-256"
   },
   {
     "output": "11540bc97b97c8d1f381c4f1af2e3688060ce9d437a1308203adc132641c3827",
     "prefix_data": "",
     "postfix_data": "a4e09416b53b7d140750c6e8d93c347f",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "2c6c12de3a5d2b1d7fe3c72c855b443603d9d54dcdc9fd39a6e4ac8c32e0f1cf",
     "algo": "Skein-256-256"
   },
   {
     "output": "62f52521c688922c4e6d256181e49c6438e2981acae3514d44c3767b06ccfe29",
     "prefix_data": "",
     "postfix_data": "59d76d65c58f64591a53b69cac1d04da",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "11540bc97b97c8d1f381c4f1af2e3688060ce9d437a1308203adc132641c3827",
     "algo": "Skein-256-256"
   },
   {
     "output": "42bbdb5ca5a7613d849814e5625231f0965550a30db6486976fbcb0ce8902304",
     "prefix_data": "",
     "postfix_data": "134b6dae2ca7d24a71e9b907c2a1c671",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "62f52521c688922c4e6d256181e49c6438e2981acae3514d44c3767b06ccfe29",
     "algo": "Skein-256-256"
   },
   {
     "output": "62cd17a79318589d1a8580d2a0eb5d7f1ed91eff1b879f75c47d3482e81b8783",
     "prefix_data": "",
     "postfix_data": "a3ee7f5aacd86a286ad95d17def4b751",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "42bbdb5ca5a7613d849814e5625231f0965550a30db6486976fbcb0ce8902304",
     "algo": "Skein-256-256"
   },
   {
     "output": "0000000000276312f079297412ecd2168f9b21057dc911758984add713c551b8",
     "prefix_data": "",
     "postfix_data": "888ab462b300217ca79c19fafffc614d",
     "action": "hash",
     "label": "snow pow step",
     "mid_data": "62cd17a79318589d1a8580d2a0eb5d7f1ed91eff1b879f75c47d3482e81b8783",
     "algo": "Skein-256-256"
   }
 ],
 "channel_block_hash": "565a051329f8dfd2f8c0787ecf97df682d522026e38bf0b4f718a91c4d114ce8",
 "transaction_hash": "d5f022da0cd087b926179af71d5d68d3858926fed74787347b5684b4be97119e",
 "snow_transaction": "c3be5a72e6ab2d6fabf3eae673cf4e6491d551946b48a4b2270cf75fc4b4c2bb"
}

A user of the service can either request and save proofs (which stand on their own with no additional metadata required) or the user can have their own snowblossom channels node join the timestamp service channel and replicate the metadata. That way, their own node could always generate proofs as needed.

Version Plan

  • v1 - Basic operation backed by Snowblossom (done as of 2024.03.04)
  • v2 - Recursive operation (a timestamp service can use another timestamp service as its backing)
  • v3 - Other chains (Bitcoin, Bitcoin Cash, Ethereum)

Scaling

For such a service to be really useful, it needs to scale and continue to be inexpensive.

Here is an example architecture that would work:

API endpoint goes to a request router. The request router knows which backends (each running their own channel) are availible. Request router sends timestamp requests to an available backend. Request router sends proof requests to the appropriate backend for the chain the transaction is on.

The backend nodes operate on channels each with an active-active configuration where any of the nodes on a channel could accept timestamp requests, service proof lookups or generate blocks. There would have to be a little coordination to avoid creating blocks close in time and confusing the channel's mempool. Same for deciding when to save state to the upstream timestamp service.

So imagine the backend nodes as pairs, each pair servicing one channel. Then the occasionally save state to an upstream timestamp service. Add more pairs running channels as needed for the load.

The upstream master timestamp service would occasionally save to public blockchains.

With this model, we can extend to a very high request rate while still only saving a transaction on a public chain every few blocks.