def stamp_command(fd, args): # Create initial commitment ops for all files merkle_roots = [] try: file_timestamp = DetachedTimestampFile.from_fd(OpSHA256(), fd) except OSError as exp: logging.error("Could not read %r: %s" % (fd.name, exp)) return # Add nonce nonce_appended_stamp = file_timestamp.timestamp.ops.add( OpAppend(os.urandom(16))) merkle_root = nonce_appended_stamp.ops.add(OpSHA256()) merkle_roots.append(merkle_root) merkle_tip = make_merkle_tree(merkle_roots) create_timestamp(merkle_tip, CALENDAR_URLS, parse_ots_args(args)) try: with open("%s.ots" % fd.name, "wb") as timestamp_fd: ctx = StreamSerializationContext(timestamp_fd) file_timestamp.serialize(ctx) except IOError as exp: logger.error("Failed to create timestamp: %s" % exp) return
def cat_then_unary_op(unary_op_cls, left, right): """Concatenate left and right, then perform a unary operation on them left and right can be either timestamps or bytes. Appropriate intermediary append/prepend operations will be created as needed for left and right. """ if not isinstance(left, Timestamp): left = Timestamp(left) if not isinstance(right, Timestamp): right = Timestamp(right) left_append_stamp = left.ops.add(OpAppend(right.msg)) right_prepend_stamp = right.ops.add(OpPrepend(left.msg)) # Left and right should produce the same thing, so we can set the timestamp # of the left to the right. left.ops[OpAppend(right.msg)] = right_prepend_stamp return right_prepend_stamp.ops.add(unary_op_cls())
def submit(self, submitted_commitment): idx = int(time.time()) serialized_idx = struct.pack('>L', idx) commitment = submitted_commitment.ops.add(OpPrepend(serialized_idx)) per_idx_key = derive_key_for_idx(self.hmac_key, idx, bits=32) mac = hashlib.sha256(commitment.msg + per_idx_key).digest()[0:HMAC_SIZE] macced_commitment = commitment.ops.add(OpAppend(mac)) macced_commitment.attestations.add(PendingAttestation(self.uri)) self.journal.submit(macced_commitment.msg)
def upgrade_timestamps_tx(self, tx): for category, script, amount in tx.outputs(): if category == 2: # agt -> txid agt = script[4:] # drop "6a20" op_return and op_pushdata(32) tx_raw = tx.serialize(witness=False) if len(x(tx_raw)) <= Op.MAX_MSG_LENGTH: i = tx_raw.find(agt) prepend = x(tx_raw[:i]) append = x(tx_raw[i + len(agt):]) t_agt = Timestamp(x(agt)) t = t_agt.ops.add(OpPrepend(prepend)) t = t.ops.add(OpAppend(append)) t = t.ops.add(OpSHA256()) t = t.ops.add(OpSHA256()) # txid in little endian for f in self.proofs_storage_file.incomplete_proofs: tf = roll_timestamp(f.detached_timestamp.timestamp) if tf.msg == x(agt): tf.merge(t_agt) f.status = "pending" f.txid = t.msg[::-1].hex() self.update_storage()
def generate(msg_bytes): '''Generates certificate''' hashed_bytes = hashlib.new('sha256', msg_bytes).digest() file_timestamp = DetachedTimestampFile(OpSHA256(), Timestamp(hashed_bytes)) nonce_appended_stamp = file_timestamp.timestamp.ops.add(OpAppend(os.urandom(16))) timestamp = nonce_appended_stamp.ops.add(OpSHA256()) remote_calendar = RemoteCalendar(CALENDAR_URL) result = remote_calendar.submit(timestamp.msg, timeout=None) try: if isinstance(result, Timestamp): timestamp.merge(result) else: logging.debug(str(result)) except Exception as error: logging.debug(str(error)) return file_timestamp
def main(): parser = otsclient.args.make_common_options_arg_parser() parser.add_argument("-g", "--gpg-program", action="store", default="/usr/bin/gpg", help="Path to the GnuPG binary (default %(default)s)") parser.add_argument( '-c', '--calendar', metavar='URL', dest='calendar_urls', action='append', type=str, default=[ "https://calendar.bitmark.one", "https://a.pool.opentimestamps.org", "https://b.pool.opentimestamps.org", "https://a.pool.eternitywall.com", "https://ots.btc.catallaxy.com" ], help= 'Create timestamp with the aid of a remote calendar. May be specified multiple times. Default: %(default)r' ) parser.add_argument( '-b', '--btc-wallet', dest='use_btc_wallet', action='store_true', help='Create timestamp locally with the local Bitcoin wallet.') parser.add_argument("gpgargs", nargs=argparse.REMAINDER, help='Arguments passed to GnuPG binary') parser.add_argument("--timeout", type=int, default=5, help="Timeout before giving up on a calendar. " "Default: %(default)d") parser.add_argument("-m", type=int, default="2", help="Commitments are sent to remote calendars," "in the event of timeout the timestamp is considered " "done if at least M calendars replied. " "Default: %(default)s") parser.add_argument('--rehash-trees', action='store_true', help=argparse.SUPPRESS) args = otsclient.args.handle_common_options(parser.parse_args(), parser) logging.basicConfig(format='ots: %(message)s') args.verbosity = args.verbose - args.quiet if args.verbosity == 0: logging.root.setLevel(logging.INFO) elif args.verbosity > 0: logging.root.setLevel(logging.DEBUG) elif args.verbosity == -1: logging.root.setLevel(logging.WARNING) elif args.verbosity < -1: logging.root.setLevel(logging.ERROR) if len(args.gpgargs) == 0 or args.gpgargs[0] != '--': parser.error("You need to have '--' as the last argument; see docs") args.gpgargs = args.gpgargs[1:] parser = argparse.ArgumentParser() parser.add_argument("-bsau", action="store") parser.add_argument("--verify", action="store") gpgargs = parser.parse_known_args(args.gpgargs)[0] if gpgargs.bsau: with subprocess.Popen([args.gpg_program] + args.gpgargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as gpg_proc: logging.debug("Reading Git commit") git_commit = sys.stdin.buffer.read() logging.debug("Git commit: %r" % git_commit) # FIXME: can this fail to write all bytes? n = gpg_proc.stdin.write(git_commit) logging.debug("Wrote %d bytes to GnuPG out of %d" % (n, len(git_commit))) gpg_proc.stdin.close() gpg_sig = gpg_proc.stdout.read() # GnuPG produces no output on failure if not gpg_sig: sys.exit(1) logging.debug("PGP sig: %r" % gpg_sig) # Timestamp the commit and tag together signed_commit_timestamp = Timestamp( hash_signed_commit(git_commit, gpg_sig)) final_timestamp = signed_commit_timestamp # with git tree rehashing minor_version = 1 # CWD will be the git repo, so this should get us the right one repo = git.Repo() hextree_start = None if git_commit.startswith(b'tree '): hextree_start = 5 elif git_commit.startswith(b'object '): # I believe this is always a git tag hextree_start = 7 else: raise AssertionError("Don't know what to do with %r" % git_commit) hextree = git_commit[hextree_start:hextree_start + 20 * 2].decode() tree = repo.tree(hextree) tree.path = '' tree_stamper = GitTreeTimestamper(tree) final_timestamp = signed_commit_timestamp.ops.add( OpAppend(tree_stamper.timestamp.msg)).ops.add(OpSHA256()) otsclient.cmds.create_timestamp(final_timestamp, args.calendar_urls, args) if args.wait: # Interpreted as override by the upgrade command # FIXME: need to clean this bad abstraction up! args.calendar_urls = [] otsclient.cmds.upgrade_timestamp(signed_commit_timestamp, args) sys.stdout.buffer.write(gpg_sig) write_ascii_armored(signed_commit_timestamp, sys.stdout.buffer, minor_version) elif gpgargs.verify: # Verify with open(gpgargs.verify, 'rb') as gpg_sig_fd: gpg_sig = gpg_sig_fd.read() git_commit = sys.stdin.buffer.read() (major_version, minor_version, timestamp) = deserialize_ascii_armored_timestamp( git_commit, gpg_sig) if timestamp is None: print("OpenTimestamps: No timestamp found", file=sys.stderr) else: good = otsclient.cmds.verify_timestamp(timestamp, args) if good: logging.info("Good timestamp") else: logging.warning("Could not verify timestamp!") sys.stderr.flush() logging.debug("Running GnuPG binary: %r" % ([args.gpg_program] + args.gpgargs)) with subprocess.Popen([args.gpg_program] + args.gpgargs, stdin=subprocess.PIPE) as gpg_proc: gpg_proc.stdin.write(git_commit) gpg_proc.stdin.close()
def make_timestamp_from_block(digest, block, blockheight, *, max_tx_size=1000): state = make_trie(block) my_root = state.root_hash block_root = bytes.fromhex(block['transactionsRoot'][2:]) assert my_root == block_root try: j, prepend_tx, append_tx = found_tx(digest, block, max_tx_size) except ValueError: return None tx_raw = prepend_tx + digest + append_tx # print("tx_raw: " + tx_raw) # print("tx_hash: " + sha3.keccak_256(bytes.fromhex(tx_raw)).hexdigest()) rlp_encode = rlp.encode(j) # print("rlp_encode: " + bytes.hex(rlp_encode)) nibbles = trie.bin_to_nibbles(rlp_encode) current_node = state.root_node ops_list = [] nibble_iter = nibbles.__iter__() while True: node_type = state._get_node_type(current_node) # print("node type: " + str(node_type)) # print([bytes.hex(cur_el) for cur_el in current_node]) current_node_rlp = rlp.encode(current_node) current_node_encoded = bytes.hex(current_node_rlp) # print(current_node_encoded) try: index = next(nibble_iter) except: pass current_el = current_node[index if node_type == trie.NODE_TYPE_BRANCH else 1] current_el_hex = bytes.hex(current_el) # print(str(index) + ":" + current_el_hex) [prepend, append] = get_append_and_prepend(current_el_hex, current_node_encoded) ops_list.append(OpKECCAK256()) if len(append) > 0: ops_list.append(OpAppend(bytes.fromhex(append))) if len(prepend) > 0: ops_list.append(OpPrepend(bytes.fromhex(prepend))) if node_type == trie.NODE_TYPE_LEAF: break else: current_node = state._decode_to_node(current_el) assert tx_raw == prepend_tx + digest + append_tx orig = Timestamp(bytes.fromhex(digest)) current = orig if len(prepend_tx) > 0: current = current.ops.add(OpPrepend(bytes.fromhex(prepend_tx))) if len(append_tx) > 0: current = current.ops.add(OpAppend(bytes.fromhex(append_tx))) while len(ops_list) > 0: current = current.ops.add(ops_list.pop()) attestation = EthereumBlockHeaderAttestation(blockheight) current.attestations.add(attestation) return orig
def nonce_timestamp(private_timestamp, crypt_op=OpSHA256(), length=16): """Create a nonced version of a timestamp for privacy""" stamp2 = private_timestamp.ops.add(OpAppend(os.urandom(length))) return stamp2.ops.add(crypt_op)