Trust Model
Deep dive on how trust propagates through the VDI protocol: from attestations to receipts to verifier sets to transparency logs.
Trust Architecture Overview
┌─────────────────────────────────────────────────────┐
│ Trust Layers │
├─────────────────────────────────────────────────────┤
│ Layer 5: Transparency Log (equivocation detection) │
│ Layer 4: Verifier Lifecycle (key rotation/revoke) │
│ Layer 3: Trusted Verifier Sets (k-of-n quorum) │
│ Layer 2: Verification Receipts (trust propagation) │
│ Layer 1: Verification Profiles (check semantics) │
│ Layer 0: Decision Attestation (ZK proof + sig) │
├─────────────────────────────────────────────────────┤
│ Foundation: Groth16 + Ed25519 (math) │
└─────────────────────────────────────────────────────┘Each layer builds on the one below. The foundation is pure mathematics.
Layer 0: Decision Attestations
An attestation is a cryptographic proof that a decision followed rules. It contains:
- A Groth16 ZK proof that the execution satisfied all constraints
- An Ed25519 signature over the canonical JSON payload
- An embedded verification key so anyone can verify without external lookup
- A pipeline hash proving the exact process that was executed
- A manifest hash proving which constraints were applied
Trust guarantee: The attestation is valid if and only if the math checks out. No trust in QuantZK or any third party required.
Layer 1: Verification Profiles
Profiles standardize what "verified" means. Without profiles, two verifiers might run different checks and both claim the attestation is "verified."
Built-in Profiles
import { PROFILES } from '@quantzk/attest';
// Strict: all 7 checks, requires formal authority
PROFILES.VDI_VERIFY_STRICT_V1
// → checks: ['schema', 'timestamps', 'pipeline_integrity', 'policy_integrity', 'zk_proof', 'signature', 'key_integrity']
// → accepted_authority_types: ['legal_review', 'standards_body', 'audit_firm']
// Standard: all 7 checks, any authority
PROFILES.VDI_VERIFY_STANDARD_V1
// Minimal: just schema, timestamps, and ZK proof
PROFILES.VDI_VERIFY_MINIMAL_V1When a verifier emits a receipt, the profile ID and hash are recorded:
receipt.verification_profile // 'VDI_VERIFY_STRICT_V1'
receipt.profile_hash // '0x...', SHA-256 of profile definitionThis lets downstream consumers know exactly which checks were performed and refuse receipts that don't meet their requirements.
Layer 2: Verification Receipts
A receipt is a signed proof-of-verification. It enables trust propagation, one agent verifies the ZK proof, and downstream agents accept the receipt instead of re-verifying.
Receipt Lifecycle
Attestation ──► Verifier B ──► Receipt ──► Agent C (accepts receipt)
│
└──► Agent D (accepts receipt)
└──► Agent E (accepts receipt)Creating a Receipt
import { verifyAndReceipt } from '@quantzk/attest';
const { verification, receipt } = await verifyAndReceipt(attestation, {
signingKey: myPrivateKey,
verifierId: 'vdi:verifier:compliance-bot',
profileId: 'VDI_VERIFY_STRICT_V1'
});What a Receipt Contains
- attestation_hash, SHA-256 binding to the original attestation
- verifier, Who verified (ID, implementation, version)
- verification_profile, Which checks were run
- result, Pass/fail with per-check breakdown
- signature, Ed25519 signature by the verifier
- expires_at, 24-hour default TTL
Accepting a Receipt
import { verifyReceipt } from '@quantzk/attest';
const result = await verifyReceipt(receipt, {
attestation: originalAttestation, // verify hash binding
trustedVerifiers: ['vdi:verifier:compliance-bot'] // trust check
});
// result.valid === true
// result.checks: [expiry, attestation_binding, trusted_verifier, receipt_signature]Receipt Chaining
Receipts can reference parent receipts, creating verifiable chains:
const { receipt: receiptC } = await verifyAndReceipt(attestation, {
signingKey: agentCKey,
verifierId: 'vdi:verifier:risk-monitor',
parentReceiptHash: '0x' + sha256(JSON.stringify(receiptB)),
chainDepth: 1
});
// receiptC.parent_receipt_hash === hash of receiptB
// receiptC.chain_depth === 1This establishes causal ordering of verifications.
Layer 3: Trusted Verifier Sets (TVS)
A TVS defines which verifiers are trusted and what quorum is required to accept a set of receipts.
Defining a TVS
const tvs = {
tvs_id: 'vdi:tvs:acme-production',
name: 'ACME Corp Production Verifier Set',
verifiers: [
{ verifier_id: 'vdi:verifier:compliance-bot', name: 'Internal Compliance', trust_level: 'primary' },
{ verifier_id: 'vdi:verifier:auditco-bot', name: 'External Auditor', trust_level: 'secondary' },
{ verifier_id: 'vdi:verifier:risk-monitor', name: 'Risk Monitor', trust_level: 'secondary' }
]
};Acceptance Policies
import { evaluateAcceptancePolicy } from '@quantzk/attest';
// Low: any 1 trusted receipt
const low = await evaluateAcceptancePolicy(receipts, { level: 'low', tvs });
// Medium: 1 primary OR 2 secondary
const medium = await evaluateAcceptancePolicy(receipts, { level: 'medium', tvs });
// High: 2+ independent verifiers
const high = await evaluateAcceptancePolicy(receipts, { level: 'high', tvs });
// Critical: 2+ independent + probabilistic spot-check (re-runs ZK proof)
const critical = await evaluateAcceptancePolicy(receipts, {
level: 'critical',
tvs,
spotCheckRate: 0.05 // 5% chance of re-verification
}, attestation);Spot-Check Enforcement
At the critical level, the policy randomly re-runs the full ZK verification to catch fraudulent receipts:
// If spot-check triggers and fails:
// { accepted: false, reason: 'Spot-check FAILED, receipts may be fraudulent' }
// If spot-check triggers and passes:
// { accepted: true, reason: '2 independent verifiers + spot-check PASSED' }The spot-check rate is configurable. Even a low rate (1-5%) creates a strong deterrent because verifiers cannot predict when they'll be checked.
Layer 4: Verifier Key Lifecycle
The verifier registry manages identity and key lifecycle.
Registration
import { VerifierRegistry } from '@quantzk/attest';
const registry = new VerifierRegistry();
registry.register({
verifierId: 'vdi:verifier:compliance-bot',
name: 'ACME Compliance Verifier',
publicKey: '0x...',
organization: 'ACME Corp',
capabilities: ['full_verification']
});Key Rotation
Keys can be rotated with a grace period where both old and new keys are valid:
const rotation = registry.rotateKey('vdi:verifier:compliance-bot', newPublicKey, 86400);
// → { new_key_version: 2, grace_period_seconds: 86400 }
// During grace period:
registry.validateKey(verifierId, oldKey); // { valid: true, status: 'grace_period' }
registry.validateKey(verifierId, newKey); // { valid: true, status: 'active' }Revocation
Verifiers can be revoked (e.g., after equivocation detection):
registry.revoke('vdi:verifier:rogue-bot', 'Equivocation detected');
registry.isRevoked('vdi:verifier:rogue-bot'); // true
registry.validateKey('vdi:verifier:rogue-bot', anyKey); // { valid: false }Layer 5: Transparency Log
The transparency log is a Merkle-tree-based append-only log, modeled after Certificate Transparency (RFC 6962).
Why It Exists
Without a transparency log, a malicious verifier could:
- Issue a PASS receipt to Agent C
- Issue a FAIL receipt to Agent D
- Neither agent would know the other received a contradictory receipt
The transparency log makes this detectable.
Appending Receipts
import { TransparencyLog } from '@quantzk/attest';
const log = new TransparencyLog();
const entry = log.append(receipt);
// entry.log_index === 0
// entry.tree_root === '0x...' (Merkle root)
// entry.equivocation_detected === falseInclusion Proofs
Prove a receipt exists in the log:
const proof = log.getInclusionProof(entry.log_index);
const valid = log.verifyInclusionProof(proof);
// valid === trueEquivocation Detection
When a verifier issues contradictory receipts, the log detects it:
// Verifier D issues PASS, then FAIL for the same attestation
log.append(passReceipt); // equivocation_detected: false
log.append(failReceipt); // equivocation_detected: true
const check = log.checkEquivocation(attestation.attestation_id);
// check.clean === false
// check.equivocations[0].verifier_id === 'vdi:verifier:rogue-bot'Response to Equivocation
- Detect equivocation via transparency log
- Revoke the verifier in the registry
- All receipts from that verifier become invalid
- Downstream agents reject those receipts
Trust Scoring
The scoreReceiptSet() function provides a quantitative trust assessment:
import { scoreReceiptSet } from '@quantzk/attest';
const score = scoreReceiptSet([receiptB, receiptC]);
// {
// total_receipts: 2,
// valid_receipts: 2,
// unique_verifiers: 2,
// unique_profiles: 2,
// all_valid: true,
// includes_zk_verification: true,
// trust_score: 100, // 0-100
// recommendation: 'high_confidence'
// }Scoring Formula
- 25 points per unique verifier (up to 75)
- 25 points if at least one receipt includes ZK proof verification
- 25 points if all receipts are valid
Recommendation Thresholds
| Score Range | Recommendation |
|---|---|
| 75+ with ZK verify | high_confidence |
| 50-74 | medium_confidence |
| < 50 | low_confidence |
End-to-End Trust Flow
1. Decision Made
└─► VDI Prover generates attestation with Groth16 proof
2. Primary Verification
└─► Verifier B runs 7-step verification (strict profile)
└─► Emits signed receipt
└─► Receipt appended to transparency log
└─► Inclusion proof generated
3. Secondary Verification
└─► Verifier C runs 7-step verification (standard profile)
└─► Emits signed receipt (chained to B)
└─► Receipt appended to transparency log
4. Trust Evaluation
└─► Agent D evaluates receipt set against TVS
└─► Acceptance policy: 2 independent verifiers ✅
└─► Spot-check: probabilistic ZK re-verification
└─► Trust score: 100/100, high_confidence
5. Trust Propagation
└─► Agent E accepts D's evaluation
└─► No ZK re-verification needed
└─► ~2ms per receipt check
6. Continuous Monitoring
└─► Transparency log monitors for equivocation
└─► Key rotation on schedule
└─► Revocation if malfeasance detected