Certichain technical documentation
Certichain is a decentralised application for tamper-evident academic records. A registered institution anchors a signed fingerprint of each credential (a degree, a transcript, a certificate) on a public Ethereum-compatible blockchain. Anyone can then check, in a browser and without an account or a wallet, that a credential exists, who signed it, that a document matches it, and whether it still stands. The document itself is encrypted in the issuer's browser and kept off the chain, and no personal data is written to the chain.
These pages describe the system as it is in the repository: the contracts, the web application, the server routes, every user flow, the file formats, the security model and the test suites. They are written for engineers who are new to the project and for reviewers who want to check how something works without reading all of the code first.
Certichain runs on the Ethereum Sepolia test network with synthetic data only. It has not had an external security audit, and some features (the verification API, status lists, the monitor) are built but switched off until their keys are configured. Each page says when a feature depends on configuration.
The promise in one sentence
"Genuine, issued by a registered institution, and not cancelled" can be checked by anyone, while personal data stays with the holder.
Who uses it
| Role | What they do | Needs a wallet |
|---|---|---|
| Verifier | Looks up a credential by id, link or QR code; checks a document, a package, a verifiable credential or a disclosure against the chain. | No |
| Holder (student) | Keeps the credential package, opens and shares the document, shows selected fields, carries credentials on a phone. | Optional |
| Issuer (institution) | Issues, re-issues, suspends, reinstates and revokes its own credentials; invites students; defines record types; imports a cohort. | Yes |
| Guardian | Pauses new issuance in an emergency. Cannot register anyone. | Yes |
| Admin | Registers and removes issuers, lifts pauses, manages roles. On Sepolia this is a 2-of-3 Safe, with a timelock deployed for admin actions. | Yes (a Safe) |
The Roles section describes each one in full.
The system at a glance
Three principles hold the design together:
- The chain is the source of truth. Issuer registration, credential anchors, signatures and status live in contracts. Lists such as "my credentials" are rebuilt from contract events; there is no application database.
- The browser does the secret work. Hashing, encryption, key derivation, commitments and proofs happen on the user's device. The server never sees a plaintext document, a private key or a student's name.
- The server holds as little as possible. It checks sign-in, stores encrypted containers through a pinning service, keeps sign-in nonces, rate-limit counters and monitor state, and (when configured) signs verification answers and status lists with keys that hold no funds.
What is on the chain and what is not
| On the chain (public, permanent) | Off the chain |
|---|---|
| Issuer addresses, registered names and roles | Student names and ids, kept in the holder's credential package |
| Credential anchors: issuer, salted subject commitment, document SHA-256, salted metadata hash, record type, dates | The document, encrypted with AES-256-GCM, stored on IPFS |
| The issuer's EIP-712 signature, carried in an event | The document key, inside the package and in wrapped grants |
| Status history: suspended, revoked, superseded, with reason codes and note hashes | Selective disclosure salts and field values |
| Holder bindings as commitments, record type names, access group commitments and receipts | Sign-in nonces, rate-limit counters and monitor history in Redis; sessions are signed cookies |
The Privacy design page explains why each item sits where it does.
Two contract generations
The repository holds two generations of contracts:
- v0.3 (current): a set of small registries (
IssuerRegistry,CredentialRegistry,StatusRegistry,HolderRegistry,RecordTypeRegistry) built on OpenZeppelin 5, with EIP-712 issuer signatures, a status lifecycle, issuer-attested enrolment and no plaintext personal data. Several versioned contract sets can be live at once (Sepolia has sets 0.3.0, active, and 0.5.0, deployed and not active), so an upgrade never strands old credentials. - v0.2 (legacy, release v2.0.0): a single
AcademicRecordscontract with role-based access, a linked storage library and a student module. It stays deployed on Sepolia and the app still supports it whenNEXT_PUBLIC_CONTRACT_VERSIONis notv03, but new work targets v0.3.
See Contract versions and sets.
How to read these docs
| If you want to... | Start with |
|---|---|
| Learn the words and the cryptography first | Concepts and the Glossary |
| See how the system is built | Architecture |
| Understand a contract rule | Smart contracts |
| Follow one feature end to end | Flows |
| Know what a given user can do | Roles |
| Parse or produce a file | Data formats |
| Review the security model | Security and privacy |
| Run or extend the tests | Testing |
| Integrate another system | Integrations |
| Run it locally or operate a deployment | Operations |
Conventions in these pages
- File paths are relative to the repository root, for example
src/services/domain/credential-service.tsorblockchain/contracts/v03/StatusRegistry.sol. - "The app" is the Next.js web application in
src/. "The registries" are the v0.3 contracts. "A set" is one deployment of the v0.3 registries listed in the deployment manifest. - Diagrams are drawn with Mermaid from the text in each page, so they change with the page.
- Environment variables are named, never given values. Example names live in
example.env. - The engineering handbook in
docs/(plan, specs, decisions, runbooks) records why things were decided. These pages describe what the result is and point to the handbook where the reasoning matters.