docs/decisions/ (airKUNA's own ADR base). Status: DRAFT v0.2, revised after two rounds of prior-art research.
0Summary
Problem: Croatians have a first-rate digital identity — Certilia MobileID (AKD, via the Ministry of the Interior, eIDAS level High) — but it is centralised. The onchain world has no reliable, Sybil-resistant proof that "this is a unique real person", which blocks legitimate onchain voting, democratic governance and fair resource allocation.
Solution: An open protocol that turns a verified eID login into a soulbound personhood token (SBT) on Gnosis. Uniqueness is bound not to a wallet but to a nullifier derived from the national ID number (nullifier = HMAC-SHA256(ID number, pepper)), so one person can hold several Safe wallets but only one identity. The raw ID number never leaves the backend (GDPR-first). The design is source-agnostic: Certilia today, the EU EUDI Wallet tomorrow — the same onchain layer works for all 27 EU countries.
Key insight (from the prior-art analysis): the MVP does not need expensive hardware infrastructure or a signer network of our own. Sybil resistance is achieved with a client-side proof (zkTLS over Certilia OIDC, or NFC reading of the eID chip) + an onchain nullifier registry. The decentralised Android verifier network is Phase 2 — it improves the decentralisation of trust, it is not a prerequisite.
1Problem
- Centralised trust. Certilia/AKD is the single source of truth. For onchain democracy we need proof of personhood that does not depend on one entity able to mint everything on its own.
- Sybil attacks. Without proof of personhood, one person opens 1000 wallets and outvotes the honest ones.
- Wallet binding. A naive "KYC per wallet" does not work: people have several wallets (cold, hot, a Safe for an association, a Safe for a company), and identity must sit above them.
- Privacy & GDPR. The national ID number is sensitive PII. It must not end up onchain or in a plaintext database.
- Inheritance/recovery. A lost wallet must not mean a lost identity.
2The core primitive: nullifier, not wallet
nullifier = HMAC-SHA256(ID_NUMBER, SECRET_PEPPER)
- Deterministic (the same ID number → always the same nullifier) and irreversible (HMAC is one-way, the pepper is secret).
- Uniqueness at the person level, not the wallet level. 100 Safes belonging to the same person → the same ID number → the same nullifier → the contract rejects the second mint. This is Sybil resistance.
- Already proven in production:
domovina-apicomputesoib_hash = HMAC-SHA256(oib, key)with auniqueconstraint → one ID number = one account.
3Onchain architecture
Three open-source contracts on Gnosis:
3.1 IdentityRegistry
mapping(bytes32 nullifier => Identity) registry;
struct Identity { address anchor; uint64 loa; uint64 verifiedAt; uint64 reverifiedAt; }
function claim(Attestation calldata a, bytes calldata proof) external {
require(registry[a.nullifier].anchor == address(0), "one person, one identity");
require(_verify(a, proof), "invalid attestation"); // see 4 — pluggable verifier
registry[a.nullifier] = Identity(a.anchor, a.loa, _now(), _now());
sbt.mint(a.anchor, a.nullifier);
}
3.2 PersonhoodSBT (EIP-5484)
A non-transferable badge bound to the anchor Safe. It carries the LoA and timestamps; voting contracts read from it.
3.3 Resolving multiple wallets
- The SBT lives in one anchor Safe.
- Other wallets resolve to the nullifier: (a) by a signature from the anchor Safe (ERC-1271
LinkedWallets), or (b) via zk membership (they vote without revealing which they are — see §6). - Recovery = eID. Lost your anchor? Log in with Certilia again → the same nullifier →
migrateAnchor()to a new Safe. Your eID is your recovery.
4The eID → onchain bridge (pluggable verifier) — and why the mesh is not the MVP
_verify() is an abstraction with several implementations, chosen per phase:
| Verifier | How | Decentralisation | Phase |
|---|---|---|---|
| A · zkTLS over Certilia OIDC | The client proves (Reclaim/zkTLS) that the Certilia JWKS signed an id_token containing their ID number; the contract verifies the zk proof | No oracle network; relies on the Certilia PKI | MVP |
| B · NFC eID card chip | The client passively authenticates the chip issuer's signature (Rarimo/zkPassport style) and derives the nullifier locally | No oracle network; relies on the state PKI | MVP alt. |
| C · EIP-712 attestation oracle | An off-chain verifier validates the id_token (JWKS/iss/aud) and signs {nullifier,anchor,loa}; the contract checks the signer | A single signer = centralised | Transitional |
| D · M-of-N Android verifier mesh | Like C, but M independent Android nodes (StrongBox + Key Attestation) co-sign | High — nobody mints alone | Phase 2 |
If you do build the mesh (Phase 2): consider Acurast as a SUBSTRATE rather than building from scratch. Acurast processors (250k+ phones) have their own EVM address, a code-bound hardware key, hardware attestation, and can sign/settle onchain. M-of-N Safe co-signing is custom logic on top of Acurast — it turns "buy and run phones" into "deploy a custom verifier onto an existing network".
5Verifier network (Phase 2): a geolocated Android signer mesh
The design is retained because it delivers strong decentralisation of trust; it is not the MVP.
- Signer-only, no execution layer. The phones connect read-only to a Gnosis RPC; they hold no chain state → no expensive hardware or SSDs. Their role = offline M-of-N co-signers of a Safe multisig.
- Execution. A relayer pays gas and submits the pre-signed
execTransaction, or each phone holds a little xDAI so the "last signer in the round" is an independent executor. The relayer is never an owner → it cannot forge. - Hardware root. A StrongBox/TEE key + Android Key Attestation (the certificate chain proves the key never left a certified secure element).
- DAO governance. The airKUNA DAO (a Safe multisig) approves new nodes; statuses:
pending → active → offline → ejected. A known human operator per node. - Geolocation & anti-spoofing. Nodes are shown on a map (MapLibre). GPS spoofing is penalised by a staking/slashing economy (GEODNET/XYO proof-of-location style).
6Privacy and voting
- Transparent voting (associations, public identities): a plain SBT + nullifier is enough.
- Anonymous voting: MACI / Semaphore — a zk proof of membership in the set of verified citizens + a per-poll nullifier
H(secret, pollId)prevents double voting without linking wallets; MACI adds receipt-freeness (resistance to vote buying). The chain never learns "this Safe = that citizen".
7GDPR / compliance
- The raw ID number never goes onchain or into a plaintext database. Only the
nullifier(irreversible) goes onchain. - If the backend briefly sees the ID number (verifier C/D), it hashes it immediately and discards it; encryption at rest (pgcrypto).
- It matches the eIDAS principles of data minimisation / selective disclosure → an advantage with the regulator and in grant applications.
- ITalk = a non-custodial software provider; regulated functions (eID issuance, KYC) are performed by licensed parties (AKD/Certilia, later EUDI).
8Positioning vs prior art
The full stack does not exist as a single product, but the components have strong prior art (Acurast, Lit, Rarimo/zkPassport, GEODNET, Reclaim/zkTLS, EBSI). Confirmed in research: "live eID-OIDC → onchain SBT via a decentralised verifier network" is genuinely unoccupied space. Our differentiation is not a patent but:
- A Certilia/EUDI (Croatian/EU eID) root — not a passport, not biometrics; eIDAS High LoA. This is the core of the novelty.
- A Gnosis-native composable personhood SBT — a public chain, DeFi/DAO-composable (unlike the permissioned EBSI).
- Nullifier registry + zk = the same family as World ID (a proven pattern); the difference is the source, not the mechanism.
- First mover in Croatia + integration with the existing airKUNA/domovina stack (pay/sms/map).
9Open source & funding
- Open-source contracts + verifier node + documentation; ITalk leads development that everyone can use.
- EU NGI Pilots (cascade) — a realistic first entry: capped at ~€60,000 per recipient, with NO consortium required.
- Digital Europe WALLET (~€129.6M) / MDL (~€77M) for EUDI — bigger money, but via consortia and LSPs (POTENTIAL/EWC/NOBID/DC4EU).
- Crypto-native complement: Gnosis/GnosisDAO ecosystem grants, Optimism RetroPGF / Octant / Gitcoin.
10Roadmap
| Phase | Deliverable |
|---|---|
| 0 — MVP | IdentityRegistry + PersonhoodSBT + verifier A (zkTLS/Certilia) or B (NFC eID); mock issuer/verifier locally |
| 1 | A second independent source (phone-SBT via sms.domovina.ai reverse-OTP) + credibility score; node map |
| 2 | M-of-N Android verifier mesh (M separate EIP-712 signers, not MPC) + DAO onboarding + statuses + slashing |
| 3 | Social attestation (web-of-trust score) |
| 4 | zk anonymous voting (MACI/Semaphore) |
| 5 | EUDI Wallet as a source (SD-JWT VC/mDoc over OpenID4VP) — pan-EU |
11Open questions / risks
- Whether the mesh is necessary — research strongly suggests A/B deliver ~90% of the value without it; prove this on the MVP before building D.
- zkTLS maturity for the Certilia OIDC endpoint (a custom flow through a proxy).
- Pepper governance — who holds the
pepper? If it leaks, nullifiers can be brute-force correlated with ID numbers (a space of ~10¹¹) → the pepper must sit in threshold/HSM custody, or be rotated per epoch. - Google as root of trust — Android Key Attestation roots in Google → the mesh is trust-minimised, not trustless; acknowledge this in every pitch.
- The eID card over NFC — does the Croatian eID card support passive chip authentication the way a passport does? (To be checked.)
- FTO risk (nChain US 11,347,838 B2) — a voting-identity patent; an FTO opinion before commercialisation.
Appendix: ADR base
airKUNA maintains its own ADR base (docs/decisions/, starting at 0001):
- 0001 — nullifier registry vs per-wallet SBT (uniqueness at the person level).
- 0002 — pluggable verifier (A zkTLS / B NFC eID / C EIP-712 oracle / D Android mesh); MVP = A/B, mesh = Phase 2.
- 0003 — pepper custody (threshold/HSM, rotation).