Research prototype. Synthetic data and simulated payments only — not an official or production security service. Limitations

Developers

Integration guide

How an organisation makes its genuine messages verifiable, and how an app gates a sensitive action on that verification.

Architecture

  • Web app + API (Next.js on Vercel): consumer app, institution portal, public verification API.
  • PostgreSQL with row-level security: trust registry, receipts, cases, protected actions, hash-chained audit log. A trigger independently enforces the protected-action state machine.
  • Media service (Python, CPU): voice anti-spoofing model, transcription and C2PA validation/signing. Reachable only by the backend with a bearer token.

Tumaini authorisation receipts

A receipt is a compact JWS (RFC 7515) signed with Ed25519 (alg: EdDSA, typ: tumaini-receipt+jws, kid = issuer key id). The payload:

{
  "v": 1,
  "iss": "tumaini:issuer:falcon-demo-bank",
  "jti": "5b0c…",                       // unique id: revocation + single use
  "iat": 1794200000, "exp": 1794286400,  // max lifetime 30 days
  "aud": "tumaini:customer:TUM-4F2A9K",  // or "*" for public notices (never for payments)
  "purpose": "card_annual_fee",
  "scope": { "action": "payment",
             "payment": { "amount_minor": 15000, "currency": "AED",
                          "beneficiary_name": "Falcon Demo Bank — Card Services",
                          "beneficiary_account": "AE07 0331 2345 6789 0123 456" } },
  "content_sha256": "…"                  // SHA-256 of canonical {title, body}
}

content_sha256 is the SHA-256 of canonical JSON (sorted keys, NFC-normalised, trimmed) of { title, body }. It binds the signature to the exact words the recipient sees.

Verification order

  1. Format and size; header typ, kid; no crit.
  2. Algorithm must be EdDSA (prevents algorithm confusion).
  3. Issuer must exist in the trust registry and be active.
  4. Key must be registered to that issuer and not revoked.
  5. Ed25519 signature verification against the registered public key.
  6. Validity window (30 s clock tolerance; lifetime ≤ 30 days).
  7. Receipt not revoked by the issuer.
  8. Audience: issued to this recipient (payments are never broadcast).
  9. Content integrity: hash of the presented text matches.
  10. Scope: the intended action (type, amount, currency, beneficiary account) matches exactly.
  11. Single use: not already consumed by another action.

The first failing check sets the outcome; all checks are returned for explainability. The verifier never throws on untrusted input.

Outcomes

OutcomeMeaning
validAll checks passed for the supplied context.
malformedNot a well-formed v1 receipt, or lifetime out of bounds.
unsupported_algorithmAnything other than EdDSA.
unknown_issuer / suspended_issuerIssuer not in the registry, or suspended.
unknown_key / revoked_keyKey not registered to the issuer, or revoked.
invalid_signatureSignature does not verify (payload or signature altered, or wrong key).
expired / not_yet_validOutside the validity window.
revokedIssuer withdrew this receipt.
audience_mismatchIssued to someone else, or a payment receipt addressed to *.
content_mismatchText was altered after signing.
missing_scope / scope_mismatchDoes not authorise this kind of action / differs in amount, currency or account.
replayedAlready used to authorise an action.

Protecting an action

Create a protected action with POST /api/actions. Tumaini runs the risk policy, verifies any receipt against that exact payment, and moves the action to VERIFIED (valid in-scope receipt, consumed atomically) or HELD. From HELD, a trusted-contact challenge can move it through PENDING_VERIFICATION to VERIFIED. Only VERIFIED can become RELEASED, and the database re-checks the evidence on every transition.

CREATED → ASSESSING → HELD | VERIFIED
HELD → PENDING_VERIFICATION → VERIFIED | HELD (unreachable/expired) | CANCELLED (denied)
VERIFIED → RELEASED
any non-terminal → CANCELLED · held/pending/verified → EXPIRED

Security considerations

  • Keep issuer private keys in an HSM or KMS in production. The prototype encrypts them with AES-256-GCM under a server-held master key and destroys them on revocation.
  • Never put a verification phone number or link in the message itself — trusted contacts must be registered beforehand.
  • Treat model output and uploaded media as untrusted input. The risk policy is deterministic; AI can add caution only.
  • The demo trust registry is not an official UAE trust list. A production registry needs a governance body and an onboarding process.