MIR Assertions Documentation

Concepts, verification, hashing, and integration guide for cryptographic media provenance

Overview

MIR Assertions is a system for creating cryptographically-signed statements about media artifacts. Each assertion records who made a statement, not whether it's accurate.

Key Concepts

  • Artifact Hash — SHA-256 hash of the media file. Files are never uploaded; only the hash is recorded.
  • Issuer — An organization's identity that signs assertions. Tied to cryptographic keys.
  • Public Key — Registered with MIR. Used by anyone to verify signatures.
  • Private Key — Stays on your infrastructure. Never sent to MIR. Used to sign assertions.
  • Assertion — A signed statement about a media artifact (e.g., "We published this image").

What stays local vs. what goes to MIR

Your InfrastructureMIR
Media filesSHA-256 hashes only
Private keyPublic key
Signing happens hereSignature verification

Media files are never uploaded. You compute the SHA-256 hash locally and submit only the hash. This protects IP and scales to any file size.

How verification works

When anyone looks up an artifact hash on MIR, they see all assertions made about it. Each assertion includes:

  • The issuer's identity and verification status
  • The assertion type (ISSUED_BY, NOT_ISSUED_BY, DISPUTE, etc.)
  • A cryptographic signature that proves the issuer authorized the statement
  • Whether conflicting assertions exist from other issuers

MIR verifies that signatures are valid and that the signing key belongs to the claimed issuer. MIR does not verify whether the assertion is truthful.

Computing Artifact Hash

The artifact hash is a SHA-256 hash of your media file's raw bytes. Compute it locally — files are never uploaded to MIR.

Command Line

macOS / Linux:

shasum -a 256 your-file.jpg
# Output: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  your-file.jpg

Windows (PowerShell):

Get-FileHash -Algorithm SHA256 your-file.jpg | Select-Object -ExpandProperty Hash

Node.js

const crypto = require('crypto');
const fs = require('fs');

function hashFile(filepath) {
  const buffer = fs.readFileSync(filepath);
  return crypto.createHash('sha256').update(buffer).digest('hex');
}

const hash = hashFile('your-file.jpg');
console.log(hash); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Python

import hashlib

def hash_file(filepath):
    with open(filepath, 'rb') as f:
        return hashlib.sha256(f.read()).hexdigest()

hash = hash_file('your-file.jpg')
print(hash)  # e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Browser (JavaScript)

async function hashFile(file) {
  const buffer = await file.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// Usage with file input
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
  const hash = await hashFile(e.target.files[0]);
  console.log(hash);
});

Why hash-only? Your media never leaves your systems. MIR stores only the 64-character hash, protecting IP and scaling to any file size.

Private Key Storage

Your private key never goes to MIR. MIR only stores your public key. You sign assertions locally, then submit the signature. If someone intercepts your API traffic, they cannot forge signatures without your private key.

Where you store your private key depends on your setup:

  • Organizations with servers — Store on your server with restricted file permissions or a secrets manager (Vault, AWS Secrets Manager, etc.).
  • Creators with a computer — Store on your local machine. Sign assertions from there.
  • No server? — Use our Browser Signer to generate keys and sign directly in your browser. Keys are protected with biometrics or a passphrase.

Keep it secure — if compromised, revoke and rotate immediately via the Issuer Portal.

Never commit private keys to git. Add *.pem and .mir/ to your .gitignore.

Signing Model

Every assertion must include a cryptographic signature. This proves the issuer authorized the statement.

Supported Algorithms

AlgorithmKey TypeNotes
Ed25519EdDSARecommended. Fast, small keys, no configuration.
ES256ECDSA P-256Widely supported. Used by the Browser Signer (WebCrypto).

How it works

  1. Create a signed payload — JSON object with version, artifact hash, assertion type, issuer ID, and timestamp
  2. Sign with your private key — Produce a base64-encoded signature
  3. Submit both — MIR verifies the signature against your registered public key before recording

Signed Payload Structure

{
  "version": 1,
  "artifactHash": "e3b0c44298fc1c14...",
  "type": "ISSUED_BY",
  "issuerId": "your-issuer-id",
  "timestamp": "2025-01-15T12:00:00.000Z"
}
FieldRequiredDescription
versionRequiredMust be 1
artifactHashRequiredSHA-256 hash of the artifact
typeRequiredAssertion type (e.g., ISSUED_BY)
issuerIdRequiredYour issuer ID (found in the portal dashboard)
timestampRequiredISO 8601 timestamp, must be within 5 minutes of server time

Timestamps must be within 5 minutes of server time. This prevents replay attacks. Use ISO 8601 format.

Where do I find my Issuer ID? Log in to the Issuer Portal — your Issuer ID is shown at the top of the dashboard with a copy button.

No server? The Browser Signer handles key generation, signing, and submission entirely in your browser — no code needed.

Lookup Assertions

GET /assertions?hash={sha256_hash}

Look up all assertions for a given artifact hash. No authentication required.

Query Parameters

ParameterRequiredDescription
hash Required SHA-256 hash of the artifact (64-char hex)

Example

curl "https://mirassertions.org/assertions?hash=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

Response

{
  "artifactHash": "e3b0c44298fc1c14...",
  "assertions": [
    {
      "id": "assertion_xyz789",
      "type": "ISSUED_BY",
      "issuer": {
        "id": "issuer_abc123",
        "name": "News Organization",
        "status": "VERIFIED",
        "verified": true
      },
      "scope": null,
      "context": null,
      "createdAt": "2025-01-15T12:00:00.000Z",
      "revoked": false
    }
  ],
  "conflicts": false,
  "guidance": "MIR records who made each assertion. MIR does not verify content accuracy."
}

When conflicting assertions exist (e.g., ISSUED_BY and NOT_ISSUED_BY from different issuers, or a DISPUTE), the conflicts field is true and guidance is updated accordingly.

Batch Lookup

POST /assertions/lookup

Look up assertions for up to 100 artifact hashes in a single request. API key required.

Headers

HeaderRequiredDescription
x-api-key Required Your issuer API key

Request Body

FieldTypeDescription
hashes string[] Array of SHA-256 hashes (64-char hex). Max 100.

Example

curl -X POST "https://mirassertions.org/assertions/lookup" \
  -H "x-api-key: mir_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "hashes": [
      "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
    ]
  }'

Response

{
  "results": {
    "e3b0c44298fc1c14...": {
      "assertions": [ ... ],
      "hasConflicts": false,
      "guidance": "MIR records who made each assertion. MIR does not verify content accuracy."
    },
    "a1b2c3d4e5f6a1b2...": {
      "assertions": [],
      "hasConflicts": false,
      "guidance": "No assertions found for this artifact. Absence of assertions is not evidence of anything."
    }
  },
  "meta": {
    "hashesRequested": 2,
    "hashesQueried": 2
  }
}

Each hash in the results has the same shape as the single lookup response. Hashes with no assertions return an empty array. Duplicate hashes are deduplicated before querying.

Rate limit: 30 requests per minute (separate from the general rate limit).

Assertion Types

TypeMeaningExample Use
ISSUED_BY "We created/published this artifact" News org claiming authorship of a photo
NOT_ISSUED_BY "This artifact is NOT from us" Denying a fake image attributed to you
DISPUTE "We dispute an existing assertion on this artifact" Challenging another issuer's claim
ROLE_SCOPE "Our relationship to this artifact is..." Photographer vs publisher distinction
INTENT "The purpose of this artifact is..." Satire, parody, training data, marketing
METHOD "This artifact was created using..." AI-generated, human, hybrid

An issuer can have only one active assertion of each type per artifact hash. To change, revoke the existing assertion and create a new one, or use the supersede flow.

Recommended Metadata

When creating assertions, include metadata to make your assertion records human-readable and easier to manage. These fields are optional but strongly recommended.

FieldTypeRecommendation
displayName string (max 200) A friendly label. Defaults to filename if submitted via Browser Signer.
originalFilename string The source filename. Auto-captured by the Browser Signer.
artifactMimeType string Strongly recommended. e.g. image/jpeg, video/mp4, application/pdf
artifactByteSize integer Strongly recommended. File size in bytes.
note string (max 500) Internal note for your team. Not shown publicly.
tags string[] (max 10) Labels for organizing. e.g. ["press-release", "Q4", "official"]
context string (max 500) Public-facing context about the assertion.

The Browser Signer auto-captures originalFilename, artifactMimeType, artifactByteSize, and displayName from dropped files. For API integrations, include these fields in your POST body.

Metadata can be edited after creation via the Issuer Portal's "My Assertions" tab, or retroactively matched to files using the Match File helper.

Issuer Badges

Issuers are assigned badges based on their verification status:

StatusBadgeMeaning
VERIFIED Verified Domain ownership confirmed, identity validated
UNVERIFIED Unverified Registered but not yet verified. Can still publish assertions.
RESTRICTED Restricted Under review, limited capabilities
SUSPENDED Suspended Temporarily blocked from publishing

Verification is achieved by confirming domain ownership via DNS TXT record, or automatically after sustained assertion activity without disputes.

Error Codes

CodeMeaning
400Bad request — invalid input or missing required field
401Unauthorized — missing or invalid API key / session
402Payment required — active subscription needed to create assertions
403Forbidden — issuer suspended or action not allowed
404Not found — assertion or issuer doesn't exist
429Rate limited — too many requests
500Server error — retry or contact support

Error Response Format

{
  "error": "Description of what went wrong",
  "hint": "Optional guidance on how to fix it"
}

What MIR Does Not Prevent

MIR Assertions is not a system for determining truth, originality, or authenticity of media. It is a system for attribution and accountability.

Edited or Derivative Media

