What Signatrust provides
What Signatrust does not claim
- Correctness — a signed receipt does not prove the underlying decision was right.
- Fairness — cryptography cannot decide whether a decision was fair.
- Legal compliance — policy binding proves a reference, not lawfulness.
- Real-world completeness — coverage is declared by DBD/DEP, not by us.
Architecture at a glance
Customer Environment
↓ raw input/output stays local
Local Hashing (SHA-256 profile)
↓
Sector Schema
↓
Deployment Evidence Profile
↓
Decision or Action Event
↓
Evidence Composition
↓ input/output commitments · DBD · policy bindings
human-review commitment · attestations · metadata
Canonical Signed Body
↓ SHA-256 → receipt_hash
↓ Ed25519 → signature
Decision Receipt
↓
Ledger Epoch (append-only, epoch-anchored)
↓
Online Verification / Offline Verification
Trust Bundle · Historical Keys · Recovery Manifest
Detailed sections follow. Each system property in the status matrix declares whether it is IMPLEMENTED, DOCUMENTED, RESEARCH, or FUTURE — no hidden limitations.
1. Framing
Signatrust is an Evidence Architecture. It is not:
- an AI Governance platform
- an AI auditor
- an AI judge
- an AI correctness validator
- a fairness engine
- an explainability framework
- a legal certification system
The single research premise:
Can AI decisions be accompanied by cryptographically verifiable evidence that enables independent verification without requiring trust in the party that issued the receipt, and without requiring that party (Signatrust) to receive or retain the underlying raw decision content or direct subject identity?
Signatrust protects the evidence that describes a decision. It does not prove that the decision itself was correct, fair, lawful, complete, safe, or free from bias.
2. Zero-Data-Access, not Zero-Knowledge
We deliberately do not use the term Zero-Knowledge Architecture. "Zero-Knowledge" is a well-defined term in cryptography (ZKP) with a specific meaning that we do not implement.
The property Signatrust does provide is:
Signatrust is designed so that cryptographic evidence can be generated and verified without requiring Signatrust to receive or retain the underlying raw decision content or direct subject identity.
We call this Zero-Data-Access Evidence Architecture. The engineering objective is: verify without unnecessary disclosure.
3. End-to-end data flow
The target model (already implemented in the JavaScript and Python SDKs):
Customer Environment
│
│ raw input
│ raw output
│ subject / patient / customer identity
│ raw prompts, model output, PII, PHI, PAN, medical record
▼
Local Signatrust SDK
│
│ local SHA-256 hashing (hashLocally: true is the default)
▼
input_hash (sha256:<hex>)
output_hash (sha256:<hex>)
metadata required for evidence (business_event, risk_level, permissions)
optional scope_declaration (Decision Boundary Disclosure)
│
│ HTTPS → /api/v1/receipts
▼
Signatrust Evidence Service
│
│ RFC 8785–style deterministic canonicalization
│ receipt_hash = SHA-256(canonical(body))
│ Ed25519 signature over receipt_hash
│ chain linkage to previous_hash
▼
Decision Receipt (signed, chained)
│
▼
Receipt ID returned to customer
│
▼
Customer stores Receipt ID in their own system
alongside their internal Patient / Case / Transaction record.
The customer's internal system holds the mapping Subject → Receipt ID. Signatrust does not need — and by design does not receive — that mapping.
4. What Signatrust does not receive by default
Under the data-minimized default (SDK hashLocally: true), the following never leave the customer's environment:
- Raw model prompt / raw model output
- Patient name, medical record, diagnosis text
- Customer name (of the customer's own end-customer), phone, address
- Email addresses of decision subjects
- Banking details, PAN / card details
- Full application content (loan, insurance, employment)
- Personally identifying case content
What Signatrust does receive is limited to:
input_hashandoutput_hash(SHA-256 commitments)- Non-sensitive decision metadata:
business_event,risk_level,human_review(boolean), optionalhuman_review_attestation_hash(SHA-256 commitment to reviewer identity/specialty; the reviewer's actual name and role never travel to Signatrust),permissions,policies, optionalscope_declaration - Agent identity (the system that made the decision, not the subject of the decision)
- Model provider/name/version (if the customer chooses to disclose)
- Optional
metadatachosen by the customer (customer decides what to include)
Note. Any regulatory scope (GDPR, HIPAA, PCI-DSS, DNB) depends on the deployment and applicable legal context. Data-minimization is an engineering property of the receipt payload and not, on its own, a certification claim.
5. Local hashing contract
Local hashing is a first-class, documented pathway in both official SDKs.
- Algorithm: SHA-256 (FIPS 180-4).
- Encoding: UTF-8 bytes of the string content.
- Serialization: the caller passes a string; if the payload is a structured value the caller is responsible for producing a stable string encoding (typically
JSON.stringifywith fixed key ordering, or a canonicalizer). - Wire format: hashes are transmitted as
sha256:<lowercase-hex>(the prefix identifies the algorithm so future algorithm agility does not silently mis-verify). - Recomputation: feeding the same original content through the same SDK produces the same
sha256:<hex>. Recomputation later — even years later — must produce a byte-identical fingerprint to match the historical commitment.
SDK reference:
// TypeScript / JavaScript SDK
const str = new Signatrust({ apiKey: process.env.SIGNATRUST_API_KEY });
// hashLocally defaults to true — the following two lines do NOT send raw content
const receipt = await str.sign({
decision: {
type: 'loan_rejection',
input: sensitivePrompt,
output: sensitiveModelOutput,
business_event: 'CREDIT_DECISION',
risk_level: 'high',
},
});
// Also available: pre-computed hashes
const receipt2 = await str.sign({
decision: {
input_hash: Signatrust.fingerprint(sensitivePrompt),
output_hash: Signatrust.fingerprint(sensitiveModelOutput),
business_event: 'CREDIT_DECISION',
},
});
6. What a Receipt contains
The signed body of a Decision Receipt includes only:
version,id,type,sequence,timestampagent— the issuing system, not the subjectmodel— provider/name/version (optional)decision—input_hash,output_hash,business_event,risk_level,human_review,human_review_attestation_hash(optional),permissions,policiesscope_declaration— Decision Boundary Disclosure (optional, sector-schema-pinned)metadata— customer-chosen non-sensitive attributesprevious_hash— link into the append-only chain
Attached to (but not part of) the signable body:
receipt_hash— SHA-256 of the canonicalized bodysignature.algorithm—ed25519signature.public_key— base64 SPKI/DER of the Ed25519 verification key, embedded in the receipt for immediate self-contained verificationsignature.value— the Ed25519 signature overreceipt_hash
A separate signature.key_id field for explicit historical-resolution / rotation is on the research list — see LONG_TERM_VERIFICATION_AND_CRYPTO_AGILITY.md. Today the embedded public key already lets an offline verifier check the signature; long-term rotation and revocation are handled through the external trust bundle rather than a receipt-side identifier.
The SDK returns to the customer:
{
"receipt": { ... },
"verify_url": "https://signatrust.net/api/v1/receipts/STR-.../verify",
"share_url": "https://signatrust.net/verify?id=STR-..."
}
7. Storing Receipt References in Your Own System
Signatrust does not maintain a central patient / customer discovery index. The subject identity belongs to the customer's domain; the evidence identity belongs to the Signatrust evidence domain.
The recommended pattern for any sector — healthcare, credit, insurance, employment, government benefits, industrial safety — is symmetric:
Customer Internal System
──────────────────────────────────────────────
Internal Subject ID 84721
Case / Encounter ID E-2027-551
AI Decisions
receipt_id: STR-A1B2C3...
receipt_id: STR-D4E5F6...
receipt_id: STR-G7H8I9...
Do not send Patient 84721 to Signatrust merely to locate a Receipt later. The customer's own system is the discovery layer.
Sector examples (all follow the same pattern):
| Sector | Internal record | Field the customer stores the Receipt ID in |
|---|---|---|
| Healthcare | EHR encounter | encounter.ai_decisions[].receipt_id |
| Credit / lending | Loan application | application.credit_decision.receipt_id |
| Insurance | Claim file | claim.underwriting.receipt_id |
| Employment / HR | Candidate record | candidate.screening.receipt_id |
| Public benefits | Case record | case.benefit_decision.receipt_id |
| Industrial safety | Work order | work_order.ai_check.receipt_id |
| Payments / fraud | Transaction | tx.fraud_decision.receipt_id |
| Content moderation | Case | case.moderation.receipt_id |
Both SDKs ship with a small, dependency-free ReceiptReferenceStore helper that persists these rows locally with restrictive permissions and offers attach, findBySubject, findByCase, and findByReceiptId. It's optional — most customers plug the same fields into their existing record system — but it gives a working reference for the exact multi-year retrieval story: Storing Receipt References in Your Own System →
8. Discovery vs Verification
| Discovery | Verification | |
|---|---|---|
| Question | Which receipts belong to this subject / case? | Is this receipt cryptographically authentic and intact? |
| Responsibility | Customer or integration layer | Signatrust verifier (or any third party with the public key) |
| Data required | Customer's own record system | The receipt itself and the archived public key |
These functions are deliberately separated. Signatrust never merges them into a "receipt lookup by patient name" API.
9. Decision Boundary Disclosure (DBD)
DBD is an independent architectural feature that pins each receipt to a versioned sector schema and declares, per receipt:
domains_evaluated— the schema domains the system actually considereddomains_excluded— the schema domains the system did not consider, with a machine-readablereasonandexcluded_byclassification
The server enforces a hard union rule:
domains_evaluated ∪ domains_excluded = all domains defined by the referenced sector schema.
If any schema domain is present in neither list, the server refuses to sign. This eliminates silent omission: a developer must actively say not evaluated — they cannot leave a domain out and hope nobody notices.
DBD data is part of the signed envelope:
scope_declaration → canonicalization → receipt_hash → Ed25519 signature
Tampering with domains_excluded after signing breaks verification.
DBD does not prove:
- that every factor relevant in reality was considered — only every factor in this version of this schema was addressed;
- that the evaluation of any given domain was correct — only that the domain was reported to have been evaluated;
- that the sector schema itself is complete or fair — the schema is a living, versioned, human-authored artifact.
10. Integrity ≠ Correctness
The single most important boundary in this project:
Decision Integrity ≠ Decision Correctness.
Cryptographic verification of a Signatrust receipt can prove:
- the receipt was signed by the stated key,
- the signed body has not been altered since,
- the receipt is properly linked into the append-only chain.
It cannot prove that the underlying AI decision was:
- correct
- fair or unbiased
- lawful under a specific jurisdiction
- medically, financially, or ethically safe
- complete with respect to reality
The verification page makes this boundary explicit in the result panel.
11. Completeness (open research)
Hash chaining and signing prove that a given receipt has not been altered and is linked to its predecessors. They do not automatically prove that the issuing organization submitted every relevant decision — the receipts we can see are only the ones we were shown.
We treat selective omission / completeness verification as an open research question. It is not implemented and is not claimed as a property of the current system.
12. Long-term retention
A receipt carries what it needs for later verification: schema version, algorithm identifier (ed25519), signing public key, chain identifier, timestamp, receipt hash, signature, and previous hash. However, long-term verification also depends on infrastructure we have not yet productionised: an archived public-key registry, a key-rotation history, and versioned canonicalization profiles. We are aware of the dependency and are not claiming it is solved.
13. Architecture status matrix
Each capability is placed in exactly one status category. Categories are:
- IMPLEMENTED — present in production code and covered by tests;
- DOCUMENTED — designed and specified but not fully proven end-to-end;
- RESEARCH — open question or active study;
- FUTURE — on the roadmap, not started.
| Capability | Status | Location / notes |
|---|---|---|
| Decision Receipt format (v1.0) | IMPLEMENTED | ADR spec, src/ledger.ts, src/types.ts |
| Ed25519 signing (software keys) | IMPLEMENTED | src/crypto.ts, src/ledger.ts |
| Receipt verification (id + JSON + full-ledger) | IMPLEMENTED | /api/v1/receipts/:id/verify, /api/v1/verify, /api/v1/verify/ledger |
| Append-only tamper-evident hash chain | IMPLEMENTED | src/ledger.ts — previous_hash linkage, write-time enforcement of both previous_hash === head and monotonic sequence |
| Same-host multi-process ledger safety | IMPLEMENTED | src/ledgerLock.ts — deterministic cross-process advisory lock: each contender writes its payload ({pid, time}) to a per-process temp file, then fs.linkSync(temp, lockPath). link(2) on POSIX / CreateHardLinkW on NTFS both guarantee the target either does not exist or already contains the full payload — no observable empty-lock window (deterministic, not probabilistic). Stale-holder reclaim via PID probe or 30s TTL. Verified by scripts/multiprocess-concurrency-test.ts (100 seals across 4 processes on the production host). |
| Graceful shutdown on SIGTERM | IMPLEMENTED | New seals are refused with 503, in-flight seals drain, HTTP server closes, process exits cleanly. Systemd unit configured with KillMode=mixed, KillSignal=SIGTERM, TimeoutStopSec=15s. This closes the "SIGTERM mid-write during systemctl restart" pattern that is consistent with the historical break at sequence 730. |
| Combined chaos test — load + restart | IMPLEMENTED | scripts/chaos-restart-under-load.ts spawns an isolated instance (fresh SIGNATRUST_DATA_DIR, port 3001), fires a paced burst of seals, sends SIGTERM mid-burst simulating systemctl restart, respawns the server, and re-verifies. 5-of-5 clean runs on the production host: ledger intact, no duplicate sequences, no missing sequences, HTTP 200 count equal to test-added disk rows (503s during drain are retried and succeed). |
| Ledger filesystem hardening | IMPLEMENTED | Production ledger.jsonl is chmod 600 and set append-only at the filesystem layer (chattr +a); overwrite/truncate is refused even for root. Baseline hash + line count pinned in data/.integrity/ and exposed via GET /api/v1/verify/ledger/integrity. |
| Local hashing (SDK-side, on by default) | IMPLEMENTED | sdk/js/signatrust.ts, sdk/python/signatrust.py |
| Server-side hashing (convenience fallback) | IMPLEMENTED | Raw content is hashed then discarded — never stored in the receipt. |
| DBD — Decision Boundary Disclosure | IMPLEMENTED | src/dbd.ts, 8 sector schemas in /schemas |
| DBD union-rule enforcement | IMPLEMENTED | src/dbd.ts — silent omission is rejected |
| DBD signature coverage | IMPLEMENTED | scope_declaration is inside toBody() → signed |
| Sector schema registry | IMPLEMENTED | /api/v1/schemas, admin CRUD via /admin |
| Sector schema hash pinned in receipt | IMPLEMENTED | scope_declaration.sector_schema_hash |
| Data-minimized indicator on verify page | IMPLEMENTED | public/assets/verify.js — renderEvidenceMode |
| Verify UI: Integrity ≠ Correctness statement | IMPLEMENTED | Result panel on /verify |
| Trace / chain-of-custody per tool call | IMPLEMENTED | src/trace.ts, SDK trace() helper |
| Multi-sector reference examples | DOCUMENTED | examples/data-minimized/ |
| Archived public-key registry | IMPLEMENTED | scripts/export-trust-bundle.ts emits a signatrust-trust-bundle-v1 file — see the live export at /architecture-evidence/trust-bundle.json. Observed keys are reconstructed by scanning the append-only ledger; explicit rotation / revocation windows can be supplied via --key-history. The bundle is what the offline verifier anchors trust against, so multi-year re-verification does not depend on signatrust.net being reachable. |
| Canonicalization test suite vs RFC 8785 | DOCUMENTED | Project-defined deterministic canonicalization; formal RFC 8785 conformance suite is not yet published. |
| Hashing Profile v1 (reference module) | DOCUMENTED | src/hashingProfile.ts, HASHING_PROFILE_V1.md — profile fields are additive on the receipt (decision.input_profile, decision.output_profile); legacy receipts without a profile still verify but expose a "content re-verification not possible" indicator on the verify page. |
| Policy binding (historical policy pinning) | DOCUMENTED | POLICY_BINDING_SPEC.md — optional policy_bindings[] on the signed body; verifier semantics documented (PASS/FAIL/UNKNOWN); policy documents are customer-held, not stored by Signatrust. |
| Deployment Evidence Profile (DEP) — per-deployment specialisation of the sector schema | IMPLEMENTED | src/deploymentProfile.ts + additive fields on scope_declaration (deployment_profile_id, deployment_profile_hash); registry under profiles/; core domains cannot be silently downgraded; conditional / deployment_specific domains must be classified with a structured reason; coverage classification is evaluated against the pinned profile's applicable set rather than the raw sector schema. Full spec: DEPLOYMENT_EVIDENCE_PROFILE_SPEC.md. Backward compatibility is guaranteed: receipts without a profile pin canonicalise identically to legacy receipts and are validated by the original schema-only rule. |
| Offline reference verifier | IMPLEMENTED | scripts/verify-offline.mjs — zero-network Node script; verifies body integrity, Ed25519 signature, trust-bundle anchor, chain linkage against a supplied tail, content re-verification under the declared hashing profile, sector-schema pin, policy-binding hashes, and independent attestations. Full spec in OFFLINE_VERIFICATION_SPEC.md. |
| Reproducible micro-benchmark harness | IMPLEMENTED | scripts/bench-receipt.ts — measures canonicalize / SHA-256 / Ed25519-sign / append / pipeline / sustained / burst phases with commit-hash-pinned reports. Full plan reference: PERFORMANCE_BENCHMARK_PLAN.md. Live single-process run on the deployment host (AMD EPYC 7543P, 2 vCPU) is published as bench-sp-20260827T115640Z.json; same-host multi-process ceiling estimates: 2 workers and 4 workers. These are reference numbers, not a customer SLA. |
| Pilot readiness package | IMPLEMENTED | Self-contained kit for a 30-day evaluation: offline verifier + trust bundle + JS/Python SDK samples + bench reports + success-criteria template. Download: pilot-package.tar.gz. Base checklist: PILOT_READINESS_CHECKLIST.md. |
| Regression matrix runner | IMPLEMENTED | scripts/regression-matrix.ts — cryptographic tamper checks, hashing-profile invariants (Unicode NFC, JSON-order, salt), policy-binding hash checks, DBD schema arithmetic, Deployment Evidence Profile rules (core-domain integrity, structured-reason vocabulary, silent-omission guard, adequacy warnings, pin-hash mismatch), DEP backward-compat gates (legacy schema + legacy receipt → pre-DEP wording preserved byte-for-byte; conditional-tagged schema does not retroactively change legacy validation), and a language-vocabulary lint over public/. 30/30 PASS today. |
| Attestation model (independent vs issuer-asserted) | DOCUMENTED | Optional attestations[] on the signed body — spec in POLICY_BINDING_SPEC.md and the taxonomy note. Verify UI already distinguishes "Reported by issuer" from "Independently attested". |
| Computation-proofs extension point | RESEARCH | Optional computation_proofs[] on the receipt for external verifiable-computing / ZKP / TEE-attestation references. This verifier checks references only; proof-scheme soundness is out of scope. See VERIFIABLE_COMPUTING_EXTENSION_RESEARCH.md. |
| Receipt taxonomy (Evidence / Decision / Action / …) | RESEARCH | RECEIPT_TAXONOMY_RESEARCH_NOTE.md — no breaking rename planned; historical type: "decision_receipt" is preserved. |
| Long-term verification & crypto agility | RESEARCH | Trusted-time options (RFC 3161, transparency logs, signed checkpoints, public anchors), historical key model, hybrid signatures — LONG_TERM_VERIFICATION_AND_CRYPTO_AGILITY.md. |
| Governance interoperability (vendor-neutral) | DOCUMENTED | metadata.governance_refs pattern — customer-controlled references to policy/control/framework IDs. Signatrust does not decide compliance. See GOVERNANCE_INTEROP_NOTE.md. |
| Horizontal write scaling across hosts | RESEARCH | The advisory lock is same-host only. Multi-host write concurrency requires an external sequencer (e.g. Postgres advisory lock, Redis SETNX + fencing tokens, or etcd) — this is an open architectural item, not an implemented property of the current single-host deployment. |
| Automated / auditable deployment pipeline | RESEARCH | Production is deployed today via manual scp + systemctl restart. Source-of-truth Git history is now in place, but a reviewable CI-driven pipeline (with reproducible builds and per-deploy attestations) is an open operational item. |
| HSM signing | FUTURE | Software keys today; HSM is an enterprise-deployment option. |
| Post-quantum signatures (hybrid Ed25519 + PQ) | RESEARCH | Algorithm agility exists via the sha256: and ed25519 prefixes; migration path is not implemented. |
| Runtime attestation of the issuing environment | RESEARCH | |
| Central Evidence Discovery Index | RESEARCH / architectural | Not planned — discovery is a customer-side concern by design. |
| Completeness proof (no silent receipt omission) | RESEARCH | Open question. Not claimed as an implemented property. |
| Formal legal / regulatory certification (GDPR, HIPAA, PCI, DNB, EU AI Act) | RESEARCH / deployment-dependent | Regulatory scope depends on the specific deployment and applicable legal context; not claimed as an inherent property of the receipt. |
14. Open research questions
- Completeness verification. How does an external verifier detect selective omission of receipts by a cooperating issuer?
- Horizontal write scaling across hosts. The current write path is safe under concurrent processes on a single host via a filesystem advisory lock. Extending safe append across multiple hosts (each with its own writer) requires an external sequencer — a Postgres advisory lock, a Redis
SETNXpattern with fencing tokens, or a consensus system such as etcd/Raft. The right choice depends on the deployment's failure model and is deliberately deferred rather than implemented pre-maturely. - Long-term key resolution. How is a receipt signed under a key that has since been rotated verified five, ten, or twenty years later, without either party trusting a central registry unconditionally?
- Post-quantum migration. What is the transition strategy from Ed25519 to a hybrid or PQ-only signature envelope that preserves verifiability of receipts issued under legacy algorithms?
- Runtime attestation. How does a receipt bind to evidence that a specific model version, running on a specific execution environment, actually produced the output the hash covers?
- Sector-schema governance. Who authors and versions sector schemas so that coverage_classification: full carries external meaning across organisations?
- Canonicalization conformance. Formal test suite proving byte-for-byte agreement with RFC 8785 across all JSON edge cases (numeric edge cases, string escape edge cases, key ordering with Unicode code points).
These questions define our research agenda. They are deliberately not solved by adding claims to the marketing site.