Skip to content

Commit

Permalink
feat(revamp-docs) - sort out versioning and default /docs to v1 docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 committed Dec 11, 2023
1 parent dbf5008 commit 46181a9
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 43 deletions.
39 changes: 0 additions & 39 deletions website/sidebars.ts

This file was deleted.

141 changes: 141 additions & 0 deletions website/versioned_docs/version-v0.x/quadratic_vote_tallying_circuit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# The quadratic vote tallying circuit

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Inputs](#inputs)
- [Circuit pseudocode](#circuit-pseudocode)
- [Circuit failure modes](#circuit-failure-modes)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Quadratic voting is one of many types of vote tallying mechanisms. We chose it for the first version of MACI due to the high amount of interest that the community has shown for it.

Quadratic voting allows users to express the strength of their preferences when they vote for options. Since users are allocated a limited number of _voice credits_, and the number of tallied votes per option is the square root of the number of voice credits spent on said option, quadratic voting [over-privileges neither concentrated nor diffuse interests](https://www.vitalik.ca/general/2019/12/07/quadratic.html).

For instance, if a user has 99 voice credits, they may spend them this way (each row represents a command):

| Option | Voice credits spent |
| ------ | ------------------- |
| A | 1 |
| A | 9 |
| B | 25 |
| C | 64 |

The outcome is as such:

| Option | Tallied votes |
| ------ | ------------- |
| A | 3.16 |
| B | 5 |
| C | 8 |

Even though the user has a disproportionate preference for option C (64 voice credits), their impact on the tallied vote (8 votes) is merely the square root of the voice credits they have spent. This prevents them from having an outsized influence on the results simply by virtue of their willingness to spend as many voice credits on that option as they had.

Additionally, we consider that votes are cumulative. This means that the user spent 10 voice credits on option A.

The MACI contract's `quadraticVoteTally()` function should verify a proof created using this circuit to compute the results of tallying a set of state leaves. This also proves that these state leaves have an intermediate root `A`, as well that `A` is part of the tree with final state root `R`. This allows the coordinator to prove the final tally in batches. The function keeps track of the index of each intermediate root to ensure that they are processed consecutively.

## Inputs

| Pseudocode name | zk-SNARK input type | Description | Set by |
| ----------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------- |
| `fullStateRoot` | Public | The final Merkle root of the state tree | Contract |
| `fullStateTreeDepth` | Hardcoded | The depth of the state tree | Contract |
| `intermediateStateTreeDepth` | Hardcoded | The depth of the intermediate state tree | Contract |
| `intermediateStateRoot` | Public | The intermediate Merkle root generated by the given state leaves | Contract |
| `intermediatePathElements[k]` | Private | The Merkle path elements from `intermediateStateRoot` to `stateRoot`. | Coordinator |
| `intermediatePathIndex` | Public | The Merkle path index from `intermediateStateRoot` to `stateRoot`. | Contract |
| `currentResults[n]` | Private | The vote tally of all prior batches of state leaves | Coordinator |
| `currentResultsSalt` | Private | A random value to hash with the vote tally for state leaves up to the current batch | Coordinator |
| `currentResultsCommitment` | Public | The salted commitment of the values in `currentResults` | Contract |
| `newResultsCommitment` | Public | The salted commitment of the vote tally for this batch of leaves plus the vote tally from `currentResults` | Contract |
| `salt` | Private | A random value to hash with the culmulate vote tally for this batch of state leaves | Coordinator |
| `stateLeaves[m][p]` | Private | The batch of leaves of the state tree to tally. | Coordinator |
| `voteLeaves[m][n]` | Private | The vote leaves for each user in this batch of state leaves. | Coordinator |

`n` is the number of options in `voteOptionTree`.
`m` is the number of state leaves in this batch.
`k` is `fullStateTreeDepth - intermediateStateTreeDepth`
`p` is the message length

A result commitment is the hash of a Merkle root of all the vote leaves, and a salt. For instance:

```javascript
root = genTree(results);
hash(root, salt);
```

## Circuit pseudocode

```javascript
// Alice votes for party A with 16 credits
// Bob votes for party A with 9 credits

// Party A gets 7 tallied votes. NOT 5 votes.

// Ensure via a constraint that the intermediate root is the
// correct Merkle root of the stateLeaves passed into this
// snark
assert(intermediateStateRoot == genTree(stateLeaves))

// Ensure via a constraint that the intermediate root is part of the full state tree
var x = generateMerkleRoot(
intermediatePathElements,
intermediatePathIndex,
intermediateRoot
)

assert(x == stateRoot)

// This variable stores the sum of the square roots of each
// user's voice credits per option.
var computedResults = currentResults

var start = 1
if intermediatePathIndex > 0:
start = 0

// For each user
for i as start to m: // we ignore leaf 0 on purpose

// Ensure via a constraint that the voteLeaves for this
// user is correct (such that when each vote leaf is
// inserted into an MT, the Merkle root matches
// the `voteOptionTreeRoot` field of the state leaf)

var computedVoteOptionTreeRoot = genTree(voteLeaves[i])
assert(computedVoteOptionTreeRoot == stateLeaves[i].voteOptionTreeRoot)

// Calculate the sum of votes for each option
for j as 0 to n.
// This adds to the subtotal from previous batches
// of state leaves
computedResults[j] += voteLeaves[i][j]


// Ensure via a constraint that the commitment to the current results is
// correct

assert(
hash(genTree(currentResults), currentResultsSalt) ==
currentResultsCommitment
)

// Ensure via a constraint that the final result
// is correct
assert(
hash(genTree(computedResults), salt) ==
newResultsCommitment
)
```

where `genTree` is pseudocode for a circuit which computes a Merkle root from a list of leaves.

## Circuit failure modes

| Condition | Outcome |
| -------------------------------------------------------------------------------------------------- | ------------------------------ |
| Invalid state leaves and/or intermediate state root | No such proof can be generated |
| Invalid vote option leaves | No such proof can be generated |
| Invalid Merkle path to the full state root from the intermediate state root for the batch of votes | No such proof can be generated |
Loading

0 comments on commit 46181a9

Please sign in to comment.