Skip to content

Evidence in Harbour Credentials

Evidence is a W3C VC Data Model concept that provides cryptographic proof of how an issuer verified claims or why a holder is authorized to perform an action.

What is Evidence?

When a credential is issued or a presentation is made, the evidence field can contain supporting proof that:

  1. For issuance: Shows what the issuer relied upon to verify claims
  2. For presentations: Shows why the holder is authorized to perform an action

Evidence creates an audit trail — allowing third parties to verify not just that something happened, but how it was validated.

Harbour Evidence Types

CredentialEvidence

Proves that an authorizing party approved the credential issuance via OID4VP. The embedded VP carries the authorization proof — a Verifiable Presentation containing the authorizer's credential.

The Harbour Signing Service is the sole issuer of all credentials. Evidence VPs establish the chain of authorization:

Use case 1 — Trust Anchor authorizes org (LegalPersonCredential): The Trust Anchor presents a VP containing its self-signed LinkedCredentialService credential (service endpoint proof, root of trust — analogous to a root CA certificate). The Signing Service verifies this VP and issues the org's credential with it as evidence.

Use case 2 — Org authorizes employee (NaturalPersonCredential): The organization presents a VP containing its LegalPersonCredential (SD-JWT with sensitive fields redacted — registration number and addresses hidden, compliance status disclosed). The Signing Service verifies this VP and issues the employee's credential with it as evidence.

{
  "type": "harbour:CredentialEvidence",
  "verifiablePresentation": {
    "@context": ["https://www.w3.org/ns/credentials/v2"],
    "type": ["VerifiablePresentation", "harbour:VerifiablePresentation"],
    "holder": "did:ethr:0x14a34:0x4d6246a7d1e60caa44b75e3af9b37ac8d6442774",
    "verifiableCredential": [
      {
        "@context": ["https://www.w3.org/ns/credentials/v2", "https://w3id.org/reachhaven/harbour/core/v1/"],
        "type": ["VerifiableCredential"],
        "issuer": "did:ethr:0x14a34:0x4d6246a7d1e60caa44b75e3af9b37ac8d6442774",
        "validFrom": "2024-01-01T00:00:00Z",
        "credentialSubject": {
          "id": "did:ethr:0x14a34:0x4d6246a7d1e60caa44b75e3af9b37ac8d6442774",
          "type": "harbour:LinkedCredentialService",
          "didcore:serviceEndpoint": {"id": "https://resolver.harbour.id/credentials/did:ethr:0x14a34:0x4d6246a7d1e60caa44b75e3af9b37ac8d6442774"}
        }
      }
    ]
  }
}

What it proves: The authorizing party (Trust Anchor or org) approved the Signing Service to issue a credential for the target subject. The chain of trust flows: Trust Anchor (LinkedCredentialService) → org (LegalPersonCredential) → employee (NaturalPersonCredential).

DelegatedSignatureEvidence

Evidence on a receipt credential (SD-JWT-VC) that a signing service executed a transaction with the user's explicit consent. The consent VP uses SD-JWT with PII redacted. Transaction data is a disclosable claim enabling three-layer privacy (public / authorized / full audit).

Use case: A signing service issues a receipt credential after executing a blockchain purchase on behalf of a user.

{
  "type": "harbour:DelegatedSignatureEvidence",
  "verifiablePresentation": "<SD-JWT VP with redacted PII>",
  "delegatedTo": "did:ethr:0x14a34:0x31f1ca3dc5da9f83f360d805662d11a418950202",
  "transaction_data": {
    "type": "harbour.delegate:data.purchase",
    "credential_ids": ["harbour_natural_person"],
    "transaction_data_hashes_alg": ["sha-256"],
    "nonce": "da9b1009",
    "iat": 1771934400,
    "txn": {
      "asset_id": "urn:uuid:550e8400-e29b-41d4-a716-446655440000",
      "price": "100",
      "currency": "ENVITED",
      "marketplace": "did:ethr:0x14a34:0x89fe5e7f506d992f76bcba309773c0ee3ee6039c"
    }
  },
  "challenge": "da9b1009 HARBOUR_DELEGATE c3d4ba771c1103935ab4121874c4b3a78c8471719c80f60d59ca5811e232089b"
}

What it proves: The user explicitly consented to the specific transaction, and the signing service executed it on their behalf.

See Delegated Signing for the complete flow.

Three-Layer Privacy Model

The receipt credential is an SD-JWT-VC. Transaction data and identity details are selectively disclosable:

Layer Audience What's Visible
Layer 1 — Public Everyone CRSet entry (credential exists), transaction_data_hash on-chain, DID identifier, KB-JWT signature valid
Layer 2 — Authorized Auditor Transaction details (asset, price, marketplace), consent VP hash verification
Layer 3 — Full Audit Compliance User identity (name, email, organization), full credential chain

When to Use Each Type

Evidence Type Use When Example Scenario
CredentialEvidence Issuing credential after authorization from a trusted party Trust Anchor authorizes org issuance; org authorizes employee issuance
DelegatedSignatureEvidence Issuing receipt after delegated action Blockchain purchase, contract signing, access delegation

Evidence Structure

All evidence types inherit from the abstract Evidence class and share:

Evidence:
  abstract: true
  class_uri: cred:Evidence
  slots:
    - type  # Required: identifies the evidence type

Most evidence types include a verifiablePresentation slot containing a signed VP as proof.

Privacy Considerations

Evidence often contains sensitive information. For privacy-preserving audit:

  1. Use SD-JWT VPs: Selectively disclose only necessary claims
  2. Redact PII: Names, emails, etc. can be hidden while keeping DID visible
  3. Three-layer disclosure:
  4. Public: CRSet + transaction hash + signature validity
  5. Authorized: Transaction details (asset, price)
  6. Full audit: Identity details (name, email, organization)

Verification

When verifying credentials or presentations with evidence:

  1. Verify the outer signature (credential or VP)
  2. Verify each evidence VP signature
  3. Check evidence issuer trust (is the evidence issuer trusted?)
  4. Validate evidence freshness (timestamps, nonces)
  5. Check revocation status of evidence credentials
from harbour.verifier import verify_vc_jose

# Verify outer credential
result = verify_vc_jose(credential_jwt, issuer_public_key)

# Verify evidence VP
for evidence in result.get("evidence", []):
    if "verifiablePresentation" in evidence:
        vp = evidence["verifiablePresentation"]
        # Verify VP signature...

Adding Evidence to Credentials

When issuing a credential with evidence:

credential = {
    "@context": [...],
    "type": ["VerifiableCredential", "harbour:NaturalPersonCredential"],
    "issuer": "did:ethr:0x14a34:0x31f1ca3dc5da9f83f360d805662d11a418950202",
    "credentialSubject": {...},
    "evidence": [
        {
            "type": "harbour:CredentialEvidence",
            "verifiablePresentation": authorization_vp_jwt
        }
    ]
}

signed_vc = sign_vc_jose(credential, issuer_private_key)

Schema Definition

Evidence types are defined in linkml/harbour-core-credential.yaml:

Evidence:
  abstract: true
  class_uri: cred:Evidence
  slots:
    - type

CredentialEvidence:
  is_a: Evidence
  class_uri: harbour:CredentialEvidence
  slots:
    - verifiablePresentation
  slot_usage:
    verifiablePresentation:
      required: true

DelegatedSignatureEvidence:
  is_a: Evidence
  class_uri: harbour:DelegatedSignatureEvidence
  slots:
    - verifiablePresentation
    - delegatedTo
    - transaction_data
  slot_usage:
    verifiablePresentation:
      required: true
    delegatedTo:
      required: true
    transaction_data:
      required: true