CredentialsOne of the most important elements in building a digital-focused work is the usage of credentials. This credentials prove our date of birth, our name, our address, and our academic qualifications. The W3C recommendation aims to standardize the usage of these credentials in a way which is cryptographically secure, privacy respecting, and machine-verifiable. For this we will generate a credential for an academic qualification for a citizen, and then sign this with a trusted Ed25519 key pair. |
Outline
Let's keep it simple, and where Alice needs a signed attestation of her university, school and level of qualification. For this we can create a claim that can just have free-form text:
type Claim struct { id string awardTo string university string department string degreeAwarded string }
If we want, we can also have a schema to define this, but we will keep it simple just now, and allow a string to be created for each of the fields. Next we need a trusted signer, and their details. For this we will define a context and type of qualitification that the signer is signing for, an ID for the signer, the issuers name, and the date of the award:
type IssuerMetadata struct { context []string id string typeOfCredential []string issuer string issuanceDate time.Time }
Next, we need a proof of how the signature is signed and its cryptographic signature. For this we can use the Ed25519 key pair, and sign with the private key, and then prove (with the creator) the public key:
type Proof struct { typeOfProof string created time.Time creator ed25519.PublicKey signature []byte }
And finally we need to package all of this up into a form which encapsulates the claim, the issuer meta data and the proof with:
type Credential struct { context []string id string typeOfCredential []string issuer string issuanceDate time.Time credentialSubject Claim proof Proof }
For this we will take the id, typeOfCredential, issure, and issuance details form the metadata of the issuer.
func createCredential(keyPair KeyPair, metadata IssuerMetadata, claim Claim) Credential { credential := Credential{ context: metadata.context, id: metadata.id, typeOfCredential: metadata.typeOfCredential, issuer: metadata.issuer, issuanceDate: metadata.issuanceDate, credentialSubject: claim, } }
Coding
We can use the Go programming language to implement this code:
package main import ( "crypto/ed25519" "fmt" "os" "time" ) type KeyPair struct { publicKey ed25519.PublicKey privateKey ed25519.PrivateKey } type IssuerMetadata struct { context []string id string typeOfCredential []string issuer string issuanceDate time.Time } type Claim struct { id string awardTo string university string department string degreeAwarded string } type Proof struct { typeOfProof string created time.Time creator ed25519.PublicKey signature []byte } type Credential struct { context []string id string typeOfCredential []string issuer string issuanceDate time.Time credentialSubject Claim proof Proof } func createCredential(keyPair KeyPair, metadata IssuerMetadata, claim Claim) Credential { //create credential credential := Credential{ context: metadata.context, id: metadata.id, typeOfCredential: metadata.typeOfCredential, issuer: metadata.issuer, issuanceDate: metadata.issuanceDate, credentialSubject: claim, } //create proof proof := Proof{ typeOfProof: "ed25519", created: time.Now(), creator: keyPair.publicKey, signature: ed25519.Sign(keyPair.privateKey, []byte(fmt.Sprintf("%v", credential))), } credential.proof = proof return credential } func verifyCredential(publicKey ed25519.PublicKey, credential Credential) bool { if string(publicKey) != string(credential.proof.creator) { return false } proofObj := credential.proof credential.proof = Proof{} return ed25519.Verify(publicKey, []byte(fmt.Sprintf("%v", credential)), proofObj.signature) } func main() { c_name := "Fred Smith" c_degree := "PhD" c_university := "Achelous University" c_department := "School of Winds and Air" argCount := len(os.Args[1:]) if argCount > 0 { c_name = os.Args[1] } if argCount > 1 { c_degree = os.Args[2] } if argCount > 2 { c_university = os.Args[3] } if argCount > 3 { c_department = os.Args[4] } publ, priv, _ := ed25519.GenerateKey(nil) keyPair := KeyPair{ publicKey: publ, privateKey: priv, } metadata := IssuerMetadata{ context: []string{"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"}, id: "did:example:123#owner", typeOfCredential: []string{"VerifiableCredential", "UniversityDegreeCredential"}, issuer: "https://example.edu/issuers/565049", issuanceDate: time.Now(), } claim := Claim{ id: "did:example:ebfeb1f712ebc6f1c276e12ec21", awardTo: c_name, university: c_university, department: c_department, degreeAwarded: c_degree, } createdCredential := createCredential(keyPair, metadata, claim) fmt.Printf("Private key: %x\n", priv) fmt.Printf("Public key: %x\n", publ) fmt.Printf("\n--- Credentials ---\n") fmt.Printf("Credential ID: %s\n", createdCredential.id) fmt.Printf("Credential Issuer: %s\n", createdCredential.issuer) fmt.Printf("Credential Date: %s\n", createdCredential.issuanceDate) fmt.Printf("Credential Subject (ID): %s\n", createdCredential.credentialSubject.id) fmt.Printf("Credential Subject (Awarded To): %s\n", createdCredential.credentialSubject.awardTo) fmt.Printf("Credential Subject (University): %s\n", createdCredential.credentialSubject.university) fmt.Printf("Credential Subject (Department): %s\n", createdCredential.credentialSubject.department) fmt.Printf("Credential Subject (DegreeAwarded): %s\n", createdCredential.credentialSubject.degreeAwarded) fmt.Printf("\n\n--- Proof ---\n") fmt.Printf("Creator: %x\n", createdCredential.proof.creator) fmt.Printf("Type: %s\n", createdCredential.proof.typeOfProof) fmt.Printf("Created: %s\n", createdCredential.proof.created) fmt.Printf("Proof signature: %x\n", createdCredential.proof.signature) rtn := verifyCredential(keyPair.publicKey, createdCredential) if rtn { fmt.Println("Valid proof") } }
A test run:
Private key: aa4631f3fc564388a2a3c53d87260886e99168ef13165afe0ae1e3a5f2f42360b0541d750da7a18bced6f249627abc510b21bf3fb4b8714e33f384ff779413ca Public key: b0541d750da7a18bced6f249627abc510b21bf3fb4b8714e33f384ff779413ca --- Credentials --- Credential ID: did:example:123#owner Credential Issuer: https://example.edu/issuers/565049 Credential Date: 2021-12-24 07:43:31.0690025 +0000 GMT m=+0.003000001 Credential Subject (ID): did:example:ebfeb1f712ebc6f1c276e12ec21 Credential Subject (Awarded To): Fred Smith Credential Subject (University): Hades University Credential Subject (Department): School of music, prophecy, education, healing and disease Credential Subject (DegreeAwarded): Higher Certificate --- Proof --- Creator: b0541d750da7a18bced6f249627abc510b21bf3fb4b8714e33f384ff779413ca Type: ed25519 Created: 2021-12-24 07:43:31.0690025 +0000 GMT m=+0.003000001 Proof signature: eac1109ed0c409ee57576d6b04436f4416c6e4afbd6f9af5d27ca614c4a6235421efc42f5da2bd2b63b7eb2ca14e7d95dc612374399ab2cde1ce7d46eaf14607 Valid proof