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.
| Subject | Predicate | Object |
|---|---|---|
| _:c0 | a | cred:VerifiableCredential |
| _:c0 | a | ufp:DiplomaUFP |
| _:c0 | cred:issuer | <did:web:ufp.pt> |
| _:c0 | cred:validFrom | "2027-07-20T00:00:00Z"^^xsd:dateTime |
| <did:key:z6Mk...> | ufp:degree | "MSc in Computer Engineering" |
| <did:key:z6Mk...> | ufp:grade | 17 |
| _:c0 | cred:credentialSubject | <did:key:z6Mk...> |
| <https://ufp.pt/status/2027#42> | a | cred:StatusList2021 |
| _:c0 | cred:credentialStatus | <https://ufp.pt/status/2027#42> |
| _:c1 | a | sec:DataIntegrityProof |
| _:c1 | sec:cryptosuite | "ecdsa-secp256k1-jcs-2026-demo" |
| _:c1 | sec:verificationMethod | <did:pkh:eip155:1:0xE1c8643C81B21181E648B3eF4Ce75D0229C34921> |
| _:c1 | sec:proofValue | "0xa2096819b59db35dc3acae1eadf60cb8f4d5fc922afeb6d20b096e79bb5012025d9a0a54ca87375b2d8668bb2155f9574e21c82343c305553b0db163a6a359a31c" |
| _:c0 | sec: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.