1. What is Civic Polling

MINOMO Civic Polling is a tool for consulting the citizens of a municipality in a structured, anonymous and verifiable way. A poll is a multi-choice question, published by the municipal administration (mayor or their delegate) with a defined voting period. Resident citizens (registered on MINOMO and linked to that city) receive a notification and can vote with one tap from the app, with no forms to download and no re-authentication.

Who can create a poll

Only the mayor — or an officer delegated by them — of a municipality active in the MINOMO program. The appointment goes through our City Agent (territorial representative); there is no self-registration. One municipality = one "municipal_admin" account. The MINOMO SuperAdmin can step in as a backstop in case of technical issues but never edits content.

📋 Neither MINOMO nor the City Agent moderate poll content: the municipal administration is autonomous in wording, within the bounds of the law (DSA). Any illegal content is handled reactively via the DSA procedure, not pre-emptively.

2. Anonymity — how it works

Anonymity is enforced by a "split-model" architecture that separates "who participated" from "what they voted".

Table A — participation (transient)

When a citizen votes, a participation table records only the fact that they voted (to prevent double voting). No information about the choice they made.

Table B — aggregate (permanent)

At the same time, the counter for the chosen option is incremented in an aggregates table. No information about who voted for what.

🔒 On poll sealing (closure), Table A is atomically DELETED. From that moment on only the final per-option counter remains: reconstructing who voted for what is technically impossible because the data no longer exists in our systems.

Civic push notifications are also designed to leave no traces: they do not populate standard MINOMO logs, contain no tracking pixels, and include no recipient identifiers.

3. Voting — the citizen side

Who can vote

Citizens registered on MINOMO who have indicated their municipality as their "interest city" and who have opted in to the "Civic Voice" program in their account settings. Opt-in is revocable at any time — disabling it does not delete already cast votes, because those are already aggregated and anonymous.

How to vote

A push notification is sent at poll opening (and at mid-period if scheduled) to eligible voters' devices. Tapping the notification opens the vote card directly, with title, question and options. Tap the chosen option, confirm. That's it — no forms, no extra authentication.

You can vote only once per poll. The system verifies that the voter resides in the correct municipality, has opted in, and has not already voted. All checks are server-side and results stay hidden until the poll closes.

4. Closing certificate

When the poll closes, the system produces a signed certificate that captures the result. This certificate is the official document of the poll and contains exclusively aggregated data.

What the certificate contains

  • Poll identifiers (UUID, city, period, issuing mayor)
  • Question and options in the 3 MINOMO languages
  • Vote count for each option (including abstain, if present)
  • Total participants and total votes
  • Applied k-anonymity threshold
  • Sealing date and time

What it does NOT contain

  • No voter identity (data has already been deleted at sealing)
  • No per-vote timestamp (only poll open/close/seal as a whole)
  • No information about how subgroups voted (district, age range, etc.) — only the per-option total

5. Cryptographic signature and Merkle tree

Ed25519 signature

The certificate is signed with an Ed25519 private key (modern, widely standardized algorithm — RFC 8032). The matching public key is published at minomo.io/civic/verify/public-key. Anyone can verify the signature with standard open-source tools (libsodium, noble-ed25519, etc.). Key rotation is supported: each certificate indicates which "public_key_id" was used.

Merkle root

In addition to the signature, a Merkle root is computed over the aggregated data following the RFC 6962 standard (domain separation with 0x00 prefix for leaves and 0x01 for nodes). This allows verifying individual elements (e.g. the count for a specific option) without reconstructing the whole certificate — useful for selective audit scenarios.

6. Bitcoin time anchoring (OpenTimestamps)

The Ed25519 signature proves the authenticity of the certificate (it was issued by MINOMO using a known key). But it does not prove when: in theory MINOMO could later re-broadcast a forged certificate with a manipulated timestamp.

To address this, every certificate is "anchored" to the Bitcoin blockchain via the open OpenTimestamps protocol. In practice, the SHA-256 hash of the certificate is included (alongside millions of other hashes worldwide) in a public Merkle tree which is anchored to a Bitcoin block. The Bitcoin block is confirmed by thousands of independent miners within hours.

Once confirmed, the anchor proves that the certificate existed in exactly that form before Bitcoin block N. Modifying the certificate afterwards would require "rewriting" the Bitcoin blockchain — an operation that would require more computing power than the entire global network combined.

OpenTimestamps is free and used worldwide for time certification. MINOMO pays nothing to use it, and neither do you to verify it.

7. Decentralized availability (IPFS)

Even though signature + Bitcoin anchoring guarantee authenticity and temporal order, one problem remained: where is the certificate kept? If MINOMO shut down, certificates hosted only on our servers would become unreachable.

That is why every certificate is also published on IPFS (Inter-Planetary File System), the peer-to-peer content-addressed storage network. On IPFS a file is identified by its cryptographic hash (CID): anyone with the CID can retrieve that file from any IPFS node that keeps it.

We publish every certificate on at least 2 independent mirrors: our self-hosted IPFS node (for control + GC) + a mirror on Pinata (commercial free tier, external redundancy). If MINOMO shut down, the certificate would remain accessible as long as at least one node in the world keeps it.

On the verification page you will find direct links to 4 public gateways to download the certificate without installing anything (ipfs.io, cloudflare-ipfs.com, dweb.link, gateway.pinata.cloud). They are standard HTTP URLs — just click.

8. What you can verify yourself

The whole system is designed so that you do not have to take MINOMO at its word. Here are the 4 independent verifications anyone can perform:

Browser verification (1 click)

Open the /verify/civic-poll/{uuid} page of a sealed poll and click "Verify now". Your browser recomputes Merkle, SHA-256 and verifies the Ed25519 signature against MINOMO's public key. No data is sent to us.

Offline verification with cert JSON

Download the cert.json file from the verify page. Using standard open-source libraries (Python pynacl, JavaScript noble-ed25519, Go ed25519, etc.) you can: compute SHA-256 hex of the canonical JSON → verify the signature → recompute the Merkle root. The values must match exactly.

OpenTimestamps verification

Download the cert.ots and cert.json files. Install opentimestamps-client (pip install opentimestamps-client). Run: ots verify -d <payload_sha256> cert-<uuid>.ots. The tool contacts the OpenTimestamps network and confirms whether the hash is anchored to a valid Bitcoin block (and which one).

pip install opentimestamps-client && ots verify -d <payload_sha256> cert-<uuid>.ots

IPFS verification (even with MINOMO offline)

Take the CID from the verify page. Open it via any public gateway: https://ipfs.io/ipfs/<CID>. Download the certificate. Compare it byte-for-byte with the cert.json downloaded from our server: they must be identical. If they are not, there is a serious inconsistency.