All articles

Verify a blockchain timestamp in Python (10 lines)

Craig Solomon2 min read

You've got a file and a .proof.json claiming it was timestamped on a blockchain. Is the proof real? Here's how to verify it in Python. The proof was generated by ProofAnchor, a service that anchors SHA-256 hashes to the Polygon blockchain. The file itself never leaves the user's machine; only the hash is anchored.

Install the verification package

The verify-proof package handles the cryptographic verification for you. It works with ProofAnchor proofs and any OpenTimestamps-compatible proof format.

pip install verify-proof

The package gives you three functions: hash_file() to get a file's SHA-256 digest, load_proof() to read a proof file, and verify_proof() to check if they match.

The verification script

Here's the complete verification in 10 lines:

from verify_proof import hash_file, load_proof, verify_proof

# Hash the original file
file_hash = hash_file("document.pdf")

# Load the blockchain proof
proof = load_proof("document.pdf.proof.json")

# Verify they match
result = verify_proof(file_hash, proof)

print(f"Verified: {result['verified']}")
print(f"Transaction: {result.get('tx_id', 'None')}")

That's it. The verify_proof() function returns a dict with the verification result. If verified is True, the file hash matches the proof and the proof contains a transaction ID. If it's False, something doesn't match.

The proof file contains the expected hash, the blockchain transaction ID, and optionally a Merkle path if the proof was batched with other files. The verify_proof() function checks that your file's hash matches the hash in the proof, and that the proof structure is valid.

Handle missing proofs and errors

Real workflows need error handling. Here's a more robust version:

import os
from verify_proof import hash_file, load_proof, verify_proof

def verify_file_proof(file_path):
    proof_path = f"{file_path}.proof.json"
    
    if not os.path.exists(proof_path):
        return {"error": "No proof file found"}
    
    try:
        file_hash = hash_file(file_path)
        proof = load_proof(proof_path)
        result = verify_proof(file_hash, proof)
        
        if result['verified']:
            return {
                "status": "VERIFIED",
                "blockchain": result.get('blockchain', 'unknown'),
                "anchored_at": result.get('anchored_at'),
                "tx_id": result.get('tx_id')
            }
        else:
            return {
                "status": "FAILED", 
                "reason": result.get('error', 'Hash mismatch')
            }
    except Exception as e:
        return {"error": f"Verification failed: {str(e)}"}

# Test it
result = verify_file_proof("important-document.pdf")
print(result)

This version checks if the proof file exists, catches any exceptions during verification, and returns structured results you can use in larger applications.

Batch verification

If you have a folder full of files with matching proof files, you can verify them all:

import os
from pathlib import Path
from verify_proof import hash_file, load_proof, verify_proof

def verify_folder(folder_path):
    folder = Path(folder_path)
    results = []
    
    for file_path in folder.glob("*"):
        if file_path.suffix == ".json" or file_path.is_dir():
            continue
            
        proof_path = folder / f"{file_path.name}.proof.json"
        
        if proof_path.exists():
            try:
                file_hash = hash_file(str(file_path))
                proof = load_proof(str(proof_path))
                result = verify_proof(file_hash, proof)
                
                results.append({
                    "file": file_path.name,
                    "verified": result['verified'],
                    "tx_id": result.get('tx_id'),
                    "blockchain": result.get('blockchain')
                })
            except Exception as e:
                results.append({
                    "file": file_path.name, 
                    "error": str(e)
                })
    
    return results

# Verify everything in a folder
results = verify_folder("./documents")
verified_count = sum(1 for r in results if r.get('verified'))
print(f"Verified {verified_count}/{len(results)} files")

This scans a folder, finds files with matching .proof.json files, and verifies each pair. Useful for document archives or backup verification.

What's next

The verify-proof package handles the crypto for you, but verification is offline-only. It confirms the file matches the proof structure, but doesn't check if the transaction ID actually exists on-chain. For that, you'd query a blockchain explorer API separately.

Get the package at PyPI or check the source at GitHub. The package works with any proof format that includes a file hash and transaction reference.