Commit 391ab425 authored by Daniel Kraft's avatar Daniel Kraft

Interpret demo in the README file.

parent 51a24a4c
#!/usr/bin/env python
# Namestamp - link Namecoin timestaps to the Bitcoin blockchain.
# Copyright (C) 2015 Daniel Kraft <d@domob.eu>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This is a proof automatically generated by namestamp.
import binascii
import hashlib
def reverseHex (hexStr):
"""
Reverse the byte order in a hex string. This is what Bitcoin
does with uint256's.
"""
data = bytearray (binascii.unhexlify (hexStr))
data.reverse ()
return binascii.hexlify (data)
def doubleHash (data):
"""
Perform Bitcoin's Double-SHA256 hash on the given byte array.
"""
hasher = hashlib.sha256 ()
hasher.update (data)
data = hasher.digest ()
hasher = hashlib.sha256 ()
hasher.update (data)
data = bytearray (hasher.digest ())
return data
class ChainHasher:
"""
Encapsulate the operation of hashing data with pre- and postfixes
over and over again.
"""
def __init__ (self, initialStr):
"""
Initialise the hasher with the initial data given as string.
This string is converted to a byte array.
"""
self.data = bytearray (initialStr)
def hash (self, preHex, postHex):
"""
Concat prefix- and postfix-constants to the value and hash the
resulting data. Pre- and postfix are hex strings.
"""
res = bytearray ()
if preHex is not None:
res.extend (bytearray (binascii.unhexlify (preHex)))
res.extend (self.data)
if postHex is not None:
res.extend (bytearray (binascii.unhexlify (postHex)))
self.data = doubleHash (res)
def reverse (self):
"""
Reverse the current state. This is required for auxpow verification.
"""
self.data.reverse ()
def getHex (self):
"""
Return the current data as hex string.
"""
return binascii.hexlify (self.data)
def getRevHex (self):
"""
Return the current data as reversed hex string.
"""
return reverseHex (self.getHex ())
def get (self):
"""
Return the current data as byte array.
"""
return self.data
################################################################################
# The proof data comes next.
def proof (value, c):
h = ChainHasher (value)
print 'Proving value:\n%s\n' % value
h.hash (c[0], c[1])
print 'Original txid: %s' % h.getRevHex ()
h.hash (None, c[2])
h.hash (c[3], None)
h.hash (None, c[4])
h.hash (c[5], c[6])
print 'Namecoin block: %s' % h.getRevHex ()
h.hash (c[7], c[8])
h.hash (c[9], c[10])
h.hash (c[11], None)
h.hash (c[12], None)
h.reverse ()
h.hash (c[13], c[14])
h.hash (None, c[15])
h.hash (None, c[16])
h.hash (None, c[17])
h.hash (None, c[18])
h.hash (None, c[19])
h.hash (None, c[20])
h.hash (None, c[21])
h.hash (None, c[22])
h.hash (None, c[23])
h.hash (None, c[24])
h.hash (None, c[25])
h.hash (c[26], c[27])
print 'Bitcoin block: %s' % h.getRevHex ()
value = 'ca6e28f4c0358dd827ef6a53fbf3a8bc146325f5ecbfb52b35f55dd5410a75c7,51a24a4cddb756a99bc91e61e148ac68484993e6'
data = []
data.append ('007100000289f469ece4c71c7feb3c167f267fae1ed609a0b2afd0fc2b1f9798831b950e78010000008b483045022100913075ed0f48be77b92996f51365e2a6a9133ef8bde0f3ea919953c582a7210202203ece48abbec23bcb782a561dce9b9fa6f96d76cd7acaf96da2fe4bfb1fb5c101014104f1b8555d6315e0ff1bab677e7c78dd5fdd81d1f6cf7c7d7e2f5cec3de0cb751e3939f6ec9aa5db271a5b206ff4dc256eca2d6c35a76cf5ceb55098947a6d4e03feffffffdbcba753e6efd4f6fa26c3c2cd8df60d02b52d3df3401dd74fd303baefefc31e010000008a473044022026b898007d05f27cc703294096ab91c31fa2869717d931c6ceeef5efdc285b7202203c61fce11824b7b42b1f34e50d74f012e4dcaa941b8d09ac368c4617dec2ce1901410468a703df5d98d403b423b5b78e68de28a69ba8e73ee75d88bb4bfc4451e65dfa73037e3ee76e30699374de7f509dcebd4a066a6f82c9933bc023d99a6a25e2f0feffffff02e0528b02000000001976a914877c1acd411abd79bb3a65a20a5d3a8aba3029b288ac40420f000000000093530b642f6e616d657374616d704c69')
data.append ('6d7576a914f439914608135c824ff3eb0e9ecaa59441049fa488ac85590300')
data.append ('3e51a337700da5e133d9817be43b1298cd5b29eb1f224d3eac74a965c0a5a071')
data.append ('e720040704b5815ff44461bdbb29a22c274c84f180aee136b18165bc99728017')
data.append ('43b7eb5776b209095b00d00ba1f1c8b1f0c0d153b2aa4bd7886edade2945a617')
data.append ('010101004c2356577ed08e1e666416de48e0a9c868fd2e654836da4b8f12657ed7c565b4')
data.append ('b63ceb548423431800000000')
data.append ('02010100')
data.append ('5a33a00da9d7fc7d5f8e6d3ef706573d22bdef372009b8dfc38780cd58ce2dfbe743eb548423431800000000')
data.append ('01010100')
data.append ('7020d252c2817106dd3b3503e4b639043a37bce753fa43d57345609a87a2576b194ceb548423431800000000')
data.append ('efb19ec0087e9b09c6adc02bc5cf1f2c5ac80751c58a7942be688f52b07608af')
data.append ('2c95454293eded08da39e3edcdc747e14f3181a4f2babaa4168d9ae4789534d7')
data.append ('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4803f94205062f503253482f04074deb540815bc0a5732ca0c002e522cfabe6d6d')
data.append ('04000000000000000000000001e651e195000000001976a91480ad90d403581fa3bf46086a91b2d9d4125db6c188ac00000000')
data.append ('7e339449cf88572d9aa2e28c57aa858bd3724e45620f6b22e201cd255a099914')
data.append ('9d8c4b454b8c0d3c3c9ec723a8de18a3b730c7139ce8960615925f0d3710460a')
data.append ('69cb32c5a89f42b20132e94c278f8ebbb25dc4b8bfdbdc2d26496214cbcdfef4')
data.append ('a0b507566253ca1bd7ebdb85e40575ab302e2a0ebdf4809665dfc7cfd812b39b')
data.append ('efd17c85bf84252d6830286157e3f369b10f9f0b8b3be1f74704cf5907fca57e')
data.append ('1bce749cecc57767f0fbdb1fd31b3bf3882cd0dbb2e5e385e56201046ff35f98')
data.append ('ef6162f35613d4a1a6cedd622d5503ee12163153fa79b1a6f897641c1e183e76')
data.append ('fac028f80fecd202de64fdf6bb22be621e09d0d8e617d5fefa254ec989023ba9')
data.append ('e0cfba9f2f425af80b67353079c0811fbf61cc9dd37a90c2496ac1ef46c285c7')
data.append ('b3376ce3500bcfa20b3947904337a8a05439b73a1a4378a92974e8d4db1fd9a2')
data.append ('048ad317dc7d3a20320f422a10b9c4bb7f7d00f672c19a6108de5e0b64d5abda')
data.append ('020000001eae9f4ebab61ed21a82372e4bbe9a56992c8705c81874120000000000000000')
data.append ('064deb543a8d1718d2372c03')
proof (value, data)
......@@ -119,3 +119,88 @@ The ports at which NameStamp tries to access the APIs are hardcoded in the
script. This should be fine as long as you do not use non-standard
"rpcport"s. If you do, just edit namestamp.py accordingly and set your
value at the top.
Live Demo
---------
I have used NameStamp itself to create a time-stamping proof for an early
version of NameStamp's code. This can serve as a nice example and demontration.
The data is contained in the Namecoin transaction
f9e91213b5f5c0156ab92eec606affa40959d19e02849fe31a5c47aa78cb1298,
which sets the name 'd/namestamp' to the value (with added line break):
ca6e28f4c0358dd827ef6a53fbf3a8bc146325f5ecbfb52b35f55dd5410a75c7,
51a24a4cddb756a99bc91e61e148ac68484993e6
The first, longer hex string is the SHA-256 sum of the actual data file,
which is kept in Demo/namestamp-poc.tar.bz2. The second, shorter hex
string is the SHA-1 commit in Git corresponding to the tag "timestamp-demo".
Using NameStamp and the transaction id above, we can simply create a proof:
$ namestamp.py f9...98 >proof.py
Stamped in Namecoin blockchain: 2015-02-23 15:44:06
Stamped in Bitcoin blockchain: 2015-02-23 16:53:42
As you can see, NameStamp also writes out the real-world times in the Namecoin
and Bitcoin blocks found while constructing the proof. In this case, you can
see that the Namecoin block containing the transaction was there before
a valid merge-mined Bitcoin block was found. This most likely means that
the merge-mining proof found for the Namecoin block was not "difficult enough"
to qualify also for the Bitcoin network. That can happen, but is no problem
to the design of NameStamp. We can just follow up the chain of Namecoin
blocks until we find one that actually corresponds to a Bitcoin block.
More important, however, is the created proof in the output file. You can
find it in Demo/proof.py if you do not want to (or can not) run NameStamp
yourself. Running the proof as Python script prints:
$ python Demo/proof.py
Proving value:
ca6e28f4c0358dd827ef6a53fbf3a8bc146325f5ecbfb52b35f55dd5410a75c7,
51a24a4cddb756a99bc91e61e148ac68484993e6
Original txid: f9e91213b5f5c0156ab92eec606affa40959d19e02849fe31a5c47aa78cb1298
Namecoin block: 3e9c6d1d6d10281bc71283984db106ee28cff70e42a60dcd7da3486845cb13c5
Bitcoin block: 000000000000000000e6ee318f139c381502ddd357d0d4561a619c464b2b5b79
This shows you the time-stamped value, the Namecoin transaction id, and the
two block hashes that "contain" the transaction. Most important, of course,
is the Bitcoin block hash at the bottom. This hash can be used independently
to verify its authenticity and real-world time against the Bitcoin blockchain.
Let us now also view the proof script itself. The important part of the
script is this:
def proof (value, c):
h = ChainHasher (value)
print 'Proving value:\n%s\n' % value
h.hash (c[0], c[1])
print 'Original txid: %s' % h.getRevHex ()
h.hash (None, c[2])
h.hash (c[3], None)
h.hash (None, c[4])
h.hash (c[5], c[6])
print 'Namecoin block: %s' % h.getRevHex ()
h.hash (c[7], c[8])
h.hash (c[9], c[10])
h.hash (c[11], None)
h.hash (c[12], None)
h.reverse ()
h.hash (c[13], c[14])
h.hash (None, c[15])
...
h.hash (None, c[25])
h.hash (c[26], c[27])
print 'Bitcoin block: %s' % h.getRevHex ()
At the very end, this function is called with "value" set to the data
string that is being time-stamped, and "c" set to an array of hex strings.
The latter is constructed carefully to fulfil the proof, but is not at all
important for the interpretation. If you look at the proof function above
as well as the definition of the class "ChainHasher", you will easily see
that the script really only takes the original value and hashes it together
with the various constants. The Bitcoin block hash printed at the end
is the ultimate hash value. This, indeed, shows that the time-stamped value
must have existed before the resulting Bitcoin block!
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment