-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: split primitives into own files and update to latest changes
- Loading branch information
Showing
13 changed files
with
254 additions
and
227 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
website/versioned_docs/version-v2.0_alpha/core-concepts/ballot.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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])$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
website/versioned_docs/version-v2.0_alpha/core-concepts/hashing-and-encryption.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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$. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
website/versioned_docs/version-v2.0_alpha/core-concepts/maci-keys.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<bigint> { | ||
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**. |
44 changes: 44 additions & 0 deletions
44
website/versioned_docs/version-v2.0_alpha/core-concepts/maci-messages.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
23 changes: 23 additions & 0 deletions
23
website/versioned_docs/version-v2.0_alpha/core-concepts/merkle-trees.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.