Skip to Content
ReferenceData Models & Crypto

Data Models & Cryptography

W3C Verifiable Credential format

All credentials conform to the W3C VC Data Model 1.1:

{ "@context": [ "https://www.w3.org/2018/credentials/v1", "https://attestpro.global/context/v1" ], "type": ["VerifiableCredential", "SecondaryEducationCredential"], "id": "urn:uuid:12345678-1234-1234-1234-123456789012", "issuer": { "id": "did:key:z6MkhaXgBZDvotDkL5257faWxcqyqQ4yoni1nUbt5d12345", "name": "National Board of Education" }, "issuanceDate": "2026-03-15T00:00:00Z", "credentialSubject": { "id": "did:key:z6MkpqXgBZDvotDkL5257faWxcqyqQ4yoni1nUbt5d67890", "name": "Jane Doe", "marks": { "english": 95, "mathematics": 92 } }, "proof": { "type": "DataIntegrityProof", "cryptosuite": "eddsa-jcs-2022", "verificationMethod": "did:key:z6MkhaXgBZDvotDkL5257faWxcqyqQ4yoni1nUbt5d12345#z6MkhaXgBZDvotDkL5257faWxcqyqQ4yoni1nUbt5d12345", "proofValue": "3MCNuFxcqyqQ4yoni1nUbt5d12345..." } }

PostgreSQL schema (orientation only)

See Database Schema Ownership for the authoritative, table-by-table reference. Quick schema-to-service map:

SchemaOwning service
authorityIssuer Registry
walletCredential Issuance
coreCore Engine (largest — 50+ tables spanning auth sessions, claim-integrity, custodian intake/compliance/workforce/search, audit logs, share links)
catalogProgram Catalog
learnerLearner Records
custodianCustodian Registry
consoleAdmin Console

Two core tables worth calling out directly:

CREATE TABLE core.share_links ( share_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), credential_id UUID NOT NULL, -- soft FK -> wallet.credentials.credential_id holder_did VARCHAR(512) NOT NULL, share_token VARCHAR(64) NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), expires_at TIMESTAMPTZ, access_limit INTEGER, access_count INTEGER NOT NULL DEFAULT 0, active BOOLEAN NOT NULL DEFAULT true, revoked_at TIMESTAMPTZ ); CREATE TABLE core.holder_requests ( request_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), issuer_id UUID NOT NULL, -- soft FK -> authority.issuers.issuer_id issuer_name VARCHAR(255), credential_id UUID NOT NULL, -- soft FK -> wallet.credentials.credential_id holder_did VARCHAR(512), holder_name VARCHAR(255) NOT NULL, holder_email VARCHAR(255) NOT NULL, credential_type VARCHAR(100), request_type VARCHAR(50) NOT NULL, -- REISSUE | REVOKE | UPDATE | DOWNLOAD reason TEXT, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING | APPROVED | REJECTED response TEXT, submitted_at TIMESTAMPTZ NOT NULL DEFAULT now(), resolved_at TIMESTAMPTZ, resolved_by VARCHAR(255) );

Holder-visible access history has no standalone access_logs table — GET /api/v1/holder/access-logs is served from core.audit_logs, the general audit trail.

Key gRPC contracts

backends/shared/src/main/proto/ holds 8 proto files. Full per-service RPC lists live in API & gRPC Reference; the two most commonly referenced:

CredentialIssuanceService (credential.proto, port 50051):

