Code Monkey home page Code Monkey logo

caritat's Introduction

Caritat

The name comes from Marie Jean Antoine Nicolas de Caritat, Marquis of Condorcet, French philosopher and mathematician, notably known for championing an election method that now named after him.

The goal of this project is to allow organisations of people working remotely to cast votes is a secure and transparent way, using a git repository to collect and authenticate votes.

Usage

Participate to a vote using Caritat

Node.js CLI

Requires Node.js 16+ and git.

If the vote is setup on a GitHub pull request and you have gh locally installed and logged in to your GitHub account:

npx --package=@node-core/caritat-cli voteOnGitHub <pr-url>

Otherwise, you can specify the details manually:

npx --package=@node-core/caritat-cli voteUsingGit \
  --repo=<repo-url> --branch=<branch-name> \
  --path=<subfolder-where-the-vote-data-is-stored> \
  --handle=<your-github-handle>

Shell scripts

You can use one of the shell script from the sh/ folder. Requires openssl (LibreSSL CLI is not compatible) and git to be available on the local machine.

On a Unix-like OS:

sh/voteUsingGit.sh <your-github-handle> <repo-url> <branch-name> <subfolder-where-the-vote-data-is-stored>

On Windows:

sh/voteUsingGit.ps1 <your-github-handle> <repo-url> <branch-name> <subfolder-where-the-vote-data-is-stored>

Web UI

Only works for vote that are hosted on a GitHub pull request.

Visit https://nodejs.github.io/caritat/, paste the URL of the pull request, and create the JSON file containing your encrypted ballot using GitHub web UI.

Setup a vote using Caritat

Node.js script

npx --package=@node-core/caritat-cli generateNewVoteFolder \
 --repo "<repo-url>" --branch "<new-vote-branch-name>" \
 --directory "<relative-path-to-new-vote-folder>" \
 --subject "Vote subject" \
 --candidate "Candidate 1" --candidate "etc." \
 --allowed-voter "[email protected]" --allowed-voter "[email protected]" \
 --shareholder "[email protected]" --shareholder "[email protected]" \
 --shareholders-threshold 2

Shell script / git-less setup

Requires openssl (LibreSSL CLI is not compatible), gpg, and node. Use the sh/generateNewVoteFolder.sh script.

sh/generateNewVoteFolder.sh <path-to-dir>

This will generate three files that will be used to let participants vote. You can then commit those files and push this to a new branch (optionally open the vote pull request). If you are participating to that vote yourself, you should cast your vote right away using one of the methods described above.

Using the API

You can build your own CLI to interface with Caritat so it's more fitted to your use-case and is more user-friendly.

Since we are using TypeScript, please rely on the type definition for documentation on how to use the API.

FAQ

Who do I need to trust?

  • As a Voter, you need to trust the Vote Instigator for:
    • using a reliable hardware and software to generate the Vote Private Key and encrypt it, and to not store it anywhere.
    • not leaking the Vote Private Key before the vote closes if they have kept it.
    • not basing their vote in function of what other has voted (having the instigator always vote first helps alleviate this issue).
  • As a Voter, you need to trust the panel of Secret Holders for:
    • not reconstitue the Vote Private Key before the vote closes.
    • not leaking the Vote Private Key before the vote closes (if they have reconstructed it, which they should not do).
    • not basing their vote in function of what other has voted (if they have reconstructed the Vote Private Key, which they should not do).
  • As a Voter or the Vote Instigator, you need to trust the git commits are genuine, and therefor you need to trust that the server hosting the vote repository is not compromised.

Can a participant tamper with the votes?

When using git, one could force push (or otherwise alter the git tree if they have direct access to the server) the branch and remove or modify ballots from other participants. Adding protection on the branch on which the vote is happening can help prevent this.

When voting using this tool, are my choices public?

Ballots are encrypted using a public key generated for the vote, only someone in possession for the Vote Private Key is theoretically able to decipher the ballot. Typically, no one should be in possession of the Vote Prive Key (although there is no way of ensuring that, see "Who do I need to trust?" section) until the vote closes. Unless the vote needs to stay private, a recommended practice is to publish the Vote Private Key, effectively making everyone's choices public.

Making the non-encrypted ballot available publicly is a great way to ensure the election was not rigged. Everyone can check that the ballot counted as their has not been altered and that the result adds up. It's still possible to not make them public (to keep the vote anonymous), but that requires to trust a single authority (the Vote Instigator).

How is a vote initialized?

When setting up the vote, the Vote Instigator creates the following keys:

  • the Vote Private Key (RSA 2048 bits)
  • the Vote Public Key (derived from the Vote Private Key)
  • the Vote Secret (a random binary string)
  • the Vote Secret Key Parts (derived from the Vote Secret, as many key parts as there are Secret Holders)