Anyone can modify a video, image, or audio file and create a new artifact with a new hash. MIR treats this as a new artifact with its own assertion history.

False or Misleading Claims

Issuers may publish assertions that are incorrect or dishonest. MIR records who made the claim, not whether it is accurate.

Competing or Conflicting Assertions

Multiple issuers may assert different claims about the same artifact. MIR preserves all assertions without adjudicating between them.

Content Misuse or Impersonation Attempts

MIR does not block impersonation attempts at creation time. It makes impersonation visible, attributable, and accountable after the fact.

Important: Absence of an assertion should never be interpreted as proof of authenticity or illegitimacy. MIR verifies signatures and attribution — not truth, intent, or content.

Repudiation Playbook

When an organization encounters a fake, altered, or impersonated video, speed and clarity matter more than takedowns alone. MIR provides a structured, auditable repudiation path.

Step 1: Identify the Artifact

  • Obtain the media file (video, audio, image)
  • Compute its SHA-256 hash locally
  • Confirm the exact artifact being circulated (re-encodes produce different hashes)

Step 2: Publish a NOT_ISSUED_BY Assertion

Create a signed assertion of type NOT_ISSUED_BY against the artifact hash. This establishes an official, cryptographically signed denial tied to your issuer identity.

Step 3: Add Context

Include concise, factual context:

  • "Impersonates our CFO"
  • "Fabricated video circulating on social media"
  • "No official communication was made via this channel"

Step 4: Share the Lookup Link

Provide the MIR lookup URL to stakeholders — finance teams, journalists, platforms, law enforcement. Anyone can independently verify: who denied the artifact, when, and under what authority.

Why This Works

  • Attackers can claim authorship — they cannot claim your authority
  • Repudiation is fast, public, and attributable
  • History is preserved; nothing is silently erased
  • MIR never becomes the arbiter — organizations speak for themselves

Key principle: MIR prevents silent impersonation, not dishonest speech.

Sharing with Your Audience

Hash-based verification only works when your audience can access the original file or knows the hash. Here's how to make verification accessible.

Platform Re-encoding

Platforms like YouTube, Vimeo, and social media re-encode uploaded media. This changes the file bytes, so the re-encoded version won't hash-match your original. However, the assertion still exists in MIR — include the hash, verification link, or QR code alongside your posts so viewers can verify via MIR lookup.

Re-encoding changes the hash, not the assertion. Your assertion is permanent. Include the hash in your caption or description so viewers can look it up directly.

Publish the Hash

Include the assertion hash in places your audience can see it:

Video Descriptions

---
MIR Assertion Hash: e3b0c44298fc1c149afbf4c8996fb924...
Verify at: https://mirassertions.org/assertions?hash=e3b0c44298fc1c14...
---

Website or Blog Posts

  • Below the video player
  • In an "About this content" section
  • In article metadata

Embedding a Badge Overlay

Add a clickable MIR badge to images on your website. The badge links to the assertion details on MIR:

<script src="https://mirassertions.org/js/mir-badge-overlay.js"></script>
<img src="your-image.jpg" data-mir-badge="YOUR_HASH_HERE" />

Hash Matching Reference

Hash matches (byte-for-byte) Hash won't match (assertion still verifiable via link)
Original files downloaded directly from youRe-encoded video from YouTube/Vimeo/TikTok
Audio files in original formatTranscoded audio from streaming platforms
Images shared without platform compressionScreenshots or screen recordings
PDFs and documents shared as-isContent cropped, resized, or filtered

Supported Media Types

MIR assertions work with any file type — the hash is computed from raw file bytes: video, audio, images, documents, archives, code, data files.

Badge Overlay Widget

Overlay a small clickable MIR badge directly on images and videos on your website. When a visitor clicks the badge, they see assertion details. The badge only appears if an assertion exists for the artifact.

Setup

<script src="https://mirassertions.org/js/mir-badge-overlay.js"></script>

Images

<!-- Explicit hash (recommended) -->
<img src="photo.jpg" data-mir-badge="YOUR_HASH_HERE" />

<!-- Auto-hash (same-origin images only) -->
<img src="photo.jpg" data-mir-badge />

Video

<video src="video.mp4" data-mir-badge="YOUR_HASH_HERE" controls></video>

Video requires an explicit hash — auto-hashing is not supported for video files (too large to hash in the browser).

Customization

AttributeDefaultDescription
data-mir-positionbottom-rightbottom-right, bottom-left, top-right, top-left
data-mir-size48Badge size in pixels
data-mir-opacity0.9Overlay opacity (0–1)

Full Example

<img src="https://example.com/photo.jpg"
     data-mir-badge="a1b2c3d4e5f6..."
     data-mir-position="top-left"
     data-mir-size="36"
     data-mir-opacity="0.8" />

Full API Reference

Endpoint details for creating, revoking, and superseding assertions, key management, team invites, and more.

Sign in to Issuer Portal →