service CredentialIssuanceService { rpc IssueCredential(IssueCredentialRequest) returns (IssueCredentialResponse); rpc RevokeCredential(RevokeCredentialRequest) returns (RevokeCredentialResponse); rpc GetCredential(GetCredentialRequest) returns (GetCredentialResponse); rpc ClaimCredential(ClaimCredentialRequest) returns (ClaimCredentialResponse); rpc ListCredentialsByIssuer(ListCredentialsByIssuerRequest) returns (ListCredentialsResponse); rpc GetCredentialForIssuer(GetCredentialForIssuerRequest) returns (CredentialRecord); rpc GetIssuerCredentialStats(GetIssuerCredentialStatsRequest) returns (IssuerCredentialStatsResponse); rpc GetCredentialForHolder(GetCredentialForHolderRequest) returns (CredentialRecord); rpc SearchCredentialsByHolder(SearchCredentialsByHolderRequest) returns (ListCredentialsResponse); rpc GetHolderCredentialStats(GetHolderCredentialStatsRequest) returns (HolderCredentialStatsResponse); rpc ListNewlyExpiredCredentials(ListNewlyExpiredCredentialsRequest) returns (ListCredentialsResponse); rpc GetNetworkCredentialStats(GetNetworkCredentialStatsRequest) returns (NetworkCredentialStatsResponse); rpc ListCredentialsByCustodian(ListCredentialsByCustodianRequest) returns (ListCredentialsResponse); rpc GetCredentialForCustodian(GetCredentialForCustodianRequest) returns (CredentialRecord); rpc GetCustodianCredentialStats(GetCustodianCredentialStatsRequest) returns (CustodianCredentialStatsResponse); rpc ListCustodianCredentialsExpiringBetween(ListCustodianCredentialsExpiringBetweenRequest) returns (ListCredentialsResponse); rpc LinkSupersededCredential(LinkSupersededCredentialRequest) returns (LinkSupersededCredentialResponse); }

There is no BatchIssue RPC — batch issuance is a REST-layer concern (POST /api/v1/credentials/batch), not a streaming gRPC method.

VerificationEngineService (verification.proto, port 50052):

service VerificationEngineService { rpc VerifyCredential(VerifyCredentialRequest) returns (VerifyCredentialResponse); rpc ValidateSignature(ValidateSignatureRequest) returns (ValidateSignatureResponse); rpc CheckCredentialStatus(CheckStatusRequest) returns (CheckStatusResponse); rpc VerifyRawSignature(VerifyRawSignatureRequest) returns (VerifyRawSignatureResponse); }

registry.proto (IssuerRegistryService, 50053) additionally carries RegisterIssuer, GetIssuer, ListIssuers, GetDIDDocument, RotateKey, UpdateIssuerStatus, SignPayload, API key CRUD, and federated did:web trust-registry RPCs. catalog.proto (CatalogRegistryService, 50054) is the largest contract in the codebase — jurisdictions, frameworks, catalog entries/versions, code sets, regulatory schemes, scheme registrations, proposals, skills, and semantic search/embeddings.

Cryptography

Ed25519 signatures (RFC 8037)

public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) { Ed25519PublicKeyParameters pubKey = new Ed25519PublicKeyParameters(publicKey, 0); Ed25519Signer signer = new Ed25519Signer(); signer.init(false, pubKey); signer.update(message, 0, message.length); return signer.verifySignature(signature); }

Key management — current state, not just target design

PathCustody
BYOK issuer keysNever touch Attest ID — true today, no caveat
Custodial issuer keysAES-256-GCM-encrypted at the application layer (SigningKeyEncryptionService, authority.signing_keys) — a documented pilot-only stopgap, not AWS KMS/CloudHSM
Custodian Registry keysSame shared encryption service, same caveat (custodian.signing_keys)

See CLAUDE.md’s “Security & Key Management” section for the real current state and the migration bar: a real HSM/KMS is required before onboarding any external issuer or custodian whose key custody isn’t otherwise trusted to this app layer.

Performance — targets, not measurements

No load-test harness or benchmark results exist in this codebase. The numbers below are targets carried over from early planning, not measured figures — load testing is an explicit launch-blocking item in CLAUDE.md’s Roadmap Context. There is also no batch/streaming issuance RPC, so “Issue Batch” below refers to the REST /api/v1/credentials/batch path issuing records sequentially, not a streamed RPC.

OperationLatency (p99)Notes
Verify link< 80 msIncludes DID resolution & access logging
Issue batch150–200/secSequential REST calls, not a streamed RPC
Cache retrieval< 5 msRedis-backed