DEV Community

Gavriliuc Vlada
Gavriliuc Vlada

Posted on AI-assisted

How do you check that an exam certificate is real? I tried to model it

This week I was reading notices on the Irish eTenders site and one of them stopped me. Maynooth University wants a new system for TEG, the European Certificate in Irish. TEG is their language exam for adults who learn Irish.

I expected a boring website tender. It is partly that. But one line in the list of things they want made me think about code for the whole evening: "an automated digital exam certification solution".

You can read the notice here.

What the notice says

I want to keep the facts separate from my guesses, so first the facts.

The buyer is Maynooth University. The notice was published on 28 October 2026 and the deadline for tenders is 10 December 2026 at 12:00. Questions can be asked until 3 December. The contract is for 36 months. The description says the total budget is €130,300 excluding VAT. (The "estimated value" field on the same page says 130,000, so there is a small difference between the two numbers.)

The reason for the project is growth. The notice says candidate numbers are "projected to reach approximately 5,000 annually".

The system they describe has these parts:

  • a bilingual public website with a CMS
  • a self-service portal where candidates book and pay for exams
  • an admin platform for the staff
  • automated digital exam certificates
  • integration with a digital language testing platform

TEG exams are "broadly based" on the Common European Framework of Reference for Languages, the CEFR. The Council of Europe page says the CEFR has six levels, A1 to C2. The TEG website says exams are offered at five levels at present, A1 to C1.

That is all I know for sure. The real tender documents are behind a login, so I did not read the technical details.

Why the certificate part caught my attention

My first thought was: a digital certificate is just a PDF, right? You make a nice template, put the name and the level on it, done.

Then I thought about who uses this certificate. A person passes B1 and then sends the certificate to an employer, or to a school, or to a public body that needs Irish speakers. And that employer has to decide if it is real.

A PDF is very easy to edit. Changing "B1" to "B2" takes about one minute. So for me the hard part is the checking. How does the employer know it is real without calling the university every time?

The EU already has an answer for this kind of problem. European Digital Credentials for Learning are described on the Europass site as "a verifiable, digital version of a credential". They are signed with an electronic seal, which is a kind of digital signature that belongs to an organisation.

I don't know if Maynooth will use this, or something else. The notice does not say. But the basic idea is the same in most systems, so I tried to build the smallest version of it.

My tiny model

The idea is simple. The exam centre has a private key and keeps it secret. It signs the certificate data with that key. Everyone else gets the public key. With the public key you can check the signature, but you cannot make a new one.

I used Ed25519 from the cryptography package because the API is short.

import json
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.exceptions import InvalidSignature

# The exam centre keeps this key secret
private_key = Ed25519PrivateKey.generate()
# Anyone (an employer, a school) can have this one
public_key = private_key.public_key()


def to_bytes(cert):
    # same dict -> same bytes, every time
    return json.dumps(cert, sort_keys=True, separators=(",", ":")).encode()


def issue(cert):
    signature = private_key.sign(to_bytes(cert))
    return {"cert": cert, "signature": signature.hex()}


def check(signed):
    try:
        public_key.verify(bytes.fromhex(signed["signature"]), to_bytes(signed["cert"]))
        return "valid"
    except InvalidSignature:
        return "NOT valid"


signed = issue({
    "id": "TEG-2027-000123",
    "candidate": "Aoife Example",
    "level": "B1",
    "components": {"oral": "pass", "written": "pass"},
    "issued": "2027-06-30",
})

print("original:", check(signed))

# someone edits the PDF / JSON and makes it a B2
signed["cert"]["level"] = "B2"
print("edited:  ", check(signed))
Enter fullscreen mode Exit fullscreen mode

When I run it I get:

original: valid
edited:   NOT valid
Enter fullscreen mode Exit fullscreen mode

The certificate ID format, the name and the fields are all invented by me. I just wanted something that looks a bit like a real exam result.

Things I got wrong at first

My first version did not have sort_keys=True. It still worked in my test, because Python keeps the order of dict keys. But if another system rebuilds the same certificate with the keys in a different order, the bytes change and a real certificate looks fake. That scared me a little, because it is the kind of bug you only find when a real person complains. Real standards solve this with fixed formats, and I think that is one reason they exist.

The second thing I noticed is what my model does not do:

  • If the private key leaks, anyone can make "valid" certificates. Keeping that key safe is probably harder than writing the code.
  • There is no way to cancel a certificate. If a result is changed after an appeal, the old signed file is still "valid" in my model. I guess a real system needs some kind of revocation list or status check.
  • The employer needs to get the public key from somewhere they trust. If I can trick them into using my key, my fake certificate passes.

My guess is that the supplier will not invent any of this from zero. They will probably use an existing credential format and a signing service. But somebody still has to decide what goes inside the certificate, and that part looks like normal database and design work. Should it show the oral and written results separately? The TEG site says candidates can take only the oral exam to get certification in the spoken language, so the data model needs to allow that too.

What I take from this

For a €130,300 budget over 36 months, the notice asks for a lot: website, CMS, booking, payments, admin, certificates and an integration. I am not sure how much of the certificate work fits inside that. Maybe it is mostly about choosing a good existing product.

I also like that a language exam tender made me read about Ed25519 late in the evening. I did not expect that when I opened the notice.

If you have built something that issues certificates or diplomas, how do you handle revocation in real life? Do people actually check it, or does everyone just trust the PDF?

Top comments (0)