This repository provides a prototype for a blockchain-based petition system.
The following components are included:
Web frontend for users.
Connects to an available wallet and generates IDP- and period-specific keys.
Can interact with a Registry contract to learn all details about the petition system in use.
Subsequently interacts with IDP and Petition contracts to generate valid signatures.
Identity Provider.
Identifies users and adds their public keys to a Merkle tree, which is periodically written to the blockchain.
Issues credentials to users in the form of Merkle proofs, enabling them to participate in petitions.
IDPs are trusted by definition: misbehavior by IDPs may result in (real or fake) users being able to vote multiple times.
If IDPs refuse to issue credentials, they can exclude users from participating in the system.
Once the Merkle tree is written to the blockchain and the corresponding proof is delivered, credentials can no longer be revoked by the IDPs.
IDPs cannot trace which petitions users have signed.
Smart contracts for data storage of IDP, Registry, and Petition.
This project uses ZoKrates to generate zero-knowledge proofs, which can verify the correct execution of programs written in the ZoKrates language (see below).
Time is divided into periods based on block timestamps.
The IDP contract defines the length of these periods.
All steps listed below must be executed anew for each voting period.
Each petition is strictly assigned to a single voting period.
-
Client -> (ID, K_pub) -> IDPID = [implementation-specific, e.g., SSI- or eIDAS-based] K_priv = rnd() K_pub = PRF(K_priv)The IDP verifies:
IDhas not yet been identified for the current voting period (the ability to make multiple entries per ID and period equates to the ability to vote multiple times)
-
IDP -> (Merkle-Root incl. K_pub) -> IDP-SCIDP -> (Merkle-Proof, Index) -> ClientAt fixed intervals, the IDP generates a Merkle tree of verified identifiers. The root hash (
rt) is written to the blockchain, and the client receives a Merkle proof of the inclusion of theirK_puband the index at whichrtcan be retrieved from the blockchain. -
Client -> (H_pers, Index, ZK) -> Petition-SCThe client creates a hash from the petition ID and their private key.
rt = (IDP-SC).get(Index) H_pers = h(ID_Petition, K_priv) ZK = ZK-SNARK(public rt, public H_pers, public ID_Petition, private K_priv, private K_pub, private directionSelector, private merkleproof)The ZK proof verifies the following conditions:
K_pub = PRF(K_priv)(i.e.,K_privis known and is the pre-image ofK_pub)H_persis correctly computedrtcontainsK_pub(usingmerkleproof)
The Petition-SC verifies:
rtis retrievable from theIDPsmart contract at the given indexZKis validH_pershas not yet been included in the list of previous signatures
-
The total number of signatures corresponds to the size of the array of all
H_persfor the voting period.
A current version of nodejs is required.
Install the shared library (run in the shared folder):
npm install
In the platform folder
Install dependencies:
npm install
Start the development server:
npx hardhat node
Deploy the smart contracts:
npx hardhat run --network localhost scripts/deploy.ts
Add test petitions:
npx hardhat run --network localhost scripts/testpetitions.ts
In the idp folder
Install dependencies:
npm install
Configuration is currently done via constants in shared/addr.ts:
const port = 65535;
const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266';
const privkey = '0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0';
const api = 'ws://127.0.0.1:8545';
const contract = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
const databasefile = `/home/mhuens2m/build/petition/idp/dist/database.db`;
Start the ZK server:
npm run start -- --type zk --port 65530
Start the non-ZK server:
npm run start -- --type normal --port 65535
In the client folder
Install dependencies:
npm install
Start the Webpack development server:
npm run dev
Once the Webpack server is running, the client is available at http://localhost:8080 by default.
To use the system, a web3-compatible browser plugin such as MetaMask is required.
To access full functionality, the development blockchain must be added as a network.
By default, it is available at localhost:8545 and has the chain ID 31337.
To submit transactions, an account with cryptocurrency must be imported.
The corresponding private keys are printed when starting the blockchain development server (see "Smart Contract Platform").