From 29cf12ca76e7ab2c1c3b5b2dd1df4ef9b3da2d37 Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Tue, 21 May 2024 14:24:04 +0100 Subject: [PATCH] docs: split primitives into own files and update to latest changes --- .../versioned_docs/version-v1.2/circuits.md | 2 +- .../core-concepts/ballot.md | 19 ++ .../core-concepts/coordinator-processing.md | 2 +- .../core-concepts/hashing-and-encryption.md | 45 ++++ .../core-concepts/key-change.md | 4 +- .../core-concepts/maci-keys.md | 74 ++++++ .../core-concepts/maci-messages.md | 44 ++++ .../core-concepts/merkle-trees.md | 23 ++ .../core-concepts/poll-types.md | 6 +- .../core-concepts/primitives.md | 216 ------------------ .../version-v2.0_alpha/core-concepts/spec.md | 2 +- .../core-concepts/state-leaf.md | 42 ++++ .../zk-snark-circuits/circuits.md | 2 +- 13 files changed, 254 insertions(+), 227 deletions(-) create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/ballot.md create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/hashing-and-encryption.md create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/maci-keys.md create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/maci-messages.md create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/merkle-trees.md delete mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/primitives.md create mode 100644 website/versioned_docs/version-v2.0_alpha/core-concepts/state-leaf.md diff --git a/website/versioned_docs/version-v1.2/circuits.md b/website/versioned_docs/version-v1.2/circuits.md index e95b2c13eb..9fc4abad40 100644 --- a/website/versioned_docs/version-v1.2/circuits.md +++ b/website/versioned_docs/version-v1.2/circuits.md @@ -241,7 +241,7 @@ The hash is computed using the `sha256` Solidity function and is then subject to | 4th 50 bits | `numSignUps` | | 5th 50 bits | `batchStartIndex` | -`numSignUps`, a value provided by the contract, is the number of users who have signed up. This is one less than the number of leaves inserted in the state tree (since the 0th state leaf is a [blank state leaf](/docs/core-concepts/primitives#state-leaf)). `batchStartIndex` is the ballot tree index at which the batch begins. +`numSignUps`, a value provided by the contract, is the number of users who have signed up. This is one less than the number of leaves inserted in the state tree (since the 0th state leaf is a blank state leaf). `batchStartIndex` is the ballot tree index at which the batch begins. For instance, if `numSignUps` is 25 and the batch index is `5`, and all other values are 0, the following is the `packedVals` representation in hexadecimal: diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/ballot.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/ballot.md new file mode 100644 index 0000000000..461e4a6a1c --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/ballot.md @@ -0,0 +1,19 @@ +--- +title: MACI Ballot +description: A short introduction of the main primitives used by MACI +sidebar_label: MACI Ballot +sidebar_position: 4 +--- + +A Ballot represents a particular user's votes in a poll, as well as their next valid nonce. It is akin to a voting slip, which belongs to only one voter and contains a list of their choices. + +| Symbol | Name | Comments | +| --------- | -------------------------- | -------------------------------------------------------------------------- | +| $blt_{v}$ | An array of vote weights | $blt_{v[i]}$ refers to the vote weights assigned to vote option $i$ | +| $blt_n$ | The current nonce | Starts from 0 and increments, so the first valid command must have nonce 1 | +| $blt_d$ | The vote option tree depth | The depth of the vote option tree | + +The hash $blt$ is computed as such: + +1. Compute the Merkle root of $blt_v$, arity 5, of a tree of depth $blt_d$; let this value be $blt_r$ +2. Compute $poseidon_2([blt_n, blt_r])$ diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/coordinator-processing.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/coordinator-processing.md index cf18101521..f1c06310da 100644 --- a/website/versioned_docs/version-v2.0_alpha/core-concepts/coordinator-processing.md +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/coordinator-processing.md @@ -2,7 +2,7 @@ title: Coordinator local processing description: How does the coordinator process and tally messages locally sidebar_label: Coordinator local processing -sidebar_position: 3 +sidebar_position: 7 --- # Coordinator local processing diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/hashing-and-encryption.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/hashing-and-encryption.md new file mode 100644 index 0000000000..74b33a913c --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/hashing-and-encryption.md @@ -0,0 +1,45 @@ +--- +title: Hashing and Encryption +description: A short introduction of the main primitives used by MACI +sidebar_label: Hashing and Encryption +sidebar_position: 2 +--- + +### Hash Functions + +MACI uses the Poseidon hash function, which is proven to be very efficient in ZK applications. Poseidon accepts $n$ inputs and produces 1 output: + +$y = poseidon_n([x_1, x_2, ..., x_n])$ + +Also, SHA256 is used to compress public inputs to a circuit into a single field element in the finite field $F$ mod $p$. + +### Message Encryption + +In order to encrypt messages, MACI uses Poseidon in DuplexSponge [mode](https://dusk.network/uploads/Encryption-with-Poseidon.pdf). This provides an encryption function and a decryption function: + +- $C$ as $poseidonEncrypt(k_s[0], k_s[1], N, l, t[])$ +- $poseidonDecrypt(k_s[0], k_s[1], N, l, C)$ + +In more details, + +- $k_s$ is the shared key, a point on the Baby Jubjub curve +- $N$ is the nonce, which we hardcode to 0 +- $l$ is the length of the plaintext $t[]$ + +The implementation can be found [here](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/poseidon-cipher). + +### Shared Key Generation + +The ECDH algorithm is used to generate a shared key, which is then used to encrypt each message. This allows to create messages which are only decryptable by the coordinator and the person sending the message. + +In more details: + +- The coordinator's public key $cPk$ is known to all. Their private key $cSk$ is secret. + +- When the user publishes a message (i.e. casts a vote), they generate an ephemeral keypair with private key $eSk$ and public key $ePk$. + +- The user generates the shared key $k$ using the coordinator's public key $cPk$ and the user's ephemeral private key $eSk$. + +- The user encrypts the command and signature with $k$ to form a message. + +- The user sends their ephemeral public key $ePk$ along with the ciphertext. The coordinator can recover the same shared key using their private key $cSk$ and the given ephemeral public key $ePk$. diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/key-change.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/key-change.md index 3ce52196c2..f7d2c3098d 100644 --- a/website/versioned_docs/version-v2.0_alpha/core-concepts/key-change.md +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/key-change.md @@ -2,11 +2,9 @@ title: MACI key change description: How key change messages work sidebar_label: Key change -sidebar_position: 4 +sidebar_position: 8 --- -# MACI Key Change - MACI's voters are identified by their MACI public key. Together with their private key, they can sign and submit messages to live Polls. As MACI's main property is to provide collusion resistance in digital voting applications, it is important to have a mechanism for a user to change their voting key, should this become compromised, or they wish to revoke past actions. diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-keys.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-keys.md new file mode 100644 index 0000000000..6af2d72403 --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-keys.md @@ -0,0 +1,74 @@ +--- +title: MACI Keys +description: A short introduction of MACI's keys +sidebar_label: Maci Keys +sidebar_position: 1 +--- + +## Elliptic Curves + +MACI uses the Baby Jubjub Elliptic [Curve](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf). The `p` scalar field of choosing is: + +$p=21888242871839275222246405745257275088548364400416034343698204186575808495617$ + +with generator: + +$995203441582195749578291179787384436505546430278305826713579947235728471134$ +$5472060717959818805561601436314318772137091100104008585924551046643952123905$ + +and within the finite field with modulo $p$. + +## Key Pairs + +MACI uses Node.js's `crypto.randomBytes(32)` function to generate a cryptographically strong pseudorandom 32-byte value. This value is the seed used to generate a maci public key. A public key is a point on the Baby Jubjub [curve](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf), which is deterministically derived from a private key `s`. + +A public key is generated with the following function from [zk-kit](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/eddsa-poseidon/src/eddsa-poseidon.ts#L75): + +```ts +export function derivePublicKey(privateKey: Buffer | Uint8Array | string): Point { + const s = deriveSecretScalar(privateKey); + + return mulPointEscalar(Base8, s); +} +``` + +In more details, the function does the following: + +1. Derive a scalar value from the seed (private key). + +```ts +export function deriveSecretScalar(privateKey: Buffer | Uint8Array | string): bigint { + // Convert the private key to buffer. + privateKey = checkPrivateKey(privateKey); + + let hash = blake(privateKey); + + hash = hash.slice(0, 32); + hash = pruneBuffer(hash); + + return scalar.shiftRight(leBufferToBigInt(hash), BigInt(3)) % subOrder; +} +``` + +2. Perform a scalar multiplication of the base point `Base8` with the scalar value `s`. + +Now we have a public key, which is a point on the Baby Jubjub curve. In TypeScript, this is an array of two bigint values, representing the x and y coordinates of the point. + +## Serialization + +In order to easily store and transmit maci keys, these are serialized to a string. + +A public key if first packed, then converted to a hex string. This string is then prefixed with `macipk.`. + +For private keys (well the seed really), the value is converted to a hex string, padded to be of 64 characters, and prefixed with `macisk.`. + +For instance, given a seed of `27514007781052885036162808648019893362811628316940391612960868886926452498447`, we have a public key of: + +```json +{ + "x": 7849177681360672621257726786949079749092629607596162839195961972852243798387, + "y": 6476520406570543146511284735472598280851241629796745672331248892171436291770 +} +``` + +Serialized, these will look like **macipk.0e5194a54562ea4d440ac6a0049a41d4b600e3eb0bf54486e7a5f7e27521f6ba** and **macisk.3cd46064ea59936f82efb384059dd4f5b6b8e5c7546614caf7c1c3be0daea00f**. diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-messages.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-messages.md new file mode 100644 index 0000000000..f00f7ac18a --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/maci-messages.md @@ -0,0 +1,44 @@ +--- +title: MACI Commands and Messages +description: A short introduction of MACI's commands and messages +sidebar_label: MACI Commands and Messages +sidebar_position: 3 +--- + +## Command + +A command represents an action that a user may take, such as casting a vote in a poll or changing their public key if bribed. It is made up of the following parameters: + +| Symbol | Name | Size | Description | +| ------------ | ----------------------- | ---- | --------------------------------------------------------------------------------------------------- | +| $cm_i$ | State index | 50 | State leaf index where the signing key is located | +| $cm_{p_{x}}$ | Public key x-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's x-coordinate | +| $cm_{p_{y}}$ | Public key y-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's y-coordinate | +| $cm_{i_{v}}$ | Vote option index | 50 | Option state leaf index of preference to assign the vote for | +| $cm_w$ | Voting weight | 50 | Voice credit balance allocation, this is an arbitrary value dependent on a user's available credits | +| $cm_n$ | Nonce | 50 | State leaf's index of actions committed plus one | +| $cm_{id}$ | Poll id | 50 | The poll's identifier to cast in regard to | +| $cm_s$ | Salt | 253 | An entropy value to inhibit brute force attacks | + +## Message + +A message is an encrypted command using the shared key $k_s$ between the voter and the coordinator. The plaintext $t$ is computed as such: + +$t = [p, cm_{p_{x}}, cm_{p_{y}}, cm_s, R8[0], R8[1], S]$ + +While the message can be computed with the formula below: + +$M$ = ${poseidonEncrypt}(k_s[0], k_s[1], cm_n, 7, t)$ + +### Decrypting a message + +To decrypt a message using $k_s$ we have the following: + +$[p, R8[0], R8[1], cm_s]$ = ${poseidonDecrypt}(M, k_s[0], k_s[1], cm_n, 7)$ + +To unpack $p$ to its original five parameters, it must be separated into 50 bit values from the parent 250 bit value. To extract 50 bits at byte $n$, we: + +1. initialise 50 bits +2. shift left by $n$ bits +3. bitwise AND with $p$ +4. shift right by $n$ bits diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/merkle-trees.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/merkle-trees.md new file mode 100644 index 0000000000..edac990b95 --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/merkle-trees.md @@ -0,0 +1,23 @@ +--- +title: Merkle Trees +description: A short introduction of the main primitives used by MACI +sidebar_label: Merkle Trees +sidebar_position: 5 +--- + +MACI uses different types of merkle trees to store and manage data. On chain, a [LazyIMT](https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/lazy-imt) is used to store user's state leaves, and an [AccQueue](https://github.com/privacy-scaling-explorations/maci/blob/dev/contracts/contracts/trees/AccQueue.sol) to store user's messages. + +## Accumulator queue + +This contract holds [messages](docs/developers-references/smart-contracts/Poll#publishmessage) sent by users. When a leaf is inserted into the `AccQueue`, the merkle root is not updated yet, instead the leaf is updated or the root of a subtree is re-computed. The smart contract exposes three functions: + +- `enqueue(leaf)`: Enqueues a leaf into a subtree + four out of five times it is invoked, an enqueue operation may or may not require the contract to perform a hash function. When it does, only up to $t_d$ required number of hashes need to be computed +- `mergeSubRoots()`: Merge all subtree roots into the shortest possible Merkle tree to fit + Before computing the main Merkle root, it is necessary to compute the smallSRTroot (the smallest subroot tree root). This is the Merkle root of a tree which is small enough to fit all the subroots + function which allows the coordinator to specify the number of queue operations to execute. The entire tree may be merged in a single transaction, or it may not. +- `merge()`: Calculate the Merkle root of all the leaves at height $d_t$ + +## LazyIMT + +A LazyIMT is a Merkle tree that is updated lazily. It is used to [store the state leaves](/docs/developers-references/smart-contracts/MACI#signup) of the users. The "lazy" tree performs the minimum number of hashes necessary to insert elements in a tree. This means if there is only a left element the parent hash is not calculated until a corresponding right element exists, to avoid having an intermediate hash that will change in the future. This tree is designed for roots that are infrequently accessed onchain. diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/poll-types.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/poll-types.md index 27c5f0e2f3..34090a11a8 100644 --- a/website/versioned_docs/version-v2.0_alpha/core-concepts/poll-types.md +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/poll-types.md @@ -2,11 +2,9 @@ title: MACI Poll Types description: Which type of polls you can run on MACI sidebar_label: MACI poll types -sidebar_position: 21 +sidebar_position: 9 --- -# MACI Poll Types - MACI allows to conduct polls in both a quadratic voting and non quadratic voting fashion. One should be aware that the only distinction between the two happens when messages are processed and votes tallied. On top of that, the Tally smart contract has been split into two different ones, with the non quadratic voting version one being slightly smaller, due to the need of one less function. This document will explain how to use each of these options. @@ -15,7 +13,7 @@ This document will explain how to use each of these options. MACI has always worked with quadratic voting. Users signing up to MACI are assigned a number of voice credits based on certain conditions (enforced by the [initial voice credit proxy contract](https://github.com/privacy-scaling-explorations/maci/blob/dev/contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol)), and after each vote, the number of voice credits is reduced by the square of the weight of the vote casted. For instance, if the vote weight is 5, a user must have at least 25 voice credits to cast the vote. -To run a poll with quadratic voting, the coordinator must set the `useQuadraticVoting` parameter to `true` when creating the MACI instance. This will make the MACI instance use the `Tally` smart contract, which is the one that has been used since the beginning of MACI. +To run a poll with quadratic voting, the coordinator must deploy the Poll with the mode set to quadratic voting. Using MACI's cli, one can create a MACI instance with quadratic voting by running the following command: diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/primitives.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/primitives.md deleted file mode 100644 index 01d7e77419..0000000000 --- a/website/versioned_docs/version-v2.0_alpha/core-concepts/primitives.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: MACI Primitives -description: A short introduction of the main primitives used by MACI -sidebar_label: Primitives -sidebar_position: 1 ---- - -## MACI primitives - -This section provides a short introduction to the main primitives used by MACI. - -### Elliptic Curves - -MACI uses the Baby Jubjub Elliptic [Curve](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf). The `p` scalar field of choosing is: - -$p=21888242871839275222246405745257275088548364400416034343698204186575808495617$ - -with generator: - -$995203441582195749578291179787384436505546430278305826713579947235728471134$ -$5472060717959818805561601436314318772137091100104008585924551046643952123905$ - -and within the finite field with modulo $p$. - -### Key Pairs - -MACI uses Node.js's `crypto.randomBytes(32)` function to generate a cryptographically strong pseudorandom 32-byte value, as well as an algorithm to prevent modulo bias. In pseudocode this is: - -```python -lim = 2 ** 256 -min = lim - p -rand = null -while true: - rand = BigInt(crypto.getRandomBytes(32)) - if rand >= min: - break - -privKey = rand % p -``` - -A public key is a point on the Baby Jubjub [curve](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf), which is deterministically derived from a private key `s`. - -### Message Signing - -To sign messages, MACI uses the Edwards-curve Digital Signature Algorithm (EdDSA), implemented by [iden3](https://iden3-docs.readthedocs.io/en/latest/iden3_repos/research/publications/zkproof-standards-workshop-2/ed-dsa/ed-dsa.html#ed-dsa). - -### Hash Functions - -MACI uses the Poseidon hash function, which is proven to be very efficient in ZK applications. Poseidon accepts $n$ inputs and produces 1 output: - -$y = poseidon_n([x_1, x_2, ..., x_n])$ - -Also, SHA256 is used to compress public inputs to a circuit into a single field element in the finite field $F$ mod $p$. - -### Message Encryption - -In order to encrypt messages, MACI uses Poseidon in DuplexSponge [mode](https://dusk.network/uploads/Encryption-with-Poseidon.pdf). This provides an encryption function and a decryption function: - -- $C$ as $poseidonEncrypt(k_s[0], k_s[1], N, l, t[])$ -- $poseidonDecrypt(k_s[0], k_s[1], N, l, C)$ - -In more details, - -- $k_s$ is the shared key, a point on the Baby Jubjub curve -- $N$ is the nonce, which we hardcode to 0 -- $l$ is the length of the plaintext $t[]$ - -The implementation can be found [here](https://github.com/weijiekoh/circomlib/). - -### Shared Key Generation - -The ECDH algorithm is used to generate a shared key, which is then used to encrypt each message. This allows to create messages which are only decryptable by the coordinator and the person sending the message. - -In more details: - -- The coordinator's public key $cPk$ is known to all. Their private key $cSk$ is secret. - -- When the user publishes a message (i.e. casts a vote), they generate an ephemeral keypair with private key $eSk$ and public key $ePk$. - -- The user generates the shared key $k$ using the coordinator's public key $cPk$ and the user's ephemeral private key $eSk$. - -- The user encrypts the command and signature with $k$ to form a message. - -- The user sends their ephemeral public key $ePk$ along with the ciphertext. The coordinator can recover the same shared key using their private key $cSk$ and the given ephemeral public key $ePk$. - -### Merkle Trees - -Rather than using Binary merkle trees, MACI uses Quinary merkle trees (5 leaves per node). This allows for more gas efficient computation using the Poseidon hash function. - -#### Accumulator queue - -This contract holds user sign-ups and messages. When a leaf is inserted into the `AccQueue`, the merkle root is not updated yet, instead the leaf is updated or the root of a subtree is re-computed. The smart contract exposes three functions: - -- `enqueue(leaf)`: Enqueues a leaf into a subtree - four out of five times it is invoked, an enqueue operation may or may not require the contract to perform a hash function. When it does, only up to $t_d$ required number of hashes need to be computed -- `mergeSubRoots()`: Merge all subtree roots into the shortest possible Merkle tree to fit - Before computing the main Merkle root, it is necessary to compute the smallSRTroot (the smallest subroot tree root). This is the Merkle root of a tree which is small enough to fit all the subroots - function which allows the coordinator to specify the number of queue operations to execute. The entire tree may be merged in a single transaction, or it may not. -- `merge()`: Calculate the Merkle root of all the leaves at height $d_t$ - -### Domain Objects - -#### Verifying Keys - -A verifying key $vk$ is comprised of the following elements: - -1. $\alpha$, a point in the curve on which $G_1$ is defined -2. $$\beta$$, a point in the curve on which $G_2$ is defined -3. $\gamma$, a point in the curve on which $G_2$ is defined -4. $\delta$, a point in the curve on which $G_2$ is defined -5. $ic[]$, a list of points in the curve on which $G_1$ is defined - -A verifying key is used to validate a zk-SNARK proof. Each unique permutation of parameters to a particular circuit has a different verifying key. - -#### Private Keys - -MACI's private keys allow users to send and decrypt messages. This key translates to a scalar point on the Baby Jubjub elliptic curve. All keys are serialized with the prefix `macisk`. - -#### Public Keys - -Public keys also translate to a point on the Baby Jubjub elliptic curve, and is derived from the private key $k$. These are serialized with the prefix `macipk`. - -#### Key Pair - -A Key Pair is a private key and its corresponding public key. - -#### Command - -A command represents an action that a user may take. Such as casting a vote in a poll or changing their public key if bribed. It is made up of the following parameters: - -| Symbol | Name | Size | Description | -| ------------ | ----------------------- | ---- | --------------------------------------------------------------------------------------------------- | -| $cm_i$ | State index | 50 | State leaf index where the signing key is located | -| $cm_{p_{x}}$ | Public key x-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's x-coordinate | -| $cm_{p_{y}}$ | Public key y-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's y-coordinate | -| $cm_{i_{v}}$ | Vote option index | 50 | Option state leaf index of preference to assign the vote for | -| $cm_w$ | Voting weight | 50 | Voice credit balance allocation, this is an arbitrary value dependent on a user's available credits | -| $cm_n$ | Nonce | 50 | State leaf's index of actions committed plus one | -| $cm_{id}$ | Poll id | 50 | The poll's identifier to cast in regard to | -| $cm_s$ | Salt | 253 | An entropy value to inhibit brute force attacks | - -#### Message - -A message is an encrypted command using the shared key $k_s$ between the voter and the coordinator. The plaintext $t$ is computed as such: - -$t = [p, cm_{p_{x}}, cm_{p_{y}}, cm_s, R8[0], R8[1], S]$ - -While the message can be computed with the formula below: - -$M$ = ${poseidonEncrypt}(k_s[0], k_s[1], cm_n, 7, t)$ - -#### Decrypting a message - -To decrypt a message using $k_s$ is expressed as - -$[p, R8[0], R8[1], cm_s]$ = ${poseidonDecrypt}(M, k_s[0], k_s[1], cm_n, 7)$ - -To unpack $p$ to its original five parameters, it must be separated into 50 bit values from the parent 250 bit value. To extract 50 bits at byte $n$, we: - -1. initialise 50 bits -2. shift left by $n$ bits -3. bitwise AND with $p$ -4. shift right by $n$ bits - -### Ballot - -A Ballot represents a particular user's votes in a poll, as well as their next valid nonce. It is akin to a voting slip, which belongs to only one voter and contains a list of their choices. - -| Symbol | Name | Comments | -| --------- | -------------------------- | -------------------------------------------------------------------------- | -| $blt_{v}$ | An array of vote weights | $blt_{v[i]}$ refers to the vote weights assigned to vote option $i$ | -| $blt_n$ | The current nonce | Starts from 0 and increments, so the first valid command must have nonce 1 | -| $blt_d$ | The vote option tree depth | | - -The hash $blt$ is computed as such: - -1. Compute the Merkle root of $blt_v$, arity 5, of a tree of depth $blt_d$; let this value be $blt_r$ -2. Compute $poseidon_2([blt_n, blt_r])$ - -### State leaf - -A state leaf represents a user's participation declared through an identity (their public key) and information relevant to their ability or right to cast votes in a poll (their voice credit balance and the block timestamp at which they signed up). - -We define a state leaf $sl$ as the $poseidon_4$ hash of the following: - -| Symbol | Name | Comments | -| ---------- | ------------------------- | ------------------------------------------- | -| $sl_{P_x}$ | Public key's x-coordinate | | -| $sl_{P_y}$ | Public key's y-coordinate | | -| $sl_{v}$ | Voice credit balance | | -| $sl_{t}$ | Block timestamp | In Unix time (seconds since Jan 1 1970 UTC) | - -The hash $sl$ is computed as such: - -$sl = poseidon_4([sl_{A_x}, sl_{A_y}, sl_{v}, sl_{t}])$ - -#### Blank state leaf - -A blank state leaf $sl_B$ has the following value: - -$6769006970205099520508948723718471724660867171122235270773600567925038008762$ - -This value is computed as such: - -$A_{b_x} = 10457101036533406547632367118273992217979173478358440826365724437999023779287$ -$A_{b_y} = 19824078218392094440610104313265183977899662750282163392862422243483260492317$ -$sl_B = poseidon_4([A_{b0}, A_{b1}, 0, 0])$ - -The code to derive $A_{b_x}$ and $A_{b_y}$ is [here](https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js). The function call required is `pedersenHash.getBasePoint('blake', 0)` - -1. Hash the string `PedersenGenerator_00000000000000000000000000000000_00000000000000000000000000000000` with $blake_{256}$. In big-endian hexadecimal format, the hash should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697160`. -2. Set the 255th bit to 0. The result should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697120`. -3. Use the method to convert a buffer to a point on the BabyJub curve described in [2.3.2]. -4. Multiply the point by 8. The result is the point with x-value $A_{b_x}$ and y-value $A_{b_y}$ - -Given the [elliptic curve discrete logarithm problem](https://wstein.org/edu/2007/spring/ent/ent-html/node89.html), we assume that no one knows the private key $s \in {F}_p$ and by using the public key generation procedure in [1.4], we can derive $A_{b_x}$ and $A_{b_y}$. Furthermore, the string above (`PedersenGenerator...`) acts as a nothing-up-my-sleeve value. diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/spec.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/spec.md index 12f0a9883c..7397696aeb 100644 --- a/website/versioned_docs/version-v2.0_alpha/core-concepts/spec.md +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/spec.md @@ -2,7 +2,7 @@ title: MACI v1.0 Specification description: A detailed specification meant to assist auditors in reviewing MACI version 1.0 sidebar_label: Specification -sidebar_position: 5 +sidebar_position: 10 --- # MACI v1.0 Specification diff --git a/website/versioned_docs/version-v2.0_alpha/core-concepts/state-leaf.md b/website/versioned_docs/version-v2.0_alpha/core-concepts/state-leaf.md new file mode 100644 index 0000000000..b3cf2c6aa2 --- /dev/null +++ b/website/versioned_docs/version-v2.0_alpha/core-concepts/state-leaf.md @@ -0,0 +1,42 @@ +--- +title: MACI StateLeaf +description: A short introduction of the main primitives used by MACI +sidebar_label: MACI StateLeaf +sidebar_position: 6 +--- + +A state leaf represents a user's participation declared through an identity (their public key) and information relevant to their ability or right to cast votes in a poll (their voice credit balance and the block timestamp at which they signed up). + +We define a state leaf $sl$ as the $poseidon_4$ hash of the following: + +| Symbol | Name | Comments | +| ---------- | ------------------------- | ------------------------------------------- | +| $sl_{P_x}$ | Public key's x-coordinate | | +| $sl_{P_y}$ | Public key's y-coordinate | | +| $sl_{v}$ | Voice credit balance | | +| $sl_{t}$ | Block timestamp | In Unix time (seconds since Jan 1 1970 UTC) | + +The hash $sl$ is computed as such: + +$sl = poseidon_4([sl_{A_x}, sl_{A_y}, sl_{v}, sl_{t}])$ + +## Blank state leaf + +A blank state leaf $sl_B$ has the following value: + +$6769006970205099520508948723718471724660867171122235270773600567925038008762$ + +This value is computed as such: + +$A_{b_x} = 10457101036533406547632367118273992217979173478358440826365724437999023779287$ +$A_{b_y} = 19824078218392094440610104313265183977899662750282163392862422243483260492317$ +$sl_B = poseidon_4([A_{b0}, A_{b1}, 0, 0])$ + +The code to derive $A_{b_x}$ and $A_{b_y}$ is [here](https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js). The function call required is `pedersenHash.getBasePoint('blake', 0)` + +1. Hash the string `PedersenGenerator_00000000000000000000000000000000_00000000000000000000000000000000` with $blake_{256}$. In big-endian hexadecimal format, the hash should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697160`. +2. Set the 255th bit to 0. The result should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697120`. +3. Use the method to convert a buffer to a point on the BabyJub curve described in [2.3.2]. +4. Multiply the point by 8. The result is the point with x-value $A_{b_x}$ and y-value $A_{b_y}$ + +Given the [elliptic curve discrete logarithm problem](https://wstein.org/edu/2007/spring/ent/ent-html/node89.html), we assume that no one knows the private key $s \in {F}_p$ and by using the public key generation procedure in [1.4], we can derive $A_{b_x}$ and $A_{b_y}$. Furthermore, the string above (`PedersenGenerator...`) acts as a nothing-up-my-sleeve value. diff --git a/website/versioned_docs/version-v2.0_alpha/developers-references/zk-snark-circuits/circuits.md b/website/versioned_docs/version-v2.0_alpha/developers-references/zk-snark-circuits/circuits.md index 81bdefefb9..6f1acfaf48 100644 --- a/website/versioned_docs/version-v2.0_alpha/developers-references/zk-snark-circuits/circuits.md +++ b/website/versioned_docs/version-v2.0_alpha/developers-references/zk-snark-circuits/circuits.md @@ -240,7 +240,7 @@ The hash is computed using the `sha256` Solidity function and is then subject to | 4th 50 bits | `numSignUps` | | 5th 50 bits | `batchStartIndex` | -`numSignUps`, a value provided by the contract, is the number of users who have signed up. This is one less than the number of leaves inserted in the state tree (since the 0th state leaf is a [blank state leaf](/docs/core-concepts/primitives#state-leaf)). `batchStartIndex` is the ballot tree index at which the batch begins. +`numSignUps`, a value provided by the contract, is the number of users who have signed up. This is one less than the number of leaves inserted in the state tree (since the 0th state leaf is a [blank state leaf](/docs/core-concepts/state-leaf)). `batchStartIndex` is the ballot tree index at which the batch begins. For instance, if `numSignUps` is 25 and the batch index is `5`, and all other values are 0, the following is the `packedVals` representation in hexadecimal: