# Copyright (c) 2026 Tiago Pinto # SPDX-License-Identifier: MIT # # Independent producer-side implementation of # draft-fassbender-scitt-time-anchor-03, written from the published # Internet-Draft alone. See README.md and CONSTRUCTION.md. """anchor_run.py: anchor one artifact (producer side, D.1 + D.3). Usage: python3 anchor_run.py [state.json] Computes SHA-256 of the file (whoever holds the artifact computes the digest; the anchoring service never receives the bytes, Section 1.3 AnchorDigest), registers the origin (D.1), aggregates a batch of one with blinding (D.3), and submits the root to the public OpenTimestamps calendars. Writes the pending proof to .ots and the state to state.json. Then: run upgrade.py periodically until promotion (hours). Inline comments below are in Portuguese, the implementer's working language. """ import hashlib, sys import anchor, calendar_client, upgrade CALENDARS = [ "https://alice.btc.calendar.opentimestamps.org", "https://bob.btc.calendar.opentimestamps.org", "https://finney.calendar.eternitywall.com", ] def main(): path = sys.argv[1] state_path = sys.argv[2] if len(sys.argv) > 2 else 'state.json' state = upgrade.load_state(state_path) with open(path, 'rb') as f: digest = hashlib.sha256(f.read()).digest() reg = anchor.construct_anchor("sha256", digest, "BATCH", state) print("origem registada:", reg['origin_id'], reg['hash_string']) origin = state['origin_attestations'][reg['origin_id']].copy() proofs = anchor.batch_anchor([origin], state, CALENDARS, calendar_client.submit) if not proofs: print("todas as submissões falharam; lote fica para retentar") sys.exit(1) oid, ots_bytes = proofs[0] # o storage do batch_anchor guarda bytes; converter para hex p/ JSON rec = state['core_ots_proofs'][oid] rec['ots_proof'] = ots_bytes.hex() if isinstance(rec['ots_proof'], bytes) else rec['ots_proof'] with open(path + '.ots', 'wb') as f: f.write(ots_bytes) upgrade.save_state(state, state_path) print(f"prova pendente: {path}.ots ({len(ots_bytes)} bytes, " f"SHA-256 {hashlib.sha256(ots_bytes).hexdigest()})") print("estado gravado em", state_path, "— correr upgrade.py até 'anchored' (inclusão + k>=6 demora horas)") if __name__ == '__main__': main()