Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ots stamp-digest subcommand #133

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions otsclient/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,31 @@ def parse_ots_args(raw_args):
help="Consider the timestamp complete if at least M calendars reply prior to the timeout. "
"Default: %(default)s")

# ----- stamp-digest -----
parser_stamp_digest = subparsers.add_parser('stamp-digest',
help='Timestamp a digest')

parser_stamp_digest.add_argument('-c', '--calendar', metavar='URL', dest='calendar_urls', action='append', type=str,
default=[],
help='Create timestamp with the aid of a remote calendar. May be specified multiple times.')

parser_stamp_digest.add_argument('-b', '--btc-wallet', dest='use_btc_wallet', action='store_true',
help='Create timestamp locally with the local Bitcoin wallet.')

parser_stamp_digest.add_argument('hex_digest', metavar='DIGEST',
help='32-byte hex-encoded SHA256 digest')

parser_stamp_digest.add_argument('timestamp_fd', metavar='TIMESTAMP', type=argparse.FileType('wb'),
help='Timestamp filename')

parser_stamp_digest.add_argument("--timeout", type=int, default=5,
help="Timeout before giving up on a calendar. "
"Default: %(default)d")

parser_stamp_digest.add_argument("-m", type=int, default="2",
help="Consider the timestamp complete if at least M calendars reply prior to the timeout. "
"Default: %(default)s")

# ----- upgrade -----
parser_upgrade = subparsers.add_parser('upgrade', aliases=['u'],
help='Upgrade remote calendar timestamps to be locally verifiable')
Expand Down Expand Up @@ -236,6 +261,7 @@ def parse_ots_args(raw_args):


parser_stamp.set_defaults(cmd_func=otsclient.cmds.stamp_command)
parser_stamp_digest.set_defaults(cmd_func=otsclient.cmds.stamp_digest_command)
parser_upgrade.set_defaults(cmd_func=otsclient.cmds.upgrade_command)
parser_verify.set_defaults(cmd_func=otsclient.cmds.verify_command)
parser_info.set_defaults(cmd_func=otsclient.cmds.info_command)
Expand Down
41 changes: 41 additions & 0 deletions otsclient/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,47 @@ def stamp_command(args):
logging.error("Failed to create timestamp %r: %s" % (timestamp_file_path, exp))
sys.exit(1)

def stamp_digest_command(args):
try:
digest = binascii.unhexlify(args.hex_digest.encode('utf8'))
except binascii.Error as exp:
logging.error("Bad digest %r: %s" % (args.hex_digest, exp))
sys.exit(1)

if len(digest) != 32:
logging.error("Bad digest %r: got %s bytes; expected 32" % (args.hex_digest, len(digest)))
sys.exit(1)

timestamp_file = DetachedTimestampFile(OpSHA256(), Timestamp(digest))

# Add nonce
#
# Remember that the files - and their timestamps - might get separated
# later, so if we didn't use a nonce for every file, the timestamp
# would leak information on the digests of adjacent files.
nonce_appended_stamp = timestamp_file.timestamp.ops.add(OpAppend(os.urandom(16)))
merkle_tip = nonce_appended_stamp.ops.add(OpSHA256())

if not args.calendar_urls:
# Neither calendar nor wallet specified; add defaults
args.calendar_urls.append('https://a.pool.opentimestamps.org')
args.calendar_urls.append('https://b.pool.opentimestamps.org')
args.calendar_urls.append('https://a.pool.eternitywall.com')
args.calendar_urls.append('https://ots.btc.catallaxy.com')

create_timestamp(merkle_tip, args.calendar_urls, args)

if args.wait:
upgrade_timestamp(merkle_tip, args)
logging.info("Timestamp complete; saving")

try:
ctx = StreamSerializationContext(args.timestamp_fd)
timestamp_file.serialize(ctx)
except IOError as exp:
logging.error("Failed to create timestamp file: %s" % (exp))
sys.exit(1)

def is_timestamp_complete(stamp, args):
"""Determine if timestamp is complete and can be verified"""
for msg, attestation in stamp.all_attestations():
Expand Down