Semantic Web and Web 3.0 · class 11 · demo

A verifiable credential is signed RDF

examples/08-credential/credential.jsonld: read with its two contexts (local excerpts — there is no network) it is a graph of 13 triples. Signed here as sign-credential.mjs signs it, with a key made when this server started and kept only in memory. Then the verifier recomputes who signed what it was given.

As issued: the signature verifies

expected signer (the proof's verificationMethod) 0xE1c8643C81B21181E648B3eF4Ce75D0229C34921
recovered from the signature and this content   0xE1c8643C81B21181E648B3eF4Ce75D0229C34921

The verifier needed no network and did not contact the issuer: the key's address is in the proof, the content is in the document.

The verifier's other checks

warning it is not valid yet (validFrom 2027-07-20T00:00:00Z)

As in verify-credential.py: validFrom is in the future on purpose (the class README, note 4) — a credential has a validity period, and the verifier checks it. A valid signature does not make it valid today.

The triples the verifier reads

The document shown below, read as RDF (lib/rdf.mjs, with the contexts of data/contexts/). With the demo's proof the graph has 14 triples; the key created is not in any context, so it gives no triple.

SubjectPredicateObject
_:c0acred:VerifiableCredential
_:c0aufp:DiplomaUFP
_:c0cred:issuer<did:web:ufp.pt>
_:c0cred:validFrom"2027-07-20T00:00:00Z"^^xsd:dateTime
<did:key:z6Mk...>ufp:degree"MSc in Computer Engineering"
<did:key:z6Mk...>ufp:grade17
_:c0cred:credentialSubject<did:key:z6Mk...>
<https://ufp.pt/status/2027#42>acred:StatusList2021
_:c0cred:credentialStatus<https://ufp.pt/status/2027#42>
_:c1asec:DataIntegrityProof
_:c1sec:cryptosuite"ecdsa-secp256k1-jcs-2026-demo"
_:c1sec:verificationMethod<did:pkh:eip155:1:0xE1c8643C81B21181E648B3eF4Ce75D0229C34921>
_:c1sec:proofValue"0xa2096819b59db35dc3acae1eadf60cb8f4d5fc922afeb6d20b096e79bb5012025d9a0a54ca87375b2d8668bb2155f9574e21c82343c305553b0db163a6a359a31c"
_:c0sec:proof_:c1

What the verifier was given

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://ufp.pt/contexts/diploma/v1"
  ],
  "type": [
    "VerifiableCredential",
    "DiplomaUFP"
  ],
  "issuer": "did:web:ufp.pt",
  "validFrom": "2027-07-20T00:00:00Z",
  "credentialSubject": {
    "id": "did:key:z6Mk...",
    "degree": "MSc in Computer Engineering",
    "grade": 17
  },
  "credentialStatus": {
    "type": "StatusList2021",
    "id": "https://ufp.pt/status/2027#42"
  },
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "ecdsa-secp256k1-jcs-2026-demo",
    "created": "2026-11-01T13:17:13.132Z",
    "verificationMethod": "did:pkh:eip155:1:0xE1c8643C81B21181E648B3eF4Ce75D0229C34921",
    "proofValue": "0xa2096819b59db35dc3acae1eadf60cb8f4d5fc922afeb6d20b096e79bb5012025d9a0a54ca87375b2d8668bb2155f9574e21c82343c305553b0db163a6a359a31c"
  }
}

The class file: 13 triples

@prefix cred: <https://www.w3.org/2018/credentials#> .
@prefix ufp: <https://ufp.pt/vocabulary/diploma#> .
@prefix sec: <https://w3id.org/security#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

_:c0 a cred:VerifiableCredential, ufp:DiplomaUFP ;
    cred:issuer <did:web:ufp.pt> ;
    cred:validFrom "2027-07-20T00:00:00Z"^^xsd:dateTime ;
    cred:credentialSubject <did:key:z6Mk...> ;
    cred:credentialStatus <https://ufp.pt/status/2027#42> ;
    sec:proof _:c1 .

<did:key:z6Mk...> ufp:degree "MSc in Computer Engineering" ;
    ufp:grade 17 .

<https://ufp.pt/status/2027#42> a cred:StatusList2021 .

_:c1 a sec:DataIntegrityProof ;
    sec:cryptosuite "eddsa-rdfc-2022" ;
    sec:proofValue "z3Mv..." .

An in-memory chain (the Ethereum virtual machine, @ethereumjs/evm), in this one process: no test network, no wallet, no keys, no money. Nothing a visitor does is kept.