Beta Release of TrackOrigin is live. We are still running verifications throughout June.
INDEPENDENT VERIFICATION · TO-1.0

Verify a
certificate.

Every TrackOrigin certificate is a signed JSON manifest. The signature can be verified independently using the published Ed25519 public key — without trusting trackorigin.io. This page documents exactly how.

SIGNATURE
Ed25519
CANONICALIZATION
sort_keys · UTF-8
DEPENDENCIES
zero required
§01

What a valid signature proves.

Verifying a TrackOrigin signature with the public key below confirms two things:

  • Authenticity. The manifest was signed by the holder of the TrackOrigin issuer private key. It was not produced by anyone else.
  • Integrity. The manifest content has not been modified since signing. A single byte change anywhere in the manifest produces an invalid signature.
[ IMPORTANT — WHAT IT DOES NOT PROVE ]

The certificate is bound to a specific audio file.

A valid signature does not prove the master file you have in front of you matches the certificate. To check that, compute the SHA-256 of your audio file and compare it to the master.sha256 field inside the manifest. The certificate is only valid for the exact master hash recorded in it.

§02

Inputs.

Three public endpoints. No authentication. Open from any origin.

01 · Certificate manifest
Returns the signed manifest as JSON. The signature field is the Ed25519 signature; all other fields are the canonicalized body.
02 · Public signing key (PEM)
Ed25519 public key in PEM format. Load directly into any crypto library.
03 · Public key metadata (JSON)
PEM plus key_id, algorithm, and the canonicalization rule used for signing.
§03

Canonicalization.

Before signing, the manifest is serialized to a canonical byte string. Verifiers must produce the same bytes to verify the signature. TrackOrigin uses Python's json.dumps with three settings, applied recursively to the manifest dict with the signature field removed:

canonicalization · python reference
json.dumps(
    manifest_without_signature,
    ensure_ascii=False,    # Unicode is passed through, not escaped to \uXXXX
    sort_keys=True,        # Keys sorted lexicographically at every nesting level
    separators=(",", ":"), # No whitespace between tokens
).encode("utf-8")

This is similar to but not identical to RFC 8785 JCS. The notable differences are number formatting (Python uses its native repr; JCS uses ECMAScript Number.prototype.toString) and some Unicode edge cases. For all manifests TrackOrigin issues today, the two outputs are byte-identical — but if you're implementing a generic verifier, treat the Python form above as the reference.

§04

Verifier implementations.

Three reference paths. Pick the one that matches your stack. All three perform the same four steps: fetch the manifest, fetch the public key, separate the signature, verify.

Requires cryptography and requests (pip install cryptography requests).

python · cryptography + requests
import base64
import json
import requests
from cryptography.hazmat.primitives import serialization
from cryptography.exceptions import InvalidSignature

CERT_ID = "cer_01KS9QWHV7PHETYGQAYMHB3DM6"  # replace with the cert you're verifying
BASE = "https://trackorigin.io"

def canonicalize(obj):
    """Match the server's signing canonicalization exactly."""
    return json.dumps(
        obj,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
    ).encode("utf-8")

# 1. Fetch the certificate manifest
cert = requests.get(f"{BASE}/v1/public/certificates/{CERT_ID}").json()

# 2. Fetch the public signing key
pem = requests.get(f"{BASE}/.well-known/trackorigin-public-key").text
public_key = serialization.load_pem_public_key(pem.encode())

# 3. Separate the signature from the signed body
signature = base64.b64decode(cert.pop("signature"))
canonical = canonicalize(cert)

# 4. Verify
try:
    public_key.verify(signature, canonical)
    print(f"✓ Signature valid for {CERT_ID}")
    print(f"  Verdict: {cert.get('verdict')}")
    print(f"  Master SHA-256: {cert.get('master', {}).get('sha256')}")
except InvalidSignature:
    print(f"✗ Signature INVALID for {CERT_ID}")

Requires Node 16+ (uses built-in crypto, no extra dependencies). Note the recursive key sort — JSON.stringify does not sort keys by default.

node.js · built-in crypto
const crypto = require('crypto');

const CERT_ID = 'cer_01KS9QWHV7PHETYGQAYMHB3DM6'; // replace with the cert you're verifying
const BASE = 'https://trackorigin.io';

function sortKeysDeep(value) {
  if (Array.isArray(value)) {
    return value.map(sortKeysDeep);
  }
  if (value && typeof value === 'object') {
    return Object.keys(value)
      .sort()
      .reduce((acc, key) => {
        acc[key] = sortKeysDeep(value[key]);
        return acc;
      }, {});
  }
  return value;
}

function canonicalize(obj) {
  // JSON.stringify with no spaces, applied to a deep-sorted clone.
  // Mirrors Python's json.dumps(..., sort_keys=True, separators=(',', ':')).
  return Buffer.from(JSON.stringify(sortKeysDeep(obj)), 'utf-8');
}

(async () => {
  const cert = await fetch(`${BASE}/v1/public/certificates/${CERT_ID}`).then(r => r.json());
  const pem  = await fetch(`${BASE}/.well-known/trackorigin-public-key`).then(r => r.text());

  const publicKey = crypto.createPublicKey(pem);
  const signature = Buffer.from(cert.signature, 'base64');

  const { signature: _, ...body } = cert;
  const canonical = canonicalize(body);

  const ok = crypto.verify(null, canonical, publicKey, signature);
  if (ok) {
    console.log(`✓ Signature valid for ${CERT_ID}`);
    console.log(`  Verdict: ${cert.verdict}`);
    console.log(`  Master SHA-256: ${cert.master && cert.master.sha256}`);
  } else {
    console.log(`✗ Signature INVALID for ${CERT_ID}`);
  }
})();

The no-dependencies path. Requires curl, openssl 1.1.1+ (for Ed25519 support), and jq for JSON manipulation. The trickiest part is the canonicalization — jq -cS sorts keys recursively and compacts whitespace, which matches the Python form.

bash · curl + jq + openssl
#!/usr/bin/env bash
set -euo pipefail

CERT_ID="cer_01KS9QWHV7PHETYGQAYMHB3DM6"
BASE="https://trackorigin.io"

# 1. Fetch the public key
curl -fsSL "$BASE/.well-known/trackorigin-public-key" -o pubkey.pem

# 2. Fetch the certificate manifest, split signature from body
CERT_JSON="$(curl -fsSL "$BASE/v1/public/certificates/$CERT_ID")"

# Extract the signature (base64) and decode to raw bytes
echo "$CERT_JSON" | jq -r '.signature' | base64 -d > signature.bin

# Canonicalize the body: sort keys recursively, compact, drop signature field
echo "$CERT_JSON" | jq -cS 'del(.signature)' | tr -d '\n' > canonical.json

# 3. Verify with openssl
if openssl pkeyutl -verify \
    -pubin -inkey pubkey.pem \
    -rawin -in canonical.json \
    -sigfile signature.bin > /dev/null 2>&1; then
  echo "✓ Signature valid for $CERT_ID"
else
  echo "✗ Signature INVALID for $CERT_ID"
  exit 1
fi
[ NOTE — JQ -CS CAVEAT ]

Unicode edge cases.

jq -cS uses lexicographic key sort and compact output, which matches Python's sort_keys=True, separators=(",",":") for ASCII-only manifests. For manifests containing certain Unicode characters in field values, jq and Python may differ on escaping — in those cases use the Python or Node.js verifiers above for guaranteed byte-identical canonicalization.

§05

If verification fails.

A failed verification means one of three things:

  • The certificate is forged. Someone produced a manifest claiming to be a TrackOrigin certificate without access to the signing key. Treat the document as invalid and report it to support@trackorigin.io.
  • The manifest has been modified. A single byte change anywhere in the JSON body invalidates the signature. Make sure you're verifying the raw response from /v1/public/certificates/{cert_id}, not a re-serialized copy.
  • Canonicalization mismatch. Your verifier produced different bytes than the signer. Compare your canonical output to the Python reference above and look for whitespace, key order, or Unicode escaping differences.
[ NO TRUST REQUIRED ]

Cryptographic proof,
not corporate trust.

You don't have to take TrackOrigin's word for anything. Every certificate verifies against a published Ed25519 public key with three lines of code — or one shell pipeline. That's the point of the Music Provenance Standard.

TO Music Provenance Standard · TO-1.0 Public key Key metadata