TectraTectra
Blockchain

Blockchain & Smart Contract

Every Tectra-signed image is eventually anchored on the Polygon blockchain via a Merkle tree batch. This creates a permanent, tamper-proof, independently verifiable record of provenance.

Why Polygon?

EVM-compatible

Standard Solidity smart contracts. Auditable by any Ethereum developer.

Low cost

Transaction fees are fractions of a cent, enabling affordable batch anchoring.

Immutable

Once written, records cannot be altered or deleted.

Independent

Anyone can query the contract directly - no Tectra servers required.

Merkle Batch Anchoring

Individual blockchain transactions per image would be expensive. Instead, Tectra batches thousands of image hashes into a single Merkle tree and anchors only the root hash on-chain. Every image still gets a verifiable on-chain proof.

Images hashed this batch:
  hash_A = sha256(image_1)
  hash_B = sha256(image_2)
  hash_C = sha256(image_3)
  hash_D = sha256(image_4)

Merkle tree:
            root
           /    \
       AB_hash  CD_hash
       /    \   /    \
   hash_A  hash_B  hash_C  hash_D

On-chain: registerBatch(root, 4, signer_pubkey, timestamp)

Proof for image_1:
  [ hash_B, CD_hash ]   ← sibling nodes up to root
  
Verification: hash(hash(hash_A, hash_B), CD_hash) == root

Each content record stores its Merkle proof path in PostgreSQL. During verification, the proof is re-computed against the on-chain root - fully trustless.

Smart Contract: ProvenanceRegistry.sol

The contract is deployed on Polygon (Amoy testnet by default). It stores two types of records:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract ProvenanceRegistry {
    
    struct ContentRecord {
        bytes32 contentHash;
        bytes32 perceptualHash;
        bytes   signerPubKey;
        uint256 timestamp;
        address registeredBy;
    }
    
    struct BatchRecord {
        bytes32 merkleRoot;
        uint256 leafCount;
        bytes   signerPubKey;
        uint256 timestamp;
        address registeredBy;
    }
    
    mapping(bytes32 => ContentRecord) public contentByHash;
    mapping(bytes32 => ContentRecord) public contentByPerceptualHash;
    mapping(bytes32 => BatchRecord)   public batches;
    
    event ContentRegistered(
        bytes32 indexed contentHash,
        bytes   signerPubKey,
        uint256 timestamp
    );
    
    event BatchRegistered(
        bytes32 indexed merkleRoot,
        uint256 leafCount,
        bytes   signerPubKey,
        uint256 timestamp
    );
    
    // Single content registration (legacy)
    function registerContent(
        bytes32 contentHash,
        bytes32 perceptualHash,
        bytes calldata signerPubKey,
        uint256 timestamp
    ) external { ... }
    
    // Batch registration (Merkle root)
    function registerBatch(
        bytes32 merkleRoot,
        uint256 leafCount,
        bytes calldata signerPubKey,
        uint256 timestamp
    ) external { ... }
    
    // Read functions - no auth required
    function getByContentHash(bytes32 h) external view returns (ContentRecord memory) { ... }
    function getByPerceptualHash(bytes32 h) external view returns (ContentRecord memory) { ... }
    function getBatch(bytes32 root) external view returns (BatchRecord memory) { ... }
}

Verify On-Chain Independently

You can verify any record directly on Polygon - no Tectra servers needed:

python
from web3 import Web3
import json

# Connect to Polygon
w3 = Web3(Web3.HTTPProvider("https://polygon-rpc.com"))

# Load contract ABI
with open("ProvenanceRegistry_abi.json") as f:
    abi = json.load(f)

contract = w3.eth.contract(
    address="0xYOUR_CONTRACT_ADDRESS",
    abi=abi,
)

# Look up by content hash
import hashlib
with open("image.jpg", "rb") as f:
    content_hash = hashlib.sha256(f.read()).hexdigest()

record = contract.functions.getByContentHash(
    bytes.fromhex(content_hash)
).call()

print(f"Timestamp: {record['timestamp']}")
print(f"Signer: {record['signerPubKey'].hex()}")
bash
# Or via PolygonScan API
curl "https://api.polygonscan.com/api?module=contract&action=call&  to=0xCONTRACT&data=0xGETBYHASH_CALLDATA&apikey=YourApiKey"

Deploy Your Own Contract

To deploy on mainnet Polygon or a private chain:

bash
# From the backend directory
cd backend
source venv/bin/activate

# Set your deployer wallet
export DEPLOYER_PRIVATE_KEY="0x..."
export POLYGON_RPC_URL="https://polygon-rpc.com"  # mainnet
# or: https://rpc-amoy.polygon.technology  (testnet)

# Deploy
PYTHONPATH=. python -m app.contracts.deploy

# Output:
# Deploying ProvenanceRegistry...
# Contract deployed at: 0x...
# TX hash: 0x...
# Add CONTRACT_ADDRESS=0x... to your .env

You need testnet MATIC for Amoy, or mainnet MATIC for Polygon mainnet. Get testnet MATIC from the Polygon Faucet.

Blockchain Transaction Status

After signing, the blockchain_status field progresses through states:

pending

Record is in the Redis batch queue, awaiting the next Celery flush (~10 seconds).

anchored

Merkle batch was submitted to Polygon. TX hash is recorded in the database.

confirmed

Transaction received sufficient block confirmations on Polygon.

Next: Verification Guide

Understanding confidence scores and the 4-check verification system.

Verification Guide