A secure data exchange layer for Zimbabwe, written in Rust.
Z-Road lets government agencies, banks, companies and other organisations query each other's data directly, safely and with a full audit trail, without anyone building a single central database. It is inspired by Estonia's X-Road and designed around the realities of Zimbabwe: patchy connectivity, power cuts, modest hardware and the need for public trust.
Status: working proof of concept. The protocol, security server, central server, timestamp authority and a first use case run end to end and are covered by automated tests. It has not had an independent security review and is not ready for real data. See the Roadmap and the threat model.
- Why Z-Road
- Core ideas
- Architecture
- How a request flows
- Worked example: tax clearance check
- Joining the network
- Zimbabwe-specific design considerations
- Why Rust
- Repository layout
- Getting started
- What works today
- Roadmap
- Documentation
- Contributing
- Acknowledgements
- License
Today, proving something to another organisation in Zimbabwe usually means a PDF, a stamped letter or an email attachment. A supplier's tax clearance certificate, a proof of address, a company registration extract: each one is easy to forge, easy to let expire and slow to verify.
Z-Road replaces "send me a document" with "ask the source, get a signed answer":
- Once-only data. The state and its partners ask the owner of the data, not the citizen, for information that already exists.
- Fast, verifiable services. Pre-filled forms, instant KYC, live tax clearance checks.
- Transparency. Every query is logged, so people can eventually see who accessed their data and when.
- No honeypot. Each organisation keeps its own data. There is no central database to breach or abuse.
| Principle | What it means |
|---|---|
| Decentralised data | Data stays with its owner. Z-Road only carries requests and answers. |
| Signed and logged | Every message is signed, timestamped and logged on both sides, so exchanges are provable later. |
| Provider decides access | The central authority vouches for who you are. The data provider decides who may use its services. |
| Minimal answers | Services answer the question asked ("is this TIN cleared?") and nothing more. |
| Per-service permissions | Access is granted per service, not per organisation. |
| Open source | The protocol and software are open for audit and independent implementation. |
Z-Road has three kinds of components.
- Security Server. Runs at every member. It signs, encrypts, timestamps and logs messages, checks access rights and forwards requests to the internal system. This is the main piece of software and where most security-critical code lives.
- Central Server. Run by the governing authority. It keeps the list of members and their services and acts as the trust anchor. It does not see or store exchanged data.
- Timestamp Service. Provides trusted timestamps so that a signed exchange can be proven to have happened at a specific time.
An organisation's internal systems never talk to another organisation directly. Only security servers talk to each other.
Every participant and service is identified by a path:
instance / member-class / member-code / subsystem [/ service / version]
For example ZW/GOV/ZIMRA/tax-clearance/verify/v1.
Both sides keep their own logs, so either party can later prove what was asked and answered.
Buyers in Zimbabwe regularly need to confirm that a supplier holds a valid ITF263 tax clearance before paying them. Today that is a PDF sent by email. With Z-Road:
- A clerk at the buyer enters a supplier invoice. The ERP calls the buyer's security server with the supplier's TIN.
- The buyer's security server signs and logs the request and sends it over mTLS to ZIMRA's security server.
- ZIMRA's security server confirms the buyer is a registered member and is allowed to use the clearance service.
- ZIMRA's system looks up the TIN and replies. The reply is signed, so the buyer can prove later that ZIMRA confirmed the supplier was cleared on that date.
Request:
POST /r1/ZW/GOV/ZIMRA/tax-clearance/verify/v1
Z-Road-Client: ZW/COM/12345678/accounts-payable
Z-Road-Id: 7f3c9a1e-...
{ "tin": "2000123456" }Response:
{
"tin": "2000123456",
"name": "Supplier (Pvt) Ltd",
"status": "VALID",
"valid_until": "2026-12-31"
}Design notes:
- Answer the question, not more. The service returns status and expiry only, with no turnover or tax history. This data minimisation is what makes it reasonable to open the service to every member.
- Live check beats a PDF. The buyer can re-check before every payment instead of trusting a certificate that may have been revoked last week.
- Shared nodes for small businesses. One security server can host many members, so an accounting vendor, bank or chamber of commerce can run a node on behalf of customers.
The authority vouches for identity. Each provider independently decides who may use each of its services. The Registrar General, for instance, decides whether ZIMRA can query the ID register.
- Legal footing. The Cyber and Data Protection Act and the role of POTRAZ as data protection authority shape what can be exchanged, logged and retained. Legal review is a prerequisite for any real deployment.
- First adopters. The Registrar General (national IDs, births), ZIMRA, and banks or mobile money operators (KYC) offer the quickest real-world wins.
- Unreliable connectivity and power. Security servers should queue, retry and resume gracefully rather than assume they are always online.
- Modest hardware. District offices may run nodes on small machines, so resource use matters.
- Citizen visibility. Letting people see who accessed their data is central to public trust and should be designed in from the start, not added later.
The security server sits at the edge of every organisation and must be hard to break.
- Memory safety without a garbage collector.
- Low memory and CPU footprint.
- Strong ecosystem for the job:
tokioandaxumfor networking,rustlsfor mTLS,ringoraws-lc-rsfor cryptography,serdefor message formats. - Single static binaries are easy to deploy on constrained machines.
A single Cargo workspace, so the protocol code is shared and end-to-end tests are simple. It can be split later if separate owners or release cycles emerge.
z-road/
crates/
zroad-core/ identifiers, signed messages, PKI helpers, hash-chained audit log
zroad-net/ mutual TLS, small HTTP client, server with peer certificates, central API client
security-server/ the main binary: provider and consumer sides, outbox, audit anchoring
central-server/ certificate authority and member directory
timestamp-service/ trusted timestamps for audit log anchoring
zroad-client/ Rust client library for integrating applications
signer-service/ lets a hosted member keep its own signing key on its own machine
zroad-cli/ admin and audit tool: enrol, revoke, verify logs and proofs, citizen access log
e2e-tests/ whole-network tests over real mutual TLS
examples/
zimra-clearance/ mock provider system (tax clearance check)
buyer-client/ sample consumer
citizen-portal/ demo "who looked at my data?" page
scripts/demo.sh run a complete local network and make a signed, logged request
Dockerfile, deploy/ container image, a Docker Compose network, systemd units, smoke tests
docs/ protocol, threat model, deployment, legal considerations, pilot plan
You need a recent stable Rust toolchain.
cargo test --workspace # unit and end-to-end tests
scripts/demo.sh # a full local network, step by step
docker compose -f deploy/docker-compose.yml up --build --wait # the same, in containersThe demo starts a central server, a timestamp authority, a mock ZIMRA clearance system and two security servers, then:
- a buyer checks a supplier's tax clearance (
VALID), and another that isEXPIRED; - the signed proof of the exchange is verified offline;
- ZIMRA's log is queried for who looked up that TIN (the citizen's view), also as a web page on http://127.0.0.1:9100;
- the audit log is verified, including its trusted timestamp.
See docs/deployment.md for setting up a network by hand and the configuration reference.
| Area | Implemented |
|---|---|
| Identity | Private CA; Ed25519 member keys; enrolment with one-time tokens; automatic renewal everywhere a key lives (security servers, nodes, signers, timestamp authority, central server), switched in without a restart or dropped calls, with old proofs and anchors still verifiable; certificate subject always the member id |
| Transport | Mutual TLS between security servers (rustls, ring) |
| Messages | Signed requests and responses, bound together by hash; body hashes; ±5 minute clock window |
| Access control | Per-service, default-deny rules evaluated by the provider; revocation through the directory |
| Replay and retries | Per-peer message id cache (rebuilt from the audit log after a restart); identical retries are idempotent |
| Integration | Plain-HTTP internal API (OpenAPI), a Rust client library with typed errors, async submit-and-wait and offline proof verification (guide) |
| Discovery and contracts | A public service catalogue with a JSON Schema per service request and answer; providers enforce them before anything reaches their system, consumers can check early; access rules stay private |
| Shared nodes | One security server can host many members with separate logs, tokens and rules (deployment guide). Operator-held keys, or member-held keys: each hosted member signs with its own key in a signer service on its own machine, and the node cannot forge its messages (guide) |
| Resilience | Durable async outbox with backoff; cached directory keeps working if the central server is down |
| Accountability | Hash-chained audit log on both sides, refuses to start on a broken chain, periodic trusted-timestamp anchors |
| Proofs | A signed proof header on every answer, verifiable offline with zroad-cli proof-verify |
| Transparency | Provider-side "who looked up this subject" query, without storing the subject in clear; a citizen endpoint that answers only for the person a login system has vouched for (signed identity assertions) |
| Access control | Named operators with roles (auditor, operator, admin, portal) and per-person tokens stored as hashes; every privileged action is recorded in the tamper-evident log before it happens (details) |
The full plan, with status per item and the gate for starting a pilot, is in ROADMAP.md. In short:
- Phases 0–4: foundations. Protocol and threat model; security server, central server and timestamp authority; first use case (ZIMRA tax clearance); resilience; transparency and citizen login; access control with roles; service catalogue with schemas; shared nodes with member-held keys; automatic renewal; clients for Rust and Python; packaging; guides.
- [~] Phase 5: hardening. Done: fuzzing, fail-closed audit logging, replay protection across restarts, renewal,
cargo audit, adversarial tests. Next: key custody (offline root CA with an HSM or hardware token), the independent security review, operator MFA, a real citizen login at the first provider, longer fuzz campaigns. - Phase 6: pilot. Gated on an accountable authority, legal review and data-sharing agreements, the independent review, and rehearsed runbooks.
- Phase 7: production readiness. High availability, metrics, signed packages, quotas, more client libraries.
- Phase 8: scale. More members and services, federation, large payloads, ecosystem.
What decides whether a pilot happens is mostly outside the code: governance, legal, assurance and people. See ROADMAP.md.
Start with the guides: how to deploy securely, a separate guide for every kind of user, how to build an SDK, operations, incident response and troubleshooting. The reference documents:
- Protocol specification
- Threat model
- Running Z-Road
- Packaging: Docker Compose and systemd
- Access control: operators, roles and citizen login
- Integrating an application and the internal API (OpenAPI)
- Legal and regulatory considerations
- Pilot plan
- Design note: shared security servers (implemented)
- Security policy and contributing guide
Ideas, critique and contributions are welcome at this early stage, particularly on:
- Zimbabwean legal and regulatory requirements
- Protocol and threat-model review
- Rust implementation
- Real-world use cases and pilot partners
Open an issue to start a discussion. Before sending code, run cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings and cargo test --workspace.
Z-Road is inspired by X-Road, developed in Estonia and now maintained by the Nordic Institute for Interoperability Solutions (NIIS). Z-Road is an independent project and is not affiliated with X-Road or NIIS.
MIT. Copyright (c) 2026 Victor Phos. Contributions are accepted under the same licence.