Then a vote.yml file is created:

  • the Vote Public Key,
  • the Vote Private Key encrypted using the Vote Secret,
  • the Vote Secret Key Parts encrypted using PGP (each key part is encrypted using Secret Holder public key),
  • a list of candidates (only those candidates are allowed in a ballot),
  • a list of allowed Voters,
  • a vote subject, header and footer instructions to give more context to the voter directly in the ballot,
  • the method to count the ballots (only Condorcet is supported at the time of writing),
  • miscellaneous vote options, such as canShuffleCandidates.

The Vote Instigator pushes to a newly created vote branch (when using git) the vote.yml, as well as a file containing the public key and a ballot example. The two other files can be used to vote without parsing the YAML file.

Why are the ballots encrypted?

Encrypting the ballot is necessary to ensure people voting early do not interfere or influence folks voting after them. At the end of the vote, the the Vote Private Key can be made public, so anyone can decrypt the ballots and verify the result themself. Or it can decided that the Vote Private Key won't be shared in order to keep the votes anonymous, and a large enough panel of Secret Holders (depending on the vote settings) need to share their key parts, decrypt the ballots, and share the vote result without disclosing the content of the ballots.

What's inside an encrypted ballot?

An encrypted ballot is a JSON object which contains at least two keys:

  • encryptedSecret: the Ballot Secret encrypted using the Vote Public Key.
  • data: the YAML ballot, encrypted using the Ballot Secret.

There could be other keys in that JSON object, they will be ignored.

How are the votes authenticated?

Voters can sign their commit using PGP. When doing the counting, the system uses the git commit metadata to attribute a ballot to a voter. If a voter casts several ballots, the system only counts the most recent one.

What happens if the Secret Holders lose their key parts?

The vote ballots cannot be deciphered, the process needs to start again (unless you have a quantum computer at home to break the RSA encryption).

Could this tool used for any elections?

The license makes no restrictions on how this tool should be used, but keep in mind that, as any electronic voting system, it can only be trusted as long as the unanonymized vote ballots are made public as soon as the vote closes, which may or may not be OK depending on the type of election you are using this for.

caritat's People

Contributors

aduh95 avatar github-actions[bot] avatar molow avatar stduhpf avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

caritat's Issues

Winning candidates should be displayed as a list

In the markdown preview, the winning candidates should be displayed as a markdown list if there are more than one of them. A comma separated list as it is today creates problem if the candidate themselves contain commas, or if they are quite long.

Expected results

**Winning candidate(s)**:

 - Option Z
 - Option X

Actual results

**Winning candidate(s)**: Option Z, Option X

Initial pull request message improvements

I'm not sure this project is the right place to open the issue. Sorry if the message is generated elsewhere.
I'm taking this message as a reference: nodejs/TSC#1225 (comment)

  1. When I voted, I didn't think that a readable version of the voting options was available in the first commit, so I thought that I had to start the process to know what the options were. My suggestion would be to add the list of options to the pull request description, before listing the different voting methods.
  2. That may be more difficult to handle here, but I think it's important to make sure that all people how are allowed to vote are aware that a vote started. In the case of the Node.js TSC, I would add a ping of the @nodejs/tsc GitHub team to the pull request description.

`Encrypt ballot` produces an error message in the web ui

After filling https://stduhpf.github.io/caritat/#https://github.com/nodejs/TSC/pull/1158 with all my details, when I click on Encrypt ballot, an error message shows up at the bottom of the page:

An error occured: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

I noticed this only after I committed the faulty vote I reported in #3, not sure if it happens otherwise.

Writing to `ballot.yml` fails with a permission denied error

System info:

$ uname -a
Darwin Darshans-MacBook-Pro.local 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:54 PST 2021; root:xnu-8019.61.5~1/RELEASE_X86_64 x86_64
$ openssl version
OpenSSL 3.0.1 14 Dec 2021 (Library: OpenSSL 3.0.1 14 Dec 2021)

Logs:

$ sh ./voteUsingGit.sh \
  RaisinTen \
  [email protected]:nodejs/TSC.git \
  vote-primordials-error-path \
  votes/primordials-error-path
Cloning into '.'...
remote: Enumerating objects: 304, done.
remote: Counting objects: 100% (304/304), done.
remote: Compressing objects: 100% (295/295), done.
remote: Total 304 (delta 12), reused 162 (delta 7), pack-reused 0
Receiving objects: 100% (304/304), 2.23 MiB | 2.40 MiB/s, done.
Resolving deltas: 100% (12/12), done.
./voteUsingGit.sh: line 20: /var/folders/1s/mr6_sxdx0_59tj0xq5qzt_z00000gn/T/tmp.u5ibUVMK/votes/primordials-error-path/ballot.yml: Permission denied
./voteUsingGit.sh: line 23: /Users/raisinten/Desktop/temp/project/sh/encryptBallot.sh: No such file or directory
[vote-primordials-error-path 1466e68] vote from RaisinTen
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 votes/primordials-error-path/RaisinTen.json
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 1.03 KiB | 1.03 MiB/s, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To github.com:nodejs/TSC.git
   a619c98..1466e68  HEAD -> vote-primordials-error-path

This ends up committing and pushing an empty file.

Workaround:

I believe running with sudo should be a temporary fix for now.